public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* FW: [PATCH] [MIPS] microMIPS gcc support
       [not found] <FD3DCEAC5B03E9408544A1E416F1124211F9CC2E@NA-MBX-04.mgc.mentorg.com>
@ 2012-07-19 18:51 ` Moore, Catherine
  2012-07-20  0:46   ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2012-07-19 18:51 UTC (permalink / raw)
  To: gcc-patches; +Cc: Moore, Catherine

[-- Attachment #1: Type: text/plain, Size: 462 bytes --]

Forgot to copy the list ...

-----Original Message-----
From: Moore, Catherine 
Sent: Thursday, July 19, 2012 2:27 PM
To: rdsandiford@googlemail.com
Cc: Moore, Catherine; Rozycki, Maciej
Subject: [PATCH] [MIPS] microMIPS gcc support

Hi Richard,

Here is the updated microMIPS patch.  It's been a very long time (two years!) since I posted the original.  Please let me know what we're going to need to do to get this committed.

Thanks,
Catherine

[-- Attachment #2: umips.cl --]
[-- Type: application/octet-stream, Size: 5578 bytes --]

2012-07-19  Catherine Moore  <clm@codesourcery.com>
	    Chao-ying Fu <fu@mips.com>
	    Maciej W. Rozycki  <macro@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>
	    Tom de Vries  <tom@codesourcery.com>
	    Nathan Sidwell <nathan@codesourcery.com>
	    Iain Sandoe  <iain@codesourcery.com>

	* doc/extend.texi (micromips,nomicromips): Document attributes.
	(nocompression): Likewise.
	* doc/invoke.texi (mmicromips, mno-micromips): Document options.
	(mjals, mno-jals): Likewise.
	(m14k, m14ke, m14kec): New processor names.
	(minterlink-mips16): Update for microMIPS.
	* doc/md.texi (YC, YD, YE): Document new constraints.
	* config/mips/mips-tables.opt (m14k, m14kc): New archs.
	*config/mips/gnu-user.h (SUBTARGET_OVERRIDE_OPTIONS): Define.
	* config/mips/micromips.md: New file.
	* config/mips/constraints.md (YC, YD, YE): New constraints.
	* config/mips/predicates.md (gpr_operand, umips_register,
	stack_pointer_register, umips_andi16_operand, umips_shift16_operand,
	umips_add_uimm5, umips_addiur1sp_imm6, umips_addiusp_imm9,
	umips_addiur2_imm3, umips_li16_imm7, umips_lw16_memref
	umips_lwsp_memref, umips_lhu16_memref, umips_lbu16_memref
	const_0_si_operand, const_0_sf_operand, movep_si_operand
	movep_sf_operand, umips_lwp_register, non_volatile_mem_operand):
	New predicates.
	* config/mips/mips.md (multimem): New type attribute.
 	(umips_not, umips_arith, umips_mfhi, umips_logicals,
	umips_shift16, umips_add_uimm5_regs, umips_addius5,
	umips_addiusp, umips_addiur1sp, umips_addiur2, umips_adds,
	umips_and_immediate, umips_zero_extend, umips_mflo,
	umips_li16, umips_lw16, umips_sw16, umips_lwsp, umips_swsp,
	umips_lhu16, umips_shu16, umips_lbu16, umips_sbu16, umips_loads,
        umips_stores, umips_move, umips_short_insn): New attributes.
	(MOVEP1, MOVEP2): New mode iterators
	(mov_<load>l, mov_<load>r): Update constraint.
	(mov_<store>l, move_<store>r): Likewise.
	(prefetch): Likewise.
	(*branch_equality<mode>_micromips: New pattern.
	(*branch_equality<mode>_inverted_micromips): Likewise.
	(*branch_equality<mode>): Disable for microMIPS.
	(*branch_equality<mode>_inverted): Likewise.
	(*jump_absolute): microMIPS support.
	(indirect_jump_<mode>): Likewise.
	(tablejump_<mode>): Likewise.
	(<optab>_internal): Likewise.
	(sibcall_internal): Likewise.
	(sibcall_value_internal): Likewise.
	(sibcall_value_multiple_internal): Likewise.
	(micromips.md): Include.
	* config/mips/mips.opt (mjals): New option.
	(mmicromips): New option.
	* config/mips/sync.md (sync_compare_and_swap<mode>,
	compare_and_swap_12, sync_add<mode>, sync_<optab>_12,
	sync_old_<optab>_12, sync_new_<optab>_12, sync_nand_12,
	sync_old_nand_12, sync_new_nand_12, sync_sub<mode>,
	sync_old_add<mode>, sync_old_sub<mode>, sync_new_add<mode>,
	sync_new_sub<mode>, sync_<optab><mode>, sync_old_<optab><mode>,
	sync_new_<optab><mode>, sync_nand<mode>, sync_old_nand<mode>,
	sync_new_nand<mode>, sync_lock_test_and_set<mode>, test_and_set_12,
	atomic_exchange<mode>_llsc, atomic_fetch_add<mode>_llsc): Update
	constraints.
	* config/mips/mips-cpus.def (m14kc, m14k): New processors.
	* config/mips/mips-protos.h (umips_address_insns): New prototype.
	(umips_three_reg): Likewise.
	(umips_two_reg): Likewise.
	(umips_two_reg_match): Likewise.
	(umips_three_reg_match0): Likewise.
	(umips_output_save_restore): Likewise.
	(umips_save_restore_pattern_p): Likewise.
	(umips_load_store_pair_p): Likewise.
	(umips_output_load_store_pair): Likewise.
	(umips_movep_target_p): Likewise.
 	(MIPS_MAX_FIRST_STACK_STEP): Add microMIPS support.
	(mips_base_micromips): Declare.
	(mips_attribute_table): Add entries for micromips,
	nomicromips and nocompression.
	(mips_nocompression_decl_p): New function.
	(mips_micromips_decl_p): New function.
	(mips_nomicromips_decl_p): New function.
	(mips_use_micromips_mode_p): New function.
	(mips_insert_attributes): Handle micromips, nomicromips and
	nocompression function attributes.
	(umips_address_insns): New function.
	(umips_three_reg): New function.
	(umips_two_reg): New function.
	(umips_two_reg_match0): New function.
	(umips_three_reg_match0): New function.
	(mips_start_function_definition): Emit microMIPS directives.
	(mips_function_ok_for_sibcall): Support for microMIPS.
	(mips_print_operand_punctuation): Emit compact versions of
	instructions for microMIPS.
	(mips_init_print_operand_punct): Use ':' and '!' for microMIPS.
	(umips_build_save_restore): New function.
	(mips_for_each_saved_gpr_and_fpr): Add support for microMIPS.
	(mips_deallocate_stack): Likewise.
	(mips_expand_epilogue): Likewise.
	(was_micromips_p): Declare.
	(mips_set_mips16_mode): Rename to...
	(mips_set_mips16_micromips_mode): ...this and add support for
	microMIPS.  Update callers.
	(mips_set_current_function): Add microMIPS support.
	(mips_option_override): Add support for microMIPS.
	(umips_save_restore_pattern_p): New function.
	(umips_output_save_restore): New function.
	(umips_load_store_pair_p): New function.
	(umips_output_load_store_pair): New function.
	(umips_movep_target_p): New function.
	* config/mips/mips.h (TARGET_CPU_CPP_BUILTINS): Add a 
	builtin_define for microMIPS.
	(mips_cpu_info): Add m14k variants.
	(ISA_HAS_LWXS): Enable for microMIPS.
	(M16STORE_REG_P): Define.
	(UMIPS_ANDI16_IMM): Define.
 	(MIPS_CALL): Add support for microMIPS.
	(MICROMIPS_J): Define.
	(mips_base_micromips): Declare.
	* config/mips/t-sde (MULTILIB_OPTIONS): Add micromips variant.
	(MULTILIB_DIRNAMES): Likewise.

[-- Attachment #3: umips.patch --]
[-- Type: application/octet-stream, Size: 104389 bytes --]

Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 189440)
+++ gcc/doc/extend.texi	(working copy)
@@ -3025,6 +3025,25 @@ not that within individual functions.  Mixed MIPS1
 may interact badly with some GCC extensions such as @code{__builtin_apply}
 (@pxref{Constructing Calls}).
 
+@item micromips/nomicromips
+@cindex @code{micromips} attribute
+@cindex @code{nomicromips} attribute
+
+On MIPS targets, you can use the @code{micromips} and @code{nomicromips}
+function attributes to locally select or turn off microMIPS code generation.
+A function with the @code{micromips} attribute is emitted as microMIPS code,
+while microMIPS code generation is disabled for functions with the
+@code{nomicromips} attribute.  These attributes override the
+@option{-mmicromips} and @option{-mno-micromips} options on the command line
+(@pxref{MIPS Options}).
+
+When compiling files containing mixed microMIPS and non-microMIPS code, the
+preprocessor symbol @code{__mips_micromips} reflects the setting on the
+command line,
+not that within individual functions.  Mixed microMIPS and non-microMIPS code
+may interact badly with some GCC extensions such as @code{__builtin_apply}
+(@pxref{Constructing Calls}).
+
 @item model (@var{model-name})
 @cindex function addressability on the M32R/D
 @cindex variable addressability on the IA-64
@@ -3126,6 +3145,13 @@ is an NMI handler.  The compiler will generate fun
 exit sequences suitable for use in an NMI handler when this
 attribute is present.
 
+@item nocompression
+@cindex @code{nocompression} attribute
+On MIPS targets, you can use the @code{nocompression} function attribute
+to locally turn off MIPS16 and microMIPS code generation.  This attribute
+overrides the @option{-mips16} and @option{-mmicromips} options on the
+command line (@pxref{MIPS Options}).
+
 @item no_instrument_function
 @cindex @code{no_instrument_function} function attribute
 @opindex finstrument-functions
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 189440)
+++ gcc/doc/invoke.texi	(working copy)
@@ -732,6 +732,7 @@ Objective-C and Objective-C++ Dialects}.
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
 -mgp32  -mgp64  -mfp32  -mfp64  -mhard-float  -msoft-float @gol
 -msingle-float  -mdouble-float  -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
+-mmicromips -mno-micromips @gol
 -mfpu=@var{fpu-type} @gol
 -msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
@@ -747,6 +748,7 @@ Objective-C and Objective-C++ Dialects}.
 -mcheck-zero-division  -mno-check-zero-division @gol
 -mdivide-traps  -mdivide-breaks @gol
 -mmemcpy  -mno-memcpy  -mlong-calls  -mno-long-calls @gol
+-mjals -mno-jals @gol
 -mmad  -mno-mad  -mfused-madd  -mno-fused-madd  -nocpp @gol
 -mfix-24k -mno-fix-24k @gol
 -mfix-r4000  -mno-fix-r4000  -mfix-r4400  -mno-fix-r4400 @gol
@@ -15354,6 +15356,7 @@ The processor names are:
 @samp{1004kc}, @samp{1004kf2_1}, @samp{1004kf1_1},
 @samp{loongson2e}, @samp{loongson2f}, @samp{loongson3a},
 @samp{m4k},
+@samp{m14k}, @samp{m14ke}, @samp{m14kec},
 @samp{octeon}, @samp{octeon+}, @samp{octeon2},
 @samp{orion},
 @samp{r2000}, @samp{r3000}, @samp{r3900}, @samp{r4000}, @samp{r4400},
@@ -15471,13 +15474,14 @@ not intended for ordinary use in compiling user co
 @itemx -mno-interlink-mips16
 @opindex minterlink-mips16
 @opindex mno-interlink-mips16
-Require (do not require) that non-MIPS16 code be link-compatible with
-MIPS16 code.
+Require (do not require) that non-MIPS16/non-microMIPS code be link-compatible
+with MIPS16/microMIPS code.
 
-For example, non-MIPS16 code cannot jump directly to MIPS16 code;
+For example, non-MIPS16/non-microMIPS code cannot jump directly to
+MIPS16/microMIPS code;
 it must either use a call or an indirect jump.  @option{-minterlink-mips16}
 therefore disables direct jumps unless GCC knows that the target of the
-jump is not MIPS16.
+jump is not MIPS16/non microMIPS.
 
 @item -mabi=32
 @itemx -mabi=o64
@@ -15680,6 +15684,17 @@ hardware floating-point support to be enabled.
 Use (do not use) the MIPS-3D ASE@.  @xref{MIPS-3D Built-in Functions}.
 The option @option{-mips3d} implies @option{-mpaired-single}.
 
+@item -mmicromips
+@itemx -mno-micromips
+@opindex mmicromips
+@opindex mno-mmicromips
+Generate (do not generate) microMIPS code.  If GCC is targetting a
+MIPS32 or MIPS64 architecture, it will make use of the microMIPS ASE@.
+
+MicroMIPS code generation can also be controlled on a per-function basis
+by means of @code{micromips} and @code{nomicromips} attributes.
+@xref{Function Attributes}, for more information.
+
 @item -mmt
 @itemx -mno-mt
 @opindex mmt
@@ -15881,6 +15896,16 @@ and callee to be in the same 256 megabyte segment.
 This option has no effect on abicalls code.  The default is
 @option{-mno-long-calls}.
 
+@item -mjals
+@itemx -mno-jals
+@opindex mjals
+@opindex mno-jals
+Generate (do not generate) the @code{jals} instruction for microMIPS
+by recognizing that the branch delay slot instruction can be 16 bits.
+This implies that the funciton call cannot switch the current mode
+during the linking stage, because we don't have the @code{jalxs}
+instruction that supports 16-bit branch delay slot instructions.
+
 @item -mmad
 @itemx -mno-mad
 @opindex mmad
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(revision 189440)
+++ gcc/doc/md.texi	(working copy)
@@ -2841,6 +2841,19 @@ Floating-point zero.
 
 @item R
 An address that can be used in a non-macro load or store.
+
+@item YC
+For MIPS, it is the same as the constraint @code{R}.  For microMIPS,
+it matches an address within a 12-bit offset that can be used for
+microMIPS @code{ll}, @code{sc}, etc.
+
+@item YD
+For MIPS, it is the same as the constraint @code{p}  For microMIPS,
+it matches a 12-bit offsest address.
+
+@item YE
+A singler register memory operand.
+
 @end table
 
 @item Motorola 680x0---@file{config/m68k/constraints.md}
Index: gcc/config/mips/mips-tables.opt
===================================================================
--- gcc/config/mips/mips-tables.opt	(revision 189440)
+++ gcc/config/mips/mips-tables.opt	(working copy)
@@ -373,248 +373,254 @@ EnumValue
 Enum(mips_arch_opt_value) String(m4k) Value(39) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kec) Value(40) Canonical
+Enum(mips_arch_opt_value) String(m14kc) Value(40) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kec) Value(40)
+Enum(mips_arch_opt_value) String(m14k) Value(41) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kem) Value(41) Canonical
+Enum(mips_arch_opt_value) String(4kec) Value(42) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kem) Value(41)
+Enum(mips_arch_opt_value) String(r4kec) Value(42)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kep) Value(42) Canonical
+Enum(mips_arch_opt_value) String(4kem) Value(43) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kep) Value(42)
+Enum(mips_arch_opt_value) String(r4kem) Value(43)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4ksd) Value(43) Canonical
+Enum(mips_arch_opt_value) String(4kep) Value(44) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4ksd) Value(43)
+Enum(mips_arch_opt_value) String(r4kep) Value(44)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kc) Value(44) Canonical
+Enum(mips_arch_opt_value) String(4ksd) Value(45) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kc) Value(44)
+Enum(mips_arch_opt_value) String(r4ksd) Value(45)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf2_1) Value(45) Canonical
+Enum(mips_arch_opt_value) String(24kc) Value(46) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf2_1) Value(45)
+Enum(mips_arch_opt_value) String(r24kc) Value(46)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf) Value(46) Canonical
+Enum(mips_arch_opt_value) String(24kf2_1) Value(47) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf) Value(46)
+Enum(mips_arch_opt_value) String(r24kf2_1) Value(47)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf1_1) Value(47) Canonical
+Enum(mips_arch_opt_value) String(24kf) Value(48) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf1_1) Value(47)
+Enum(mips_arch_opt_value) String(r24kf) Value(48)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kfx) Value(48) Canonical
+Enum(mips_arch_opt_value) String(24kf1_1) Value(49) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kfx) Value(48)
+Enum(mips_arch_opt_value) String(r24kf1_1) Value(49)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kx) Value(49) Canonical
+Enum(mips_arch_opt_value) String(24kfx) Value(50) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kx) Value(49)
+Enum(mips_arch_opt_value) String(r24kfx) Value(50)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kec) Value(50) Canonical
+Enum(mips_arch_opt_value) String(24kx) Value(51) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kec) Value(50)
+Enum(mips_arch_opt_value) String(r24kx) Value(51)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef2_1) Value(51) Canonical
+Enum(mips_arch_opt_value) String(24kec) Value(52) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef2_1) Value(51)
+Enum(mips_arch_opt_value) String(r24kec) Value(52)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef) Value(52) Canonical
+Enum(mips_arch_opt_value) String(24kef2_1) Value(53) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef) Value(52)
+Enum(mips_arch_opt_value) String(r24kef2_1) Value(53)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef1_1) Value(53) Canonical
+Enum(mips_arch_opt_value) String(24kef) Value(54) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef1_1) Value(53)
+Enum(mips_arch_opt_value) String(r24kef) Value(54)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kefx) Value(54) Canonical
+Enum(mips_arch_opt_value) String(24kef1_1) Value(55) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kefx) Value(54)
+Enum(mips_arch_opt_value) String(r24kef1_1) Value(55)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kex) Value(55) Canonical
+Enum(mips_arch_opt_value) String(24kefx) Value(56) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kex) Value(55)
+Enum(mips_arch_opt_value) String(r24kefx) Value(56)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kc) Value(56) Canonical
+Enum(mips_arch_opt_value) String(24kex) Value(57) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kc) Value(56)
+Enum(mips_arch_opt_value) String(r24kex) Value(57)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf2_1) Value(57) Canonical
+Enum(mips_arch_opt_value) String(34kc) Value(58) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf2_1) Value(57)
+Enum(mips_arch_opt_value) String(r34kc) Value(58)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf) Value(58) Canonical
+Enum(mips_arch_opt_value) String(34kf2_1) Value(59) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf) Value(58)
+Enum(mips_arch_opt_value) String(r34kf2_1) Value(59)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf1_1) Value(59) Canonical
+Enum(mips_arch_opt_value) String(34kf) Value(60) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf1_1) Value(59)
+Enum(mips_arch_opt_value) String(r34kf) Value(60)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kfx) Value(60) Canonical
+Enum(mips_arch_opt_value) String(34kf1_1) Value(61) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kfx) Value(60)
+Enum(mips_arch_opt_value) String(r34kf1_1) Value(61)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kx) Value(61) Canonical
+Enum(mips_arch_opt_value) String(34kfx) Value(62) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kx) Value(61)
+Enum(mips_arch_opt_value) String(r34kfx) Value(62)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kc) Value(62) Canonical
+Enum(mips_arch_opt_value) String(34kx) Value(63) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kc) Value(62)
+Enum(mips_arch_opt_value) String(r34kx) Value(63)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf2_1) Value(63) Canonical
+Enum(mips_arch_opt_value) String(74kc) Value(64) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf2_1) Value(63)
+Enum(mips_arch_opt_value) String(r74kc) Value(64)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf) Value(64) Canonical
+Enum(mips_arch_opt_value) String(74kf2_1) Value(65) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf) Value(64)
+Enum(mips_arch_opt_value) String(r74kf2_1) Value(65)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf1_1) Value(65) Canonical
+Enum(mips_arch_opt_value) String(74kf) Value(66) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf1_1) Value(65)
+Enum(mips_arch_opt_value) String(r74kf) Value(66)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kfx) Value(66) Canonical
+Enum(mips_arch_opt_value) String(74kf1_1) Value(67) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kfx) Value(66)
+Enum(mips_arch_opt_value) String(r74kf1_1) Value(67)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kx) Value(67) Canonical
+Enum(mips_arch_opt_value) String(74kfx) Value(68) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kx) Value(67)
+Enum(mips_arch_opt_value) String(r74kfx) Value(68)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf3_2) Value(68) Canonical
+Enum(mips_arch_opt_value) String(74kx) Value(69) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf3_2) Value(68)
+Enum(mips_arch_opt_value) String(r74kx) Value(69)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kc) Value(69) Canonical
+Enum(mips_arch_opt_value) String(74kf3_2) Value(70) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kc) Value(69)
+Enum(mips_arch_opt_value) String(r74kf3_2) Value(70)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf2_1) Value(70) Canonical
+Enum(mips_arch_opt_value) String(1004kc) Value(71) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf2_1) Value(70)
+Enum(mips_arch_opt_value) String(r1004kc) Value(71)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf) Value(71) Canonical
+Enum(mips_arch_opt_value) String(1004kf2_1) Value(72) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf) Value(71)
+Enum(mips_arch_opt_value) String(r1004kf2_1) Value(72)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf1_1) Value(72) Canonical
+Enum(mips_arch_opt_value) String(1004kf) Value(73) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf1_1) Value(72)
+Enum(mips_arch_opt_value) String(r1004kf) Value(73)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kc) Value(73) Canonical
+Enum(mips_arch_opt_value) String(1004kf1_1) Value(74) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kc) Value(73)
+Enum(mips_arch_opt_value) String(r1004kf1_1) Value(74)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kf) Value(74) Canonical
+Enum(mips_arch_opt_value) String(5kc) Value(75) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kf) Value(74)
+Enum(mips_arch_opt_value) String(r5kc) Value(75)
 
 EnumValue
-Enum(mips_arch_opt_value) String(20kc) Value(75) Canonical
+Enum(mips_arch_opt_value) String(5kf) Value(76) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r20kc) Value(75)
+Enum(mips_arch_opt_value) String(r5kf) Value(76)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1) Value(76) Canonical
+Enum(mips_arch_opt_value) String(20kc) Value(77) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1a) Value(77) Canonical
+Enum(mips_arch_opt_value) String(r20kc) Value(77)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71000) Value(78) Canonical
+Enum(mips_arch_opt_value) String(sb1) Value(78) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71k) Value(78)
+Enum(mips_arch_opt_value) String(sb1a) Value(79) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlr) Value(79) Canonical
+Enum(mips_arch_opt_value) String(sr71000) Value(80) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(loongson3a) Value(80) Canonical
+Enum(mips_arch_opt_value) String(sr71k) Value(80)
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon) Value(81) Canonical
+Enum(mips_arch_opt_value) String(xlr) Value(81) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon+) Value(82) Canonical
+Enum(mips_arch_opt_value) String(loongson3a) Value(82) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon2) Value(83) Canonical
+Enum(mips_arch_opt_value) String(octeon) Value(83) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlp) Value(84) Canonical
+Enum(mips_arch_opt_value) String(octeon+) Value(84) Canonical
 
+EnumValue
+Enum(mips_arch_opt_value) String(octeon2) Value(85) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(xlp) Value(86) Canonical
+
Index: gcc/config/mips/gnu-user.h
===================================================================
--- gcc/config/mips/gnu-user.h	(revision 189440)
+++ gcc/config/mips/gnu-user.h	(working copy)
@@ -138,3 +138,11 @@ extern const char *host_detect_local_cpu (int argc
 #define ENDFILE_SPEC \
   GNU_USER_TARGET_MATHFILE_SPEC " " \
   GNU_USER_TARGET_ENDFILE_SPEC
+
+#undef SUBTARGET_OVERRIDE_OPTIONS
+#define SUBTARGET_OVERRIDE_OPTIONS                              \
+do {                                                            \
+  /* microMIPS PLT entries are non-microMIPS.  */               \
+  TARGET_INTERLINK_MIPS16 = 1;                                  \
+} while (0)
+
Index: gcc/config/mips/micromips.md
===================================================================
--- gcc/config/mips/micromips.md	(revision 0)
+++ gcc/config/mips/micromips.md	(revision 0)
@@ -0,0 +1,180 @@
+(define_insn "*store_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "memory_operand")
+	     (match_operand:SI 2 "register_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (true, operands[0])"
+  {
+    return umips_output_save_restore (true, operands[0]);
+  }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+(define_insn "*load_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "register_operand")
+	     (match_operand:SI 2 "memory_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (false, operands[0])"
+  {
+    return umips_output_save_restore (false, operands[0]);
+  }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For lwp
+(define_peephole2
+  [(set (match_operand:SI 0 "umips_lwp_register" "")
+        (match_operand:SI 1 "non_volatile_mem_operand" ""))
+   (set (match_operand:SI 2 "umips_lwp_register" "")
+        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+  "TARGET_MICROMIPS
+   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
+	&& umips_load_store_pair_p (true, false, operands[0],
+				    operands[1], operands[3]))
+       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
+	   && umips_load_store_pair_p (true, true, operands[2],
+				       operands[3], operands[1])))"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*lwp"
+  [(parallel [(set (match_operand:SI 0 "umips_lwp_register")
+		   (match_operand:SI 1 "memory_operand"))
+	      (set (match_operand:SI 2 "umips_lwp_register")
+		   (match_operand:SI 3 "memory_operand"))])]
+
+  "TARGET_MICROMIPS
+   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
+	&& umips_load_store_pair_p (true, false, operands[0],
+				    operands[1], operands[3]))
+       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
+	   && umips_load_store_pair_p (true, true, operands[2],
+				       operands[3], operands[1])))"
+  {
+    if (REGNO (operands[0]) + 1 == REGNO (operands[2]))
+      return umips_output_load_store_pair (true, operands[0], operands[1]);
+    else
+      return umips_output_load_store_pair (true, operands[2], operands[3]);
+  }
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For swp
+(define_peephole2
+  [(set (match_operand:SI 0 "non_volatile_mem_operand" "")
+        (match_operand:SI 1 "umips_lwp_register" ""))
+   (set (match_operand:SI 2 "non_volatile_mem_operand" "")
+        (match_operand:SI 3 "umips_lwp_register" ""))]
+  "TARGET_MICROMIPS
+   && ((REGNO (operands[1]) + 1 == REGNO (operands[3])
+	&& umips_load_store_pair_p (false, false, operands[1],
+                                    operands[0], operands[2]))
+       || (REGNO (operands[3]) + 1 == REGNO (operands[1])
+	   && umips_load_store_pair_p (false, true, operands[3],
+                                       operands[2], operands[0])))"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*swp"
+  [(parallel [(set (match_operand:SI 0 "memory_operand")
+		   (match_operand:SI 1 "umips_lwp_register"))
+	      (set (match_operand:SI 2 "memory_operand")
+		   (match_operand:SI 3 "umips_lwp_register"))])]
+
+  "TARGET_MICROMIPS
+   && ((REGNO (operands[1]) + 1 == REGNO (operands[3])
+	&& umips_load_store_pair_p (false, false, operands[1],
+                                    operands[0], operands[2]))
+       || (REGNO (operands[3]) + 1 == REGNO (operands[1])
+	   && umips_load_store_pair_p (false, true, operands[3],
+                                       operands[2], operands[0])))"
+  {
+    if (REGNO (operands[1]) + 1 == REGNO (operands[3]))
+      return umips_output_load_store_pair (false, operands[1], operands[0]);
+    else
+      return umips_output_load_store_pair (false, operands[3], operands[2]);
+  }
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For jraddiusp
+(define_insn "mips_jraddiusp"
+  [(parallel [(return)
+              (use (reg:SI 31))
+	      (set (reg:SI 29)
+		   (plus:SI (reg:SI 29)
+			    (match_operand 0 "const_int_operand")))])]
+  "TARGET_MICROMIPS"
+  "jraddiusp\t%0"
+  [(set_attr "type" "trap")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For movep
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+        (match_operand:SI 1 "movep_si_operand" ""))
+   (set (match_operand:SI 2 "register_operand" "")
+        (match_operand:SI 3 "movep_si_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+        (match_operand:SI 1 "movep_si_operand" ""))
+   (set (match_operand:SF 2 "register_operand" "")
+        (match_operand:SF 3 "const_0_sf_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SF 0 "register_operand" "")
+        (match_operand:SF 1 "const_0_sf_operand" ""))
+   (set (match_operand:SI 2 "register_operand" "")
+        (match_operand:SI 3 "movep_si_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SF 0 "register_operand" "")
+        (match_operand:SF 1 "const_0_sf_operand" ""))
+   (set (match_operand:SF 2 "register_operand" "")
+        (match_operand:SF 3 "const_0_sf_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+		   (match_operand:MOVEP1 1 "movep_<MOVEP1:mode>_operand"))
+	      (set (match_operand:MOVEP2 2 "register_operand")
+		   (match_operand:MOVEP2 3 "movep_<MOVEP2:mode>_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+{
+  if (REGNO (operands[0]) < REGNO (operands[2]))
+    return "movep\t%0,%2,%z1,%z3";
+  else
+    return "movep\t%2,%0,%z3,%z1";
+}
+  [(set_attr "type" "move")
+   (set_attr "mode" "<MODE>")
+   (set_attr "can_delay" "no")])
Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	(revision 189440)
+++ gcc/config/mips/constraints.md	(working copy)
@@ -162,7 +162,7 @@
 (define_memory_constraint "R"
   "An address that can be used in a non-macro load or store."
   (and (match_code "mem")
-       (match_test "mips_address_insns (XEXP (op, 0), mode, false) == 1")))
+       (match_test "mips_address_insns (XEXP (op, 0), mode, false)")))
 
 (define_constraint "S"
   "@internal
@@ -216,6 +216,22 @@
   (and (match_code "const_int")
        (match_test "IMM10_OPERAND (ival)")))
 
+(define_memory_constraint "YC"
+  "For MIPS, it is the same as the constraint R.  For microMIPS, it matches
+   an address within a 12-bit offset that can be used in ll, sc, etc."
+  (and (match_code "mem")
+       (ior (and (match_test "TARGET_MICROMIPS")
+		 (match_test "umips_address_insns (XEXP (op, 0), mode, false)"))
+	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "YD"
+  "@internal
+   For MIPS, it is the same as the constraint p.  For microMIPS, it matches
+   a 12-bit offset address."
+   (ior (and (match_test "TARGET_MICROMIPS")
+	     (match_test "umips_address_insns (op, mode, false)"))
+	(match_test "mips_address_insns (op, mode, false)")))
+
 (define_constraint "Yb"
    "@internal"
    (match_operand 0 "qi_mask_operand"))
@@ -232,6 +248,11 @@
    "@internal"
    (match_operand 0 "low_bitmask_operand"))
 
+(define_memory_constraint "YE"
+  "A single reg memory operand."
+  (and (match_code "mem")
+       (match_test "REG_P (XEXP (op, 0))")))
+
 (define_memory_constraint "ZR"
  "@internal
   An address valid for loading/storing register exclusive"
Index: gcc/config/mips/predicates.md
===================================================================
--- gcc/config/mips/predicates.md	(revision 189440)
+++ gcc/config/mips/predicates.md	(working copy)
@@ -122,6 +122,126 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "gpr_operand"
+  (and (match_code "reg")
+       (match_test "GP_REG_P (REGNO (op))")))
+
+(define_predicate "umips_register"
+  (and (match_code "reg")
+       (match_test "M16_REG_P (REGNO (op))")))
+
+(define_predicate "stack_pointer_register"
+  (and (match_code "reg")
+       (match_test "REGNO (op) == STACK_POINTER_REGNUM")))
+
+(define_predicate "umips_andi16_operand"
+  (and (match_code "const")
+       (match_test "UMIPS_ANDI16_IMM (INTVAL (op))")))
+
+(define_predicate "umips_shift16_operand"
+  (and (match_code "const")
+       (match_test "IN_RANGE (INTVAL (op), 1, 8)")))
+
+(define_predicate "umips_add_uimm5"
+  (and (match_code "const")
+       (match_test "IN_RANGE (INTVAL (op), -8, 7)")))
+
+(define_predicate "umips_addiur1sp_imm6"
+  (and (match_code "const")
+       (match_test "(INTVAL (op) & 3) == 0")
+       (match_test "(IN_RANGE (INTVAL (op), -8, 7))")))
+
+(define_predicate "umips_addiusp_imm9"
+  (and (match_code "const")
+       (ior (match_test "IN_RANGE (INTVAL(op), 2, 257)")
+            (match_test "IN_RANGE (INTVAL (op), -258, -3)"))))
+
+(define_predicate "umips_addiur2_imm3"
+  (and (match_code "const")
+       (ior (match_test "INTVAL(op) == 1")
+       (ior (match_test "INTVAL(op) == 4")
+       (ior (match_test "INTVAL(op) == 8")
+       (ior (match_test "INTVAL(op) == 12")
+       (ior (match_test "INTVAL(op) == 16")
+       (ior (match_test "INTVAL(op) == 20")
+       (ior (match_test "INTVAL(op) == 24")
+	    (match_test "INTVAL(op) == -1"))))))))))
+
+(define_predicate "umips_li16_imm7"
+  (and (match_code "const")
+       (match_test "IN_RANGE (INTVAL (op), -1, 126)")))
+
+(define_predicate "umips_lw16_memref"
+  (and (match_code "plus")
+       (match_operand 0 "umips_register" ""))
+{
+  rtx op2 = XEXP (op, 1);
+
+  return (GET_CODE (op2) == CONST_INT
+          && ((INTVAL (op2) & 3) == 0)
+	  && (IN_RANGE (INTVAL (op2), 0, 60)));
+})
+
+(define_predicate "umips_lwsp_memref"
+  (and (match_code "plus")
+       (match_operand 0 "stack_pointer_register" ""))
+{
+  rtx op2 = XEXP (op, 1);
+
+  return (GET_CODE (op2) == CONST_INT
+          && ((INTVAL (op2) & 3) == 0)
+	  && (IN_RANGE (INTVAL (op2), 0, 124)));
+})
+
+(define_predicate "umips_lhu16_memref"
+  (and (match_code "plus")
+       (match_operand 0 "umips_register" ""))
+{
+  rtx op2 = XEXP (op, 1);
+
+  return (GET_MODE (op) == HImode
+          && GET_CODE (op2) == CONST_INT
+          && ((INTVAL (op2) & 1) == 0)
+	  && (IN_RANGE (INTVAL (op2), 0, 30)));
+})
+
+(define_predicate "umips_lbu16_memref"
+  (and (match_code "plus")
+       (match_operand 0 "umips_register" ""))
+{
+  rtx op2 = XEXP (op, 1);
+
+  return (GET_MODE (op) == QImode
+	  && GET_CODE (op2) == CONST_INT
+	  && (IN_RANGE (INTVAL (op2), -1, 14)));
+})
+
+(define_predicate "const_0_si_operand"
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "op == CONST0_RTX (SImode)")))
+
+(define_predicate "const_0_sf_operand"
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "op == CONST0_RTX (SFmode)")))
+
+(define_predicate "movep_si_operand"
+  (ior (and (match_code "const_int,const_double,const_vector")
+	    (match_test "op == CONST0_RTX (SImode)"))
+       (and (match_code "reg")
+	    (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
+		 (match_test ("IN_RANGE (REGNO (op), 16, 20)"))))))
+
+(define_predicate "movep_sf_operand"
+  (ior (and (match_code "const_int, const_double, const_vector")
+	    (match_test "op == CONST0_RTX (SFmode)"))
+       (and (match_code "reg")
+	    (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
+		 (match_test ("IN_RANGE (REGNO (op), 16, 20)"))))))
+
+(define_predicate "umips_lwp_register"
+  (and (match_code "reg")
+       (match_test "REGNO (op) <= GP_REG_LAST")))
+
 (define_predicate "lo_operand"
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
@@ -374,3 +494,17 @@
 (define_predicate "mem_noofs_operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
+
+;; Return 1 if the operand is in non-volatile memory.  Note that during the
+;; RTL generation phase, memory_operand does not return TRUE for volatile
+;; memory references.  So this function allows us to recognize volatile
+;; references where it's safe.
+(define_predicate "non_volatile_mem_operand"
+  (not (and (and (match_code "mem")
+          (match_test "MEM_VOLATILE_P (op)"))
+       (if_then_else (match_test "reload_completed")
+         (match_operand 0 "memory_operand")
+         (if_then_else (match_test "reload_in_progress")
+         (match_test "strict_memory_address_p (mode, XEXP (op, 0))")
+         (match_test "memory_address_p (mode, XEXP (op, 0))"))))))
+
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 189440)
+++ gcc/config/mips/mips.md	(working copy)
@@ -276,12 +276,13 @@
 ;; multi	multiword sequence (or user asm statements)
 ;; nop		no operation
 ;; ghost	an instruction that produces no real code
+;; multimem	microMIPS multiword load and store
 (define_attr "type"
   "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
    prefetch,prefetchx,condmove,mtc,mfc,mthilo,mfhilo,const,arith,logical,
    shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
    fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
-   frsqrt,frsqrt1,frsqrt2,multi,nop,ghost"
+   frsqrt,frsqrt1,frsqrt2,multi,nop,ghost,multimem"
   (cond [(eq_attr "jal" "!unset") (const_string "call")
 	 (eq_attr "got" "load") (const_string "load")
 
@@ -344,6 +345,223 @@
 		(const_string "yes")
 		(const_string "no")))
 
+(define_attr "umips_not" "no, yes"
+  (if_then_else (and (eq_attr "alu_type" "not")
+		     (match_test "umips_two_reg (PATTERN (insn))"))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_arith" "no, yes"
+  (if_then_else (and (eq_attr "type" "arith")
+		     (not (eq_attr "mode" "DI"))
+		     (match_test "umips_three_reg_match0 (PATTERN (insn))"))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_mfhi" "no, yes"
+  (if_then_else (and (eq_attr "move_type" "mfhilo")
+		     (match_operand 1 "gpr_operand" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_logicals" "no, yes"
+  (if_then_else (and (ior (eq_attr "alu_type" "and")
+			  (eq_attr "alu_type" "or")
+			  (eq_attr "alu_type" "xor"))
+		     (match_test "umips_three_reg_match0 (PATTERN (insn))"))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_shift16" "no, yes"
+  (if_then_else (and (eq_attr "type" "shift")
+		     (not (eq_attr "mode" "DI"))
+		     (match_test "umips_two_reg (PATTERN (insn))")
+		     (match_operand 2 "umips_shift16_operand" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_add_uimm5_regs" "no, yes"
+  (if_then_else (and (match_operand 0 "gpr_operand" "")
+		     (match_operand 1 "gpr_operand" "")
+		     (match_test "umips_two_reg_match0 (PATTERN(insn))"))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_addius5" "no, yes"
+  (if_then_else (and (eq_attr "umips_add_uimm5_regs" "yes")
+		     (match_operand 2 "umips_add_uimm5" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_addiusp" "no, yes"
+  (if_then_else (and (match_operand 0 "stack_pointer_register")
+		     (match_operand 1 "stack_pointer_register")
+		     (match_operand 2 "umips_addiur1sp_imm6" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_addiur1sp" "no, yes"
+  (if_then_else (and (match_operand 0 "umips_register" "")
+		     (match_operand 1 "stack_pointer_register")
+		     (match_operand 2 "umips_addiusp_imm9" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_addiur2" "no, yes"
+  (if_then_else (and (match_operand 0 "umips_register" "")
+		     (match_operand 1 "umips_register" "")
+		     (match_operand 2 "umips_addiur2_imm3" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_adds" "no, yes"
+  (if_then_else (and (eq_attr "alu_type" "add")
+		     (not (eq_attr "mode" "DI"))
+		     (ior (eq_attr "umips_addius5" "yes")
+			  (eq_attr "umips_addiusp" "yes")
+			  (eq_attr "umips_addiur2" "yes")
+			  (eq_attr "umips_addiur1sp" "yes")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_and_immediate" "no, yes"
+  (if_then_else (and (eq_attr "alu_type" "and")
+		     (match_test "umips_two_reg (PATTERN (insn))")
+		     (match_operand 2 "umips_andi16_operand" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_zero_extend" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI")
+		     (match_test "umips_two_reg (PATTERN (insn))"))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_mflo" "no, yes"
+  (if_then_else (and (eq_attr "move_type" "mfhilo")
+                     (match_operand 0 "gpr_operand" "")
+		     (match_operand 1 "lo_operand" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_li16" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI")
+		     (match_operand 0 "umips_register" "")
+		     (match_operand 1 "umips_li16_imm7" ""))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_lw16" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI,SF")
+		     (match_operand 0 "umips_register" "")
+		     (ior (match_operand 1 "umips_register" "")
+			  (match_operand 1 "umips_lw16_memref" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_sw16" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI,SF")
+		     (ior (match_operand 1 "umips_register" "")
+			  (match_operand 1 "const_0_operand"))
+		     (ior (match_operand 0 "umips_register" "")
+			  (match_operand 0 "umips_lw16_memref" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_lwsp" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI,SF")
+		     (match_operand 0 "gpr_operand" "")
+		     (ior (match_operand 1 "stack_pointer_register" "")
+			  (match_operand 1 "umips_lwsp_memref" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_swsp" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI,SF")
+		     (match_operand 1 "gpr_operand" "")
+		     (ior (match_operand 0 "stack_pointer_register" "")
+			  (match_operand 0 "umips_lwsp_memref" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_lhu16" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI")
+		     (match_operand 0 "umips_register" "")
+		     (ior (match_operand 1 "umips_register" "")
+			  (match_operand 1 "umips_lhu16_memref" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_shu16" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI")
+		     (match_operand 1 "umips_register" "")
+		     (ior (match_operand 0 "umips_register" "")
+			  (match_operand 0 "umips_lhu16_memref" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_lbu16" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI")
+		     (match_operand 0 "umips_register" "")
+		     (ior (match_operand 1 "umips_register" "")
+			  (match_operand 1 "umips_lbu16_memref" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_sbu16" "no, yes"
+  (if_then_else (and (eq_attr "mode" "SI")
+		     (match_operand 1 "umips_register" "")
+		     (ior (match_operand 0 "umips_register" "")
+			  (match_operand 0 "umips_lbu16_memref" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+(define_attr "umips_loads" "no, yes"
+  (if_then_else (and (eq_attr "move_type" "load")
+		     (ior (eq_attr "umips_li16" "yes")
+			  (eq_attr "umips_lw16" "yes")
+			  (eq_attr "umips_lwsp" "yes")
+			  (eq_attr "umips_lhu16" "yes")
+			  (eq_attr "umips_lbu16" "yes")))
+  (const_string "yes")      
+  (const_string "no")))
+
+(define_attr "umips_stores" "no, yes"
+  (if_then_else (and (eq_attr "move_type" "store")
+		     (ior (eq_attr "umips_li16" "yes")
+			  (eq_attr "umips_sw16" "yes")
+			  (eq_attr "umips_swsp" "yes")
+			  (eq_attr "umips_lhu16" "yes")
+			  (eq_attr "umips_lbu16" "yes")))
+  (const_string "yes")      
+  (const_string "no")))
+
+(define_attr "umips_move" "no, yes"
+  (if_then_else (and (eq_attr "move_type" "move")
+		     (match_operand 0 "gpr_operand" "")
+		     (ior (match_operand 1 "gpr_operand" "")
+			  (match_operand 0 "const_0_operand" "")))
+  (const_string "yes")
+  (const_string "no")))
+
+;; Is this a short instruction in microMIPS mode?
+(define_attr "umips_short_insn" "no, yes"
+  (if_then_else (and (match_test "TARGET_MICROMIPS")
+		     (ior (eq_attr "umips_not" "yes")
+			  (eq_attr "umips_arith" "yes")
+			  (eq_attr "umips_shift16" "yes")
+			  (eq_attr "umips_adds" "yes")
+			  (eq_attr "umips_logicals" "yes")
+			  (eq_attr "umips_loads" "yes")
+			  (eq_attr "umips_stores" "yes")
+			  (eq_attr "umips_move" "yes")
+			  (eq_attr "umips_and_immediate" "yes")
+			  (eq_attr "umips_zero_extend" "yes")
+			  (eq_attr "umips_mflo" "yes")
+			  (eq_attr "umips_mfhi" "yes")))
+  (const_string "yes")
+  (const_string "no")))
+
 ;; Attributes describing a sync loop.  These loops have the form:
 ;;
 ;;       if (RELEASE_BARRIER == YES) sync
@@ -400,9 +618,18 @@
 	       (match_test "TARGET_MIPS16"))
 	  (const_int 8)
 
+	  (and (eq_attr "umips_short_insn" "yes")
+	       (match_test "TARGET_MICROMIPS"))
+	  (const_int 2)
+
 	  ;; Direct branch instructions have a range of [-0x20000,0x1fffc],
-	  ;; relative to the address of the delay slot.  If a branch is
-	  ;; outside this range, we have a choice of two sequences.
+	  ;; relative to the address of the delay slot.
+	  ;;
+	  ;; For microMIPS the range is reduced to [-0x10000,0xfffe].
+	  ;;
+	  ;; If a branch is outside this range, we have a choice of two
+	  ;; sequences.
+	  ;;
 	  ;; For PIC, an out-of-range branch like:
 	  ;;
 	  ;;	bne	r1,r2,target
@@ -430,11 +657,19 @@
 	  ;; pattern has no explicit delay slot, mips_adjust_insn_length
 	  ;; will add the length of the implicit nop.  The values for
 	  ;; forward and backward branches will be different as well.
+
 	  (eq_attr "type" "branch")
-	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
-			  (le (minus (pc) (match_dup 0)) (const_int 131068)))
+	  	 ;; any variant can handle the 17-bit range
+	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 65532))
+		      (le (minus (pc) (match_dup 0)) (const_int 65534)))
 		   (const_int 4)
 
+		 ;; The 18-bit range is OK other than for microMIPS.
+		 (and (eq (symbol_ref "TARGET_MICROMIPS") (const_int 0))
+		      (and (le (minus (match_dup 0) (pc)) (const_int 131064))
+		      	   (le (minus (pc) (match_dup 0)) (const_int 131068))))
+		   (const_int 4)
+
 		 ;; The non-PIC case: branch, first delay slot, and J.
 		 (match_test "TARGET_ABSOLUTE_JUMPS")
 		   (const_int 12)]
@@ -458,6 +693,9 @@
 	  (eq_attr "got" "xgot_high")
 	  (const_int 8)
 
+	  (eq_attr "type" "multimem")
+	  (const_int 4)
+
 	  ;; In general, constant-pool loads are extended instructions.
 	  (eq_attr "move_type" "loadpool")
 	  (const_int 8)
@@ -602,6 +840,9 @@
 ;; modes.
 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
 
+(define_mode_iterator MOVEP1 [SI SF])
+(define_mode_iterator MOVEP2 [SI SF])
+
 ;; This mode iterator allows :HILO to be used as the mode of the
 ;; concatenated HI and LO registers.
 (define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
@@ -3802,7 +4043,7 @@
 (define_insn "mov_<load>l"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "YC")]
 		    UNSPEC_LOAD_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
   "<load>l\t%0,%2"
@@ -3812,7 +4053,7 @@
 (define_insn "mov_<load>r"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "YC")
 		     (match_operand:GPR 3 "register_operand" "0")]
 		    UNSPEC_LOAD_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
@@ -3823,7 +4064,7 @@
 (define_insn "mov_<store>l"
   [(set (match_operand:BLK 0 "memory_operand" "=m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "YC")]
 		    UNSPEC_STORE_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
   "<store>l\t%z1,%2"
@@ -3833,7 +4074,7 @@
 (define_insn "mov_<store>r"
   [(set (match_operand:BLK 0 "memory_operand" "+m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "YC")
 		     (match_dup 0)]
 		    UNSPEC_STORE_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
@@ -5352,12 +5593,38 @@
 			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
 	 (label_ref (match_operand 0 "" ""))
 	 (pc)))]
-  "!TARGET_MIPS16"
+  "!TARGET_MIPS16 && !TARGET_MICROMIPS"
 {
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
 }
+  [(set_attr "type" "branch")
+   (set_attr "mode" "none")])
+
+(define_insn "*branch_equality<mode>_micromips"
+  [(set (pc)
+	(if_then_else
+	 (match_operator 1 "equality_operator"
+			 [(match_operand:GPR 2 "register_operand" "d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
+	 (label_ref (match_operand 0 "" ""))
+	 (pc)))]
+  "TARGET_MICROMIPS"
+{
+  /* For a simple bnez or beqz microMIPS branch.  */
+  if (!TARGET_BRANCHLIKELY
+      && get_attr_length (insn) <= 8
+      && GET_CODE (operands[3]) == CONST_INT
+      && INTVAL (operands[3]) == 0)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%C1z%:\t%2,%0",
+					   "%*b%N1z%:\t%2,%0");
+
+  return mips_output_conditional_branch (insn, operands,
+					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
+					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
+}
   [(set_attr "type" "branch")])
 
 (define_insn "*branch_equality<mode>_inverted"
@@ -5368,7 +5635,7 @@
 			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
 	 (pc)
 	 (label_ref (match_operand 0 "" ""))))]
-  "!TARGET_MIPS16"
+  "!TARGET_MIPS16 && !TARGET_MICROMIPS"
 {
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
@@ -5438,6 +5705,32 @@
 		      (label_ref (match_operand 1))
 		      (pc)))])
 
+(define_insn "*branch_equality<mode>_inverted_micromips"
+  [(set (pc)
+	(if_then_else
+	 (match_operator 0 "equality_operator"
+			 [(match_operand:GPR 2 "register_operand" "d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
+	 (pc)
+	 (label_ref (match_operand 1 "" ""))))]
+  "TARGET_MICROMIPS"
+{
+  /* For a simple bnez or beqz microMIPS branch.  */
+  if (!TARGET_BRANCHLIKELY
+      && get_attr_length (insn) <= 8
+      && GET_CODE (operands[3]) == CONST_INT
+      && INTVAL (operands[3]) == 0)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%N0z%:\t%2,%1",
+					   "%*b%C0z%:\t%2,%1");
+
+  return mips_output_conditional_branch (insn, operands,
+					 MIPS_BRANCH ("b%N0", "%2,%z3,%1"),
+					 MIPS_BRANCH ("b%C0", "%2,%z3,%1"));
+}
+  [(set_attr "type" "branch")
+   (set_attr "mode" "none")])
+
 ;; Branch if bit is set/clear.
 
 (define_insn "*branch_bit<bbv><mode>"
@@ -5672,7 +5965,14 @@
   [(set (pc)
 	(label_ref (match_operand 0)))]
   "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
-  { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
+{
+  /* Use a branch for microMIPS.  The assembler will choose
+     a 16-bit branch, a 32-bit branch, or a 32-bit jump.  */
+  if (TARGET_MICROMIPS && !TARGET_ABICALLS_PIC2)
+    return "%*b\t%l0%/";
+  else
+    return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+}
   [(set_attr "type" "jump")])
 
 (define_insn "*jump_pic"
@@ -5712,7 +6012,12 @@
 (define_insn "indirect_jump_<mode>"
   [(set (pc) (match_operand:P 0 "register_operand" "d"))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -5749,7 +6054,12 @@
 	(match_operand:P 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -5871,7 +6181,12 @@
   [(any_return)
    (use (match_operand 0 "pmode_register_operand" ""))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type"	"jump")
    (set_attr "mode"	"none")])
 
@@ -6127,7 +6442,12 @@
   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
 	 (match_operand 1 "" ""))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 0, 1); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J (operands, 0);
+    else
+      return MIPS_CALL ("j", operands, 0, 1);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6148,7 +6468,12 @@
         (call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
               (match_operand 2 "" "")))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J (operands, 1);
+    else
+      return MIPS_CALL ("j", operands, 1, 2);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6160,7 +6485,12 @@
 	(call (mem:SI (match_dup 1))
 	      (match_dup 2)))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J (operands, 1);
+    else
+      return MIPS_CALL ("j", operands, 1, 2);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6406,7 +6736,7 @@
 
 
 (define_insn "prefetch"
-  [(prefetch (match_operand:QI 0 "address_operand" "p")
+  [(prefetch (match_operand:QI 0 "address_operand" "YD")
 	     (match_operand 1 "const_int_operand" "n")
 	     (match_operand 2 "const_int_operand" "n"))]
   "ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
@@ -6688,6 +7018,9 @@
 ; MIPS fixed-point instructions.
 (include "mips-fixed.md")
 
+; microMIPS patterns.
+(include "micromips.md")
+
 ; ST-Microelectronics Loongson-2E/2F-specific patterns.
 (include "loongson.md")
 
Index: gcc/config/mips/mips.opt
===================================================================
--- gcc/config/mips/mips.opt	(revision 189440)
+++ gcc/config/mips/mips.opt	(working copy)
@@ -221,6 +221,13 @@ minterlink-mips16
 Target Report Var(TARGET_INTERLINK_MIPS16) Init(0)
 Generate code that can be safely linked with MIPS16 code.
 
+mjals
+Target Report Var(TARGET_JALS) Init(1)
+Generate jals for microMIPS by recognizing that the branch delay slot
+instruction can be 16 bits.  This implies that the function call cannot
+switch the current mode during the linking stage, because we don't have
+jalxs that supports 16-bit branch delay slot instructions.
+
 mips
 Target RejectNegative Joined ToLower Enum(mips_mips_opt_value) Var(mips_isa_option)
 -mipsN	Generate code for ISA level N
@@ -261,6 +268,10 @@ mmemcpy
 Target Report Mask(MEMCPY)
 Don't optimize block moves
 
+mmicromips
+Target Report Mask(MICROMIPS)
+Use microMIPS instructions
+
 mmt
 Target Report Var(TARGET_MT)
 Allow the use of MT instructions
Index: gcc/config/mips/sync.md
===================================================================
--- gcc/config/mips/sync.md	(revision 189440)
+++ gcc/config/mips/sync.md	(working copy)
@@ -60,7 +60,7 @@
 ;; Can be removed in favor of atomic_compare_and_swap below.
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+YE,YE"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
 			      (match_operand:GPR 3 "arith_operand" "I,d")]
@@ -90,7 +90,7 @@
 ;; Helper insn for mips_expand_atomic_qihi.
 (define_insn "compare_and_swap_12"
   [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-	(match_operand:SI 1 "memory_operand" "+R,R"))
+	(match_operand:SI 1 "memory_operand" "+YE,YE"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
 			     (match_operand:SI 3 "register_operand" "d,d")
@@ -107,7 +107,7 @@
    (set_attr "sync_insn1_op2" "5")])
 
 (define_insn "sync_add<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+YE,YE")
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 0)
 		     (match_operand:GPR 1 "arith_operand" "I,d"))]
@@ -135,7 +135,7 @@
 
 ;; Helper insn for sync_<optab><mode>
 (define_insn "sync_<optab>_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+YE")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -175,7 +175,7 @@
 ;; Helper insn for sync_old_<optab><mode>
 (define_insn "sync_old_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+YE"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -218,7 +218,7 @@
 (define_insn "sync_new_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+YE")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
@@ -258,7 +258,7 @@
 
 ;; Helper insn for sync_nand<mode>
 (define_insn "sync_nand_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+YE")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -297,7 +297,7 @@
 ;; Helper insn for sync_old_nand<mode>
 (define_insn "sync_old_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+YE"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -338,7 +338,7 @@
 (define_insn "sync_new_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+YE")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (match_operand:SI 4 "reg_or_0_operand" "dJ")]
@@ -361,7 +361,7 @@
    (set_attr "sync_insn1_op2" "4")])
 
 (define_insn "sync_sub<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R")
+  [(set (match_operand:GPR 0 "memory_operand" "+YE")
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 0)
 		      (match_operand:GPR 1 "register_operand" "d"))]
@@ -375,7 +375,7 @@
 ;; Can be removed in favor of atomic_fetch_add below.
 (define_insn "sync_old_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+YE,YE"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 1)
@@ -390,7 +390,7 @@
 
 (define_insn "sync_old_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-	(match_operand:GPR 1 "memory_operand" "+R"))
+	(match_operand:GPR 1 "memory_operand" "+YE"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 1)
@@ -405,7 +405,7 @@
 
 (define_insn "sync_new_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-        (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+        (plus:GPR (match_operand:GPR 1 "memory_operand" "+YE,YE")
 		  (match_operand:GPR 2 "arith_operand" "I,d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -421,7 +421,7 @@
 
 (define_insn "sync_new_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-        (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+        (minus:GPR (match_operand:GPR 1 "memory_operand" "+YE")
 		   (match_operand:GPR 2 "register_operand" "d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -436,7 +436,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_<optab><mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+YE,YE")
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
 			      (match_dup 0))]
@@ -449,7 +449,7 @@
 
 (define_insn "sync_old_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+YE,YE"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -464,7 +464,7 @@
 
 (define_insn "sync_new_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+YE,YE"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -479,7 +479,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_nand<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+YE,YE")
 	(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
@@ -491,7 +491,7 @@
 
 (define_insn "sync_old_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+YE,YE"))
    (set (match_dup 1)
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
@@ -505,7 +505,7 @@
 
 (define_insn "sync_new_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+YE,YE"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_NEW_OP))]
@@ -520,7 +520,7 @@
 
 (define_insn "sync_lock_test_and_set<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+YE,YE"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
 	 UNSPEC_SYNC_EXCHANGE))]
@@ -547,7 +547,7 @@
 
 (define_insn "test_and_set_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+YE"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
 			     (match_operand:SI 3 "register_operand" "d")
@@ -577,7 +577,7 @@
 	;; TODO: the obscuring unspec can be relaxed for permissive memory
 	;; models.
 	;; Same applies to other atomic_* patterns.
-	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+R,R")
+	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+YE,YE")
 			      (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
 	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
    (set (match_operand:GPR 1 "register_operand" "=&d,&d")
@@ -630,7 +630,7 @@
 
 (define_insn "atomic_exchange<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+YE,YE")]
 	 UNSPEC_ATOMIC_EXCHANGE))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
@@ -684,7 +684,7 @@
 
 (define_insn "atomic_fetch_add<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+YE,YE")]
 	 UNSPEC_ATOMIC_FETCH_OP))
    (set (match_dup 1)
 	(unspec_volatile:GPR
Index: gcc/config/mips/mips-cpus.def
===================================================================
--- gcc/config/mips/mips-cpus.def	(revision 189440)
+++ gcc/config/mips/mips-cpus.def	(working copy)
@@ -95,6 +95,8 @@ MIPS_CPU ("4ksc", PROCESSOR_4KC, 32, 0)
 
 /* MIPS32 Release 2 processors.  */
 MIPS_CPU ("m4k", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14kc", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14k", PROCESSOR_M4K, 33, 0)
 MIPS_CPU ("4kec", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kem", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kep", PROCESSOR_4KP, 33, 0)
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 189440)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -178,6 +178,11 @@ extern bool mips_symbolic_constant_p (rtx, enum mi
 extern int mips_regno_mode_ok_for_base_p (int, enum machine_mode, bool);
 extern bool mips_stack_address_p (rtx, enum machine_mode);
 extern int mips_address_insns (rtx, enum machine_mode, bool);
+extern int umips_address_insns (rtx, enum machine_mode, bool);
+extern int umips_three_reg (rtx insn);
+extern int umips_two_reg (rtx insn);
+extern int umips_two_reg_match0 (rtx insn);
+extern int umips_three_reg_match0 (rtx insn);
 extern int mips_const_insns (rtx);
 extern int mips_split_const_insns (rtx);
 extern int mips_load_store_insns (rtx, rtx);
@@ -328,6 +333,12 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern const char *umips_output_save_restore (bool, rtx);
+extern bool umips_save_restore_pattern_p (bool, rtx);
+extern bool umips_load_store_pair_p (bool, bool, rtx, rtx, rtx);
+extern const char *umips_output_load_store_pair (bool, rtx, rtx);
+extern bool umips_movep_target_p (rtx, rtx);
+
 extern bool mips_eh_uses (unsigned int);
 extern bool mips_epilogue_uses (unsigned int);
 extern void mips_final_prescan_insn (rtx, rtx *, int);
Index: mips.c
===================================================================
--- mips.c	(revision 189440)
+++ mips.c	(working copy)
@@ -79,6 +79,10 @@ along with GCC; see the file COPYING3.  If not see
    preserve the maximum stack alignment.  We therefore use a value
    of 0x7ff0 in this case.
 
+   microMIPS LWM and SWM support 12-bit offsets (from -2048 to 2047) and
+   to preserve the maximum stack alignment, so 0x7f0 is used when
+   TARGET_MICROMIPS.
+
    MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
    up to 0x7f8 bytes and can usually save or restore all the registers
    that we need to save or restore.  (Note that we can only use these
@@ -89,7 +93,8 @@ along with GCC; see the file COPYING3.  If not see
    to save and restore registers, and to allocate and deallocate the top
    part of the frame.  */
 #define MIPS_MAX_FIRST_STACK_STEP					\
-  (!TARGET_MIPS16 ? 0x7ff0						\
+  ((!TARGET_MIPS16 && !TARGET_MICROMIPS) ? 0x7ff0			\
+   : TARGET_MICROMIPS ? 0x7f0						\
    : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8				\
    : TARGET_64BIT ? 0x100 : 0x400)
 
@@ -543,6 +548,9 @@ static int mips_base_target_flags;
 /* True if MIPS16 is the default mode.  */
 bool mips_base_mips16;
 
+/* True if microMIPS is the default mode.  */
+bool mips_base_micromips;
+
 /* The ambient values of other global variables.  */
 static int mips_base_schedule_insns; /* flag_schedule_insns */
 static int mips_base_reorder_blocks_and_partition; /* flag_reorder... */
@@ -652,8 +660,11 @@ static const struct attribute_spec mips_attribute_
      attributes, but GCC doesn't provide the hooks we need to support
      the right conversion rules.  As declaration attributes, they affect
      code generation but don't carry other semantics.  */
-  { "mips16", 	   0, 0, true,  false, false, NULL, false },
-  { "nomips16",    0, 0, true,  false, false, NULL, false },
+  { "mips16",	     0, 0, true,  false, false, NULL, false },
+  { "nomips16",	     0, 0, true,  false, false, NULL, false },
+  { "micromips",     0, 0, true,  false, false, NULL, false },
+  { "nomicromips",   0, 0, true,  false, false, NULL, false },
+  { "nocompression", 0, 0, true,  false, false, NULL, false },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 0, false, true,  true, NULL, false },
   { "use_shadow_register_set",	0, 0, false, true,  true, NULL, false },
@@ -1201,6 +1212,16 @@ mips_nomips16_decl_p (const_tree decl)
   return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
 }
 
+static bool
+mips_nocompression_decl_p (const_tree decl)
+{
+  if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
+    return true;
+
+  return (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL
+          && lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL);
+}
+
 /* Check if the interrupt attribute is set for a function.  */
 
 static bool
@@ -1258,6 +1279,41 @@ mips_use_mips16_mode_p (tree decl)
   return mips_base_mips16;
 }
 
+/* Similar predicates for "micromips"/"nomicromips" function attributes.  */
+
+static bool
+mips_micromips_decl_p (const_tree decl)
+{
+  return lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL;
+}
+
+static bool
+mips_nomicromips_decl_p (const_tree decl)
+{
+  return lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL;
+}
+
+/* Return true if function DECL is a microMIPS function.  Return the ambient
+   setting if DECL is null.  */
+
+static bool
+mips_use_micromips_mode_p (tree decl)
+{
+  if (decl)
+    {
+      /* Nested functions must use the same frame pointer as their
+	 parent and must therefore use the same ISA mode.  */
+      tree parent = decl_function_context (decl);
+      if (parent)
+	decl = parent;
+      if (mips_micromips_decl_p (decl))
+	return true;
+      if (mips_nomicromips_decl_p (decl))
+	return false;
+    }
+  return mips_base_micromips;
+}
+
 /* Implement TARGET_COMP_TYPE_ATTRIBUTES.  */
 
 static int
@@ -1278,21 +1334,35 @@ mips_insert_attributes (tree decl, tree *attribute
 {
   const char *name;
   bool mips16_p, nomips16_p;
+  bool micromips_p, nomicromips_p;
+  bool nocompression_p;
 
   /* Check for "mips16" and "nomips16" attributes.  */
   mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
   nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+  micromips_p = lookup_attribute ("micromips", *attributes) != NULL;
+  nomicromips_p = lookup_attribute ("nomicromips", *attributes) != NULL;
+  nocompression_p = lookup_attribute ("nocompression", *attributes) != NULL;
+
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
       if (mips16_p)
 	error ("%qs attribute only applies to functions", "mips16");
       if (nomips16_p)
 	error ("%qs attribute only applies to functions", "nomips16");
+      if (micromips_p)
+	error ("%qs attribute only applies to functions", "micromips");
+      if (nomicromips_p)
+	error ("%qs attribute only applies to functions", "nomicromips");
+      if (nocompression_p)
+	error ("%qs attribute only applies to functions", "nocompression");
+  
     }
   else
     {
       mips16_p |= mips_mips16_decl_p (decl);
       nomips16_p |= mips_nomips16_decl_p (decl);
+      nocompression_p | mips_nocompression_decl_p (decl);
       if (mips16_p || nomips16_p)
 	{
 	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
@@ -1301,6 +1371,14 @@ mips_insert_attributes (tree decl, tree *attribute
 		   "%<nomips16%> attributes",
 		   DECL_NAME (decl));
 	}
+      else if (mips16_p || nocompression_p)
+	{
+	  /* DECL cannot be simultaneously "mips16" and "nocompression".  */
+	  if (mips16_p && nocompression_p)
+	    error ("%qE cannot have both %<mips16%> and "
+		   "%<nocompression%> attributes",
+		   DECL_NAME (decl));
+	}
       else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
 	{
 	  /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
@@ -1309,6 +1387,39 @@ mips_insert_attributes (tree decl, tree *attribute
 	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
 	}
+
+      micromips_p |= mips_micromips_decl_p (decl);
+      nomicromips_p |= mips_nomicromips_decl_p (decl);
+      if (micromips_p || nomicromips_p)
+	{
+	  /* DECL cannot be simultaneously "micromips" and "nomicromips".  */
+	  if (micromips_p && nomicromips_p)
+	    error ("%qs cannot have both %<micromips%> and "
+		   "%<nomicromips%> attributes",
+		   IDENTIFIER_POINTER (DECL_NAME (decl)));
+	}
+      else if (micromips_p || nocompression_p)
+	{
+	  /* DECL cannot be simultaneously "micromips" and "nocompression".  */
+	  if (micromips_p && nocompression_p)
+	    error ("%qE cannot have both %<micromips%> and "
+		   "%<nocompression%> attributes",
+		   DECL_NAME (decl));
+	}
+
+      if (mips16_p && micromips_p)
+	error ("%qs cannot have both %<mips16%> and %<micromips%> attributes",
+	       IDENTIFIER_POINTER (DECL_NAME (decl)));
+
+      /* If DECL is "nocompression" set the "nomips16" and 
+	 "nomicromips" attributes.  */
+      if (nocompression_p)
+	{
+	  name = "nomips16";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	  name = "nomicromips";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	}
     }
 }
 
@@ -2262,6 +2373,7 @@ mips_address_insns (rtx x, enum machine_mode mode,
     switch (addr.type)
       {
       case ADDRESS_REG:
+
 	if (TARGET_MIPS16
 	    && !mips16_unextended_reference_p (mode, addr.reg,
 					       UINTVAL (addr.offset)))
@@ -2280,6 +2392,39 @@ mips_address_insns (rtx x, enum machine_mode mode,
   return 0;
 }
 
+int
+umips_address_insns (rtx x, enum machine_mode mode, bool might_split_p)
+{
+  struct mips_address_info addr;
+  int factor;
+
+  /* BLKmode is used for single unaligned loads and stores and should
+     not count as a multiword mode.  (GET_MODE_SIZE (BLKmode) is pretty
+     meaningless, so we have to single it out as a special case one way
+     or the other.)  */
+  if (mode != BLKmode && might_split_p)
+    factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  else
+    factor = 1;
+
+  if (mips_classify_address (&addr, x, mode, false))
+    switch (addr.type)
+      {
+      case ADDRESS_REG:
+	if (!CONST_INT_P (addr.offset)
+	    || INTVAL (addr.offset) < -2048
+	    || INTVAL (addr.offset) > 2047)
+	  return 0;
+
+	return factor;
+
+      default:
+	break;
+
+      }
+  return 0;
+}
+
 /* Return the number of instructions needed to load constant X.
    Return 0 if X isn't a valid constant.  */
 
@@ -2402,6 +2547,66 @@ mips_load_store_insns (rtx mem, rtx insn)
   return mips_address_insns (XEXP (mem, 0), mode, might_split_p);
 }
 
+/* Return true if the insn has three micromips register operands.  */
+int
+umips_three_reg (rtx insn)
+{
+   rtx op0 = XEXP (insn, 0);
+   rtx op1 = XEXP (insn, 1);
+   rtx op2 = XEXP (insn, 2);
+
+   return (op0 != NULL_RTX
+           && op1 != NULL_RTX
+	   && op2 != NULL_RTX
+	   && REG_P (op0)
+	   && M16_REG_P (REGNO (op0))
+	   && REG_P (op1)
+	   && M16_REG_P (REGNO (op1))
+	   && REG_P (op2)
+	   && M16_REG_P (REGNO (op2)));
+}
+
+/* Return true if the insn has two micromips register operands.  */
+int
+umips_two_reg (rtx insn)
+{
+   rtx op0 = XEXP (insn, 0);
+   rtx op1 = XEXP (insn, 1);
+
+   return (op0 != NULL_RTX
+           && op1 != NULL_RTX
+	   && REG_P (op0)
+	   && M16_REG_P (REGNO (op0))
+	   && REG_P (op1)
+	   && M16_REG_P (REGNO (op1)));
+}
+
+/* Return true if this insn has two microMIPS register operands
+   and the the register numbers are identical.  */
+int
+umips_two_reg_match0 (rtx insn)
+{
+  rtx op0 = XEXP (insn, 0);
+  rtx op1 = XEXP (insn, 1);
+
+  return (umips_two_reg (insn)
+          && REGNO (op0) == REGNO (op1));
+}
+/* Return true if this insn has three microMIPS register operands
+   and the the register number for either operand 1 or operand 2
+   is identical to the register number for operand 0.  */
+int
+umips_three_reg_match0 (rtx insn)
+{
+  rtx op0 = XEXP (insn, 0);
+  rtx op1 = XEXP (insn, 1);
+  rtx op2 = XEXP (insn, 2);
+
+  return (umips_three_reg (insn)
+          && (REGNO (op0) == REGNO (op1)
+	      || REGNO (op0) == REGNO (op2)));
+}
+
 /* Return the number of instructions needed for an integer division.  */
 
 int
@@ -5920,6 +6125,11 @@ mips_start_function_definition (const char *name,
   else
     fprintf (asm_out_file, "\t.set\tnomips16\n");
 
+  if (TARGET_MICROMIPS)
+    fprintf (asm_out_file, "\t.set\tmicromips\n");
+  else
+    fprintf (asm_out_file, "\t.set\tnomicromips\n");
+
   if (!flag_inhibit_size_directive)
     {
       fputs ("\t.ent\t", asm_out_file);
@@ -6739,12 +6949,35 @@ mips_function_ok_for_sibcall (tree decl, tree exp
   if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
     return false;
 
+  if (TARGET_MICROMIPS)
+    {
+      /* We can't do a sibcall if the called function is a MIPS32 function.  */
+      if (decl
+	  && !mips_use_micromips_mode_p (decl)
+	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+	return false;
+
+      /* When -minterlink-mips16 is in effect, assume that non-locally-binding
+	 functions could be MIPS32 ones unless an attribute explicitly tells
+	 us otherwise.  */
+      if (TARGET_INTERLINK_MIPS16
+	  && decl
+	  && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
+	  && !mips_micromips_decl_p (decl)
+	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+	return false;
+
+      /* Otherwise OK.  */
+      return true;
+    }
+
   /* We can't do a sibcall if the called function is a MIPS16 function
      because there is no direct "jx" instruction equivalent to "jalx" to
      switch the ISA mode.  We only care about cases where the sibling
      and normal calls would both be direct.  */
   if (decl
-      && mips_use_mips16_mode_p (decl)
+      && (mips_use_mips16_mode_p (decl)
+         || mips_use_micromips_mode_p (decl))
       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
     return false;
 
@@ -6755,6 +6988,7 @@ mips_function_ok_for_sibcall (tree decl, tree exp
       && decl
       && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
       && !mips_nomips16_decl_p (decl)
+      && !mips_nomicromips_decl_p (decl)
       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
     return false;
 
@@ -7625,6 +7859,9 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_s
    '^'	Print the name of the pic call-through register (t9 or $25).
    '+'	Print the name of the gp register (usually gp or $28).
    '$'	Print the name of the stack pointer register (sp or $29).
+   ':'  Print "c" to use the compact version if the delay slot is a nop.
+   '!'  Print "s" to use the short version if the delay slot contains a
+	16-bit instruction.
 
    See also mips_init_print_operand_pucnt.  */
 
@@ -7708,6 +7945,28 @@ mips_print_operand_punctuation (FILE *file, int ch
       fputs (reg_names[STACK_POINTER_REGNUM], file);
       break;
 
+    case ':':
+      /* When reorder or noreorder with final_squence 0, the delay slot will
+	 be a nop, so we just use the compact version for microMIPS.  */
+      if (mips_noreorder.nesting_level == 0 || final_sequence == 0)
+	putc ('c', file);
+      break;
+
+    case '!':
+      /* When reorder or noreorder with final_squence 0, the delay slot will
+	 be a nop, so we just use the compact version for microMIPS.  */
+      if (mips_noreorder.nesting_level == 0 || final_sequence == 0)
+	putc ('s', file);
+      else 
+	{
+	 /* Use the compact version for microMIPS if the delay slot
+	    is a compact microMIPS instruction.  */
+	  rtx insn = XVECEXP (final_sequence, 0, 1);
+	  if (get_attr_length (insn) == 2)
+	    putc ('s', file);
+	}
+      break;
+
     default:
       gcc_unreachable ();
       break;
@@ -7721,7 +7980,7 @@ mips_init_print_operand_punct (void)
 {
   const char *p;
 
-  for (p = "()[]<>*#/?~.@^+$"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$:!"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -10033,6 +10292,131 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset,
       }
 }
 
+static void mips_save_reg (rtx reg, rtx mem);
+
+/* Build microMIPS save or restore.  FN is save or restore function.
+   OFFSET is the current stack offset.
+   Return true if we succeed creating save or restore.  */
+
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+			      HOST_WIDE_INT offset)
+{
+  int i, num_of_reg;
+  unsigned int j;
+  rtx pattern, set, reg, mem;
+  HOST_WIDE_INT this_offset;
+  rtx this_base;
+  unsigned int type[19] = {0x00010000, 0x00030000, 0x00070000, 0x000f0000,
+			   0x001f0000, 0x003f0000, 0x007f0000, 0x00ff0000,
+			   0x40ff0000, 0x80000000, 0x80010000, 0x80030000,
+			   0x80070000, 0x800f0000, 0x801f0000, 0x803f0000,
+			   0x807f0000, 0x80ff0000, 0xc0ff0000};
+  unsigned int encode[19] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19,
+			     20, 21, 22, 23, 24, 25};
+
+  /* LWM/SWM can only support offsets from -2048 to 2047.  */
+  if (offset < -2048 || offset > 2047)
+    return false;
+
+  /* Try matching $16 to $31 (s0 to ra).  */
+  for (i = 0; i < 19; i++)
+    if ((cfun->machine->frame.mask & 0xffff0000) == type[i])
+      break;
+
+  if (i == 19)
+    {
+      /* Try matching $16 to $23 (s0 to s7) only.  */
+      for (i = 0; i < 8; i ++)
+	if ((cfun->machine->frame.mask & 0x00ff0000) == type[i])
+	  break;
+
+      if (i == 8)
+	return false;
+    }
+
+  /* For only one register, we use normal sw/lw for speed.  */
+  if (i == 0 || i == 9)
+    return false;
+
+  /* For $31 to $24.  */
+  if (i < 8 && (cfun->machine->frame.mask & 0xff000000))
+    {
+      int regno;
+      for (regno = GP_REG_LAST; regno > GP_REG_LAST - 8; regno--)
+	if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+	  {
+	    mips_save_restore_reg (word_mode, regno, offset, fn);
+	    offset -= UNITS_PER_WORD;
+	  }
+    }
+
+  /* Adjust offset for output.  */
+  num_of_reg = (encode[i] & 0xf) + (encode[i] >> 4);
+  offset -= (UNITS_PER_WORD * (num_of_reg - 1));
+
+  /* Create the final PARALLEL.  */
+  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_of_reg));
+
+  this_base = stack_pointer_rtx;
+  this_offset = offset;
+
+  /* For $16-$23, $30.  */
+  for (j = 0; j < (encode[i] & 0xf); j++)
+    {
+      unsigned int regno;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base,
+			   this_offset + j * UNITS_PER_WORD));
+      regno = (j != 8) ? 16 + j : 30;
+      reg = gen_rtx_REG (SImode, regno);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  /* For $31.  */
+  if (encode[i] >> 4)
+    {
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base,
+			   this_offset + j * UNITS_PER_WORD));
+      reg = gen_rtx_REG (SImode, 31);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  pattern = emit_insn (pattern);
+  if (fn == mips_save_reg)
+    RTX_FRAME_RELATED_P(pattern) = 1;  
+
+  /* Adjust the last offset.  */
+  offset -= UNITS_PER_WORD;
+
+  /* For $15 to $0.  */
+  if (cfun->machine->frame.mask & 0xffff)
+    {
+      int regno;
+      for (regno = GP_REG_FIRST + 15; regno >= GP_REG_FIRST; regno--)
+	if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+	  {
+	    mips_save_restore_reg (word_mode, regno, offset, fn);
+	    offset -= UNITS_PER_WORD;
+	  }
+    }
+
+  return true;
+}
+
 /* Call FN for each register that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -10050,6 +10434,13 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
   offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+
+  if (TARGET_MICROMIPS)
+    {
+      if (umips_build_save_restore (fn, offset))
+	goto save_restore_fp_reg;
+    }
+
   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
     if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
       {
@@ -10060,6 +10451,8 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
 	offset -= UNITS_PER_WORD;
       }
 
+save_restore_fp_reg:
+
   /* This loop must iterate over the same space as its companion in
      mips_compute_frame_info.  */
   offset = cfun->machine->frame.fp_sp_offset - sp_offset;
@@ -10731,12 +11124,17 @@ mips_restore_reg (rtx reg, rtx mem)
    BASE, if not the stack pointer, is available as a temporary.  */
 
 static void
-mips_deallocate_stack (rtx base, rtx offset, HOST_WIDE_INT new_frame_size)
+mips_deallocate_stack (rtx base, rtx offset, HOST_WIDE_INT new_frame_size,
+                       bool use_jraddiusp_p)
 {
+  if (use_jraddiusp_p)
+    return;
+
   if (base == stack_pointer_rtx && offset == const0_rtx)
     return;
 
   mips_frame_barrier ();
+
   if (offset == const0_rtx)
     {
       emit_move_insn (stack_pointer_rtx, base);
@@ -10782,6 +11180,7 @@ mips_expand_epilogue (bool sibcall_p)
   const struct mips_frame_info *frame;
   HOST_WIDE_INT step1, step2;
   rtx base, adjust, insn;
+  bool use_jraddiusp_p = false;
 
   if (!sibcall_p && mips_can_use_return_insn ())
     {
@@ -10831,7 +11230,7 @@ mips_expand_epilogue (bool sibcall_p)
       mips_emit_move (MIPS_EPILOGUE_TEMP (Pmode), adjust);
       adjust = MIPS_EPILOGUE_TEMP (Pmode);
     }
-  mips_deallocate_stack (base, adjust, step2);
+  mips_deallocate_stack (base, adjust, step2, use_jraddiusp_p);
 
   /* If we're using addressing macros, $gp is implicitly used by all
      SYMBOL_REFs.  We must emit a blockage insn before restoring $gp
@@ -10900,7 +11299,8 @@ mips_expand_epilogue (bool sibcall_p)
 
 	  /* If we don't use shoadow register set, we need to update SP.  */
 	  if (!cfun->machine->use_shadow_register_set_p)
-	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
+	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2),
+				   0, use_jraddiusp_p);
 	  else
 	    /* The choice of position is somewhat arbitrary in this case.  */
 	    mips_epilogue_emit_cfa_restores ();
@@ -10911,9 +11311,11 @@ mips_expand_epilogue (bool sibcall_p)
 	}
       else
 	/* Deallocate the final bit of the frame.  */
-	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
+	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2),
+			       0, use_jraddiusp_p);
     }
-  gcc_assert (!mips_epilogue.cfa_restores);
+  if (!use_jraddiusp_p)
+    gcc_assert (!mips_epilogue.cfa_restores);
 
   /* Add in the __builtin_eh_return stack adjustment.  We need to
      use a temporary in MIPS16 code.  */
@@ -10963,6 +11365,10 @@ mips_expand_epilogue (bool sibcall_p)
 	      rtx reg = gen_rtx_REG (Pmode, GP_REG_FIRST + 7);
 	      pat = gen_return_internal (reg);
 	    }
+	  else if (use_jraddiusp_p)
+	    {
+	      pat = gen_mips_jraddiusp (GEN_INT (step2));
+	    }
 	  else
 	    {
 	      rtx reg = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
@@ -15625,17 +16031,19 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndec
   reload_completed = 0;
 }
 \f
-/* The last argument passed to mips_set_mips16_mode, or negative if the
-   function hasn't been called yet.  */
+/* The last argument passed to mips_set_mips16_micromips_mode,
+   or negative if the function hasn't been called yet.  */
 static int was_mips16_p = -1;
+static int was_micromips_p = -1;
 
 /* Set up the target-dependent global state so that it matches the
    current function's ISA mode.  */
 
 static void
-mips_set_mips16_mode (int mips16_p)
+mips_set_mips16_micromips_mode (int mips16_p, int micromips_p)
 {
-  if (mips16_p == was_mips16_p)
+  if (mips16_p == was_mips16_p
+      && micromips_p == was_micromips_p)
     return;
 
   /* Restore base settings of various flags.  */
@@ -15701,6 +16109,18 @@ static void
       /* Switch to normal (non-MIPS16) mode.  */
       target_flags &= ~MASK_MIPS16;
 
+      if (micromips_p)
+	{
+	  /* Switch to microMIPS mode.  */
+	  target_flags |= MASK_MICROMIPS;
+
+	  /* Avoid branch likely.  */
+	  target_flags &= ~MASK_BRANCHLIKELY;
+	}
+      else
+	/* Switch to normal (non-microMIPS) mode.  */
+	target_flags &= ~MASK_MICROMIPS;
+
       /* Provide default values for align_* for 64-bit targets.  */
       if (TARGET_64BIT)
 	{
@@ -15732,6 +16152,7 @@ static void
     restore_target_globals (&default_target_globals);
 
   was_mips16_p = mips16_p;
+  was_micromips_p = micromips_p;
 }
 
 /* Implement TARGET_SET_CURRENT_FUNCTION.  Decide whether the current
@@ -15740,7 +16161,18 @@ static void
 static void
 mips_set_current_function (tree fndecl)
 {
-  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+  mips_set_mips16_micromips_mode (mips_use_mips16_mode_p (fndecl),
+				  mips_use_micromips_mode_p (fndecl));
+
+  /* Override the default setting for function alignment once it is decided
+     which mode is in force.  */
+
+  if (fndecl
+      && TARGET_MICROMIPS
+      && optimize_size
+      && ! TARGET_INTERLINK_MIPS16
+      && lookup_attribute ("aligned", DECL_ATTRIBUTES (fndecl)) == NULL)
+    DECL_ALIGN (fndecl) = 16;
 }
 \f
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -15848,13 +16280,20 @@ mips_option_override (void)
   if (global_options_set.x_mips_isa_option)
     mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
 
+#ifdef SUBTARGET_OVERRIDE_OPTIONS
+  SUBTARGET_OVERRIDE_OPTIONS;
+#endif
+
+  /* MIPS16 and microMIPS cannot coexist  */
+  if (TARGET_MICROMIPS && TARGET_MIPS16)
+    error ("unsupported combination: %s", "-mips16 -mmicromips");
+
   /* Process flags as though we were generating non-MIPS16 code.  */
   mips_base_mips16 = TARGET_MIPS16;
   target_flags &= ~MASK_MIPS16;
 
-#ifdef SUBTARGET_OVERRIDE_OPTIONS
-  SUBTARGET_OVERRIDE_OPTIONS;
-#endif
+  mips_base_micromips = TARGET_MICROMIPS;
+  target_flags &= ~MASK_MICROMIPS;
 
   /* -mno-float overrides -mhard-float and -msoft-float.  */
   if (TARGET_NO_FLOAT)
@@ -16227,9 +16666,9 @@ mips_option_override (void)
 
   /* Now select the ISA mode.
 
-     Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
-     MIPS16 mode afterwards if need be.  */
-  mips_set_mips16_mode (false);
+     Do all CPP-sensitive stuff in non-MIPS16/non-microMIPS mode;
+     We'll switch modes later if required.  */
+  mips_set_mips16_micromips_mode (false, false);
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -16489,6 +16928,262 @@ mips_mulsidi3_gen_fn (enum rtx_code ext_code)
       return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
     }
 }
+
+/* Return true if PATTERN matches the kind of instruction generated by
+   micromips_build_save_restore.  SAVE_P is true for store.  */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+  int n;
+  HOST_WIDE_INT first_offset = 0;
+  rtx first_base = 0;
+  unsigned int first_regno = 0;
+
+  for (n = 0; n < XVECLEN (pattern, 0); n++)
+    {
+      rtx set, reg, mem, this_base;
+      HOST_WIDE_INT this_offset;
+      unsigned int this_regno;
+
+      /* Check that we have a SET.  */
+      set = XVECEXP (pattern, 0, n);
+      if (GET_CODE (set) != SET)
+	return false;
+
+      /* Check that the SET is a load (if restoring) or a store
+	 (if saving).  */
+      mem = save_p ? SET_DEST (set) : SET_SRC (set);
+      if (!MEM_P (mem))
+	return false;
+
+      /* Check that the address is the sum of base and a
+	 possibly-zero constant offset.  */
+      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+      if (!REG_P (this_base))
+	return false;
+
+      if (n == 0)
+	{
+	  first_base = this_base;
+	  first_offset = this_offset;
+	}
+      else
+	{
+	  /* Check if this_base is the same as first_base.  */
+	  if (REGNO (this_base) != REGNO (first_base))
+	    return false;
+
+	  /* Check if this_offset is first_offset + UNITS_PER_WORD * n.  */
+	  if (this_offset != first_offset + UNITS_PER_WORD * n)
+	    return false;
+	}
+
+      /* Check that SET's other operand is a register.  */
+      reg = save_p ? SET_SRC (set) : SET_DEST (set);
+      if (!REG_P (reg))
+	return false;
+
+      /* Make sure the order of regno is "$16-$23, $30, $31", "$16-$23, $30",
+	 or "$31".  */
+      this_regno = REGNO (reg);
+      if (n == 0)
+	{
+	  if (this_regno != 16 && this_regno != 31)
+	    return false;
+	  first_regno = this_regno;
+	}
+      else if (n == 8) /* For s8.  */
+	{
+	  if (n == XVECLEN (pattern, 0) - 1)
+	    {
+	      if (this_regno != 30 && this_regno != 31)
+		return false;
+	    }
+	  else
+	    {
+	      if (this_regno != 30)
+		return false;
+	    }
+	}
+      else if (n != XVECLEN (pattern, 0) - 1)
+	{
+	  if (this_regno != first_regno + n)
+	    return false;
+	}
+      else /* The last item.  */
+	{
+	  if ((this_regno != first_regno + n) && this_regno != 31)
+	    return false;
+	}
+
+      /* If any item in the list is volatile then disallow.  This is a
+         safeguard only as this is a path unlikely to be exercised since 
+         typical code only generates the instructions for stack accesses.  */
+      if (MEM_VOLATILE_P (mem))
+        return false;
+    }
+
+  return true;
+}
+
+/* Return the assembly instruction for microMIPS lwm or swm.
+   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+  static char buffer[300];
+  char *s;
+  int n;
+  HOST_WIDE_INT offset;
+  rtx base, mem, set, reg, last_set, last_reg;
+
+  /* Parse the pattern.  */
+  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
+
+  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
+  s += strlen (s);
+  n = XVECLEN (pattern, 0);
+
+  set = XVECEXP (pattern, 0, 0);
+  reg = save_p ? SET_SRC (set) : SET_DEST (set);
+  mem = save_p ? SET_DEST (set) : SET_SRC (set);
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+
+  last_set = XVECEXP (pattern, 0, n - 1);
+  last_reg = save_p ? SET_SRC (last_set) : SET_DEST (last_set);
+
+  if (REGNO (last_reg) == 31)
+    n--;
+
+  gcc_assert (n <= 9);
+  if (n == 0)
+    ;
+  else if (n == 1)
+    s += sprintf (s, "%s,", reg_names[16]);
+  else if (n < 9)
+    s += sprintf (s, "%s-%s,", reg_names[16], reg_names[15 + n]);
+  else if (n == 9)
+    s += sprintf (s, "%s-%s,%s,", reg_names[16], reg_names[23],
+		  reg_names[30]);
+
+  if (REGNO (last_reg) == 31)
+    s += sprintf (s, "%s,", reg_names[31]);
+
+  s += sprintf (s, "%d(%s)", (int)offset, reg_names[REGNO (base)]);
+  return buffer;
+}
+
+/* Return true if MEM1 and MEM2 use the same base register, and the
+   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
+   register into (from) which the contents of MEM1 will be loaded
+   (stored), depending on the value of LOAD_P.
+   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
+
+bool
+umips_load_store_pair_p (bool load_p, bool swap_p, rtx first_reg,
+			 rtx mem1, rtx mem2)
+{
+  rtx base1, base2, mem1_temp, mem2_temp;
+  HOST_WIDE_INT offset1, offset2;
+
+  if (!MEM_P (mem1) || !MEM_P (mem2))
+    return false;
+
+  mem1_temp = XEXP (mem1, 0);
+  mem2_temp = XEXP (mem2, 0);
+
+  /* Make sure memory is base plus offset.  */
+  if (GET_CODE (mem1_temp) != PLUS
+      || GET_CODE (mem2_temp) != PLUS
+      || GET_CODE (XEXP (mem1_temp, 1)) != CONST_INT
+      || GET_CODE (XEXP (mem2_temp, 1)) != CONST_INT)
+    return false;
+
+  mips_split_plus (mem1_temp, &base1, &offset1);
+  mips_split_plus (mem2_temp, &base2, &offset2);
+
+  if (!REG_P (base1) || !REG_P (base2))
+    return false;
+
+  if (REGNO (base1) != REGNO (base2))
+    return false;
+
+  /* Avoid invalid load pair instructions.  */
+  if (load_p && REGNO (first_reg) == REGNO (base1))
+    return false;
+
+  /* We must avoid this case for anti-dependence.
+     Ex:  lw $3, 4($3)
+          lw $2, 0($3)
+     first_reg is $2, but the base is $3.  */
+  if (load_p && swap_p && (REGNO (first_reg) + 1) == REGNO (base1))
+    return false;
+
+  if (offset1 + 4 != offset2)
+    return false;
+
+  if (offset1 < -2048 || offset1 > 2047)
+    return false;
+
+  return true;
+}
+
+/* Return the assembly instruction for microMIPS lwp or swp.
+   LOAD_P is true for load.  */
+
+const char *
+umips_output_load_store_pair (bool load_p, rtx reg, rtx mem)
+{
+  static char buffer[300];
+  HOST_WIDE_INT offset;
+  rtx base;
+
+  gcc_assert (REG_P (reg) && MEM_P (mem));
+
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+  gcc_assert (REG_P (base));
+
+  sprintf (buffer, "%s\t%s,%d(%s)", load_p ? "lwp" : "swp",
+	   reg_names [REGNO (reg)], (int) offset, reg_names [REGNO (base)]);
+  return buffer;
+}
+
+/* Return true if reg1 and reg2 can be target of movep.  */
+
+bool
+umips_movep_target_p (rtx reg1, rtx reg2)
+{
+  int regno1, regno2, pair, i;
+  int match[8] = {0x00000060,	/* 5, 6 */
+		  0x000000a0,	/* 5, 7 */
+		  0x000000c0,	/* 6, 7 */
+		  0x00200010,	/* 4, 21 */
+		  0x00400010,	/* 4, 22 */
+		  0x00000030,	/* 4, 5 */
+		  0x00000050,	/* 4, 6 */
+		  0x00000090};	/* 4, 7 */
+
+  if (!REG_P (reg1) || !REG_P (reg2))
+    return false;
+
+  regno1 = REGNO (reg1);
+  regno2 = REGNO (reg2);
+
+  if (!GP_REG_P (regno1)  || !GP_REG_P (regno2))
+    return false;
+
+  pair = (1 << regno1) | (1 << regno2);
+
+  for (i = 0; i < 8; i++)
+    {
+      if (pair == match[i])
+	return true;
+    }
+
+  return false;
+}
 \f
 /* Return the size in bytes of the trampoline code, padded to
    TRAMPOLINE_ALIGNMENT bits.  The static chain pointer and target
@@ -16743,7 +17438,7 @@ mips_prepare_pch_save (void)
      It therefore seems best to switch back to non-MIPS16 mode at
      save time, and to ensure that mips16_globals remains null after
      a PCH load.  */
-  mips_set_mips16_mode (false);
+  mips_set_mips16_micromips_mode (false, false);
   mips16_globals = 0;
 }
 \f
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	(revision 189440)
+++ gcc/config/mips/mips.h	(working copy)
@@ -386,6 +386,9 @@ struct mips_cpu_info {
       if (TARGET_SMARTMIPS)						\
 	builtin_define ("__mips_smartmips");				\
 									\
+      if (mips_base_micromips)						\
+	builtin_define ("__mips_micromips");				\
+									\
       if (TARGET_DSP)							\
 	{								\
 	  builtin_define ("__mips_dsp");				\
@@ -699,7 +702,7 @@ struct mips_cpu_info {
        |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
      %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
      %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
-       |march=34k*|march=74k*|march=1004k*: -mips32r2} \
+       |march=34k*|march=74k*|march=m14k*|march=1004k*: -mips32r2} \
      %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
        |march=xlr|march=loongson3a: -mips64} \
      %{march=mips64r2|march=octeon|march=xlp: -mips64r2} \
@@ -713,7 +716,7 @@ struct mips_cpu_info {
   "%{mhard-float|msoft-float|march=mips*:; \
      march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
      |march=34kc|march=74kc|march=1004kc|march=5kc \
-     |march=octeon|march=xlr: -msoft-float;		  \
+     |march=m14k*|march=octeon|march=xlr: -msoft-float;		  \
      march=*: -mhard-float}"
 
 /* A spec condition that matches 32-bit options.  It only works if
@@ -982,7 +985,8 @@ struct mips_cpu_info {
 				     || ISA_MIPS64R2))
 
 /* ISA has lwxs instruction (load w/scaled index address.  */
-#define ISA_HAS_LWXS		(TARGET_SMARTMIPS && !TARGET_MIPS16)
+#define ISA_HAS_LWXS		((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
+				 && !TARGET_MIPS16)
 
 /* ISA has lbx, lbux, lhx, lhx, lhux, lwx, lwux, or ldx instruction. */
 #define ISA_HAS_LBX		(TARGET_OCTEON2)
@@ -1116,6 +1120,7 @@ struct mips_cpu_info {
 %{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
 %{mips32*} %{mips64*} \
 %{mips16} %{mno-mips16:-no-mips16} \
+%{mmicromips} %{mno-micromips} \
 %{mips3d} %{mno-mips3d:-no-mips3d} \
 %{mdmx} %{mno-mdmx:-no-mdmx} \
 %{mdsp} %{mno-dsp} \
@@ -1661,6 +1666,8 @@ struct mips_cpu_info {
   ((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define M16_REG_P(REGNO) \
   (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 16 || (REGNO) == 17)
+#define M16STORE_REG_P(REGNO) \
+  (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 0 || (REGNO) == 17)
 #define FP_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
 #define MD_REG_P(REGNO) \
@@ -2002,6 +2009,24 @@ enum reg_class
   (((VALUE) | 0x7fff0000) == 0x7fff0000				\
    || ((VALUE) | 0x7fff0000) + 0x10000 == 0)
 
+/* True if this constant is valid for the microMIPS andi16 insn.  */
+#define UMIPS_ANDI16_IMM(VALUE)	\
+  (((unsigned HOST_WIDE_INT) (VALUE) == 1)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 2)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 3)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 4)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 7)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 8)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 15)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 16)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 31)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 32)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 63)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 64)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 255)	\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 32768)	\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 65536))
+
 /* Return a value X with the low 16 bits clear, and such that
    VALUE - X is a signed 16-bit value.  */
 
@@ -2430,18 +2455,46 @@ typedef struct mips_args {
    all calls should use assembly macros.  Otherwise, all indirect
    calls should use "jr" or "jalr"; we will arrange to restore $gp
    afterwards if necessary.  Finally, we can only generate direct
-   calls for -mabicalls by temporarily switching to non-PIC mode.  */
+   calls for -mabicalls by temporarily switching to non-PIC mode.
+
+   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+   instruction is in the delay slot of jal(r).  */
 #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
+  (TARGET_MICROMIPS						\
+   ? (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
+      ? (TARGET_JALS ? "%*" INSN "%!\t%" #TARGET_OPNO "%/"	\
+                     : "%*" INSN "\t%" #TARGET_OPNO "%/")	\
+      : (REG_P (OPERANDS[TARGET_OPNO])				\
+         && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
+      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
+         "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
+      : REG_P (OPERANDS[TARGET_OPNO])				\
+      ? (TARGET_JALS ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"	\
+                     : "%*" INSN "r\t%" #TARGET_OPNO "%/")	\
+      : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))	\
+  : (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
+     ? "%*" INSN "\t%" #TARGET_OPNO "%/"			\
+     : (REG_P (OPERANDS[TARGET_OPNO])				\
+        && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
+     ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
+        "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
+     : REG_P (OPERANDS[TARGET_OPNO])				\
+     ? "%*" INSN "r\t%" #TARGET_OPNO "%/"			\
+     : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/")))
+\f
+/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
+   "jrc" when nop is in the delay slot of "jr".  */
+#define MICROMIPS_J(OPERANDS, OPNO)				\
   (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
-   ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
-   : (REG_P (OPERANDS[TARGET_OPNO])				\
-      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
-   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
-      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
-   : REG_P (OPERANDS[TARGET_OPNO])				\
-   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"				\
-   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
-\f
+   ? "%*j\t%" #OPNO "%/"					\
+   : REG_P (OPERANDS[OPNO])					\
+   ? "%*jr%:\t%" #OPNO						\
+   : TARGET_ABICALLS && flag_pic				\
+   ? (".option\tpic0\n\t"					\
+      "%*j\t%" #OPNO "%/\n\t"					\
+      ".option\tpic2")						\
+   : "%*j\t%" #OPNO "%/")
+
 /* Control the assembler format that we output.  */
 
 /* Output to assembler file text saying following lines
@@ -2846,6 +2899,7 @@ extern int mips_isa;			/* architectural level */
 extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
 extern bool mips_base_mips16;
+extern bool mips_base_micromips;
 extern GTY(()) struct target_globals *mips16_globals;
 #endif
 
Index: gcc/config/mips/t-sde
===================================================================
--- gcc/config/mips/t-sde	(revision 189440)
+++ gcc/config/mips/t-sde	(working copy)
@@ -16,8 +16,8 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16 msoft-float/mfp64 mcode-readable=no
-MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 sof f64 spram
+MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16/mmicromips msoft-float/mfp64 mcode-readable=no
+MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 micromips sof f64 spram
 MULTILIB_MATCHES = EL=mel EB=meb
 
 # The -mfp64 option is only valid in conjunction with -mips32r2.
@@ -33,3 +33,6 @@ MULTILIB_EXCLUSIONS += !mips32/!mips32r2/mips16
 else
 MULTILIB_EXCLUSIONS += mips64/mips16 mips64r2/mips16
 endif
+
+# The -mcode-readable=no is only in conjunction with -mips16.
+MULTILIB_EXCLUSIONS += mcode-readable=no/!mips16

[-- Attachment #4: umips-libgcc.cl --]
[-- Type: application/octet-stream, Size: 273 bytes --]

2012-07-19  Catherine Moore  <clm@codesourcery.com>
	    Joseph Myers  <joseph@codesourcery.com>

	* config/mips/mips16.S: Do not build for microMIPS multilibs.
	* config/mips/linux-unwind.h (mips_fallback_frame_state): 
	Support lack of signal frames for microMIPS.

[-- Attachment #5: umips-libgcc.patch --]
[-- Type: application/octet-stream, Size: 1202 bytes --]

Index: config/mips/mips16.S
===================================================================
--- config/mips/mips16.S	(revision 189440)
+++ config/mips/mips16.S	(working copy)
@@ -22,6 +22,10 @@
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#ifdef __mips_micromips
+  /* DO NOTHING */
+#else
+
 /* This file contains mips16 floating point support functions.  These
    functions are called by mips16 code to handle floating point when
    -msoft-float is not used.  They accept the arguments and return
@@ -719,3 +723,4 @@
 #endif /* !__mips_single_float */
 
 #endif
+#endif /* __mips_micromips */
Index: config/mips/linux-unwind.h
===================================================================
--- config/mips/linux-unwind.h	(revision 189440)
+++ config/mips/linux-unwind.h	(working copy)
@@ -52,6 +52,11 @@
   _Unwind_Ptr new_cfa, reg_offset;
   int i;
 
+  /* microMIPS frame; the kernel does not have microMIPS signal
+     frames.  */
+  if ((_Unwind_Ptr) pc & 3)
+    return _URC_END_OF_STACK;
+
   /* 24021061 li v0, 0x1061 (rt_sigreturn)*/
   /* 0000000c syscall    */
   /*    or */

[-- Attachment #6: umips-testsuite.cl --]
[-- Type: application/octet-stream, Size: 1065 bytes --]

2012-07-19  Catherine Moore <clm@codesourcery.com>
	    Maciej W. Rozycki  <macro@codesourcery.com>

	* gcc.target/mips/branch-13.c: Use NOCOMPRESSION instead of NOMIPS16.
	* gcc.target/mips/mips-3d-6.c: Likewise.
	* gcc.target/mips/mips-3d-7.c: Likewise.
	* gcc.target/mips/branch-4.c: Likewise.
	* gcc.target/mips/no-smartmips-lwxs.c: Likewise.
	* gcc.target/mips/mips-3d-8.c: Likewise.
	* gcc.target/mips/branch-5.c: Likewise.
	* gcc.target/mips/mips-3d-1.c: Likewise.
	* gcc.target/mips/mips-3d-9.c: Likewise.
	* gcc.target/mips/branch-6.c: Likewise.
	* gcc.target/mips/mips-3d-2.c: Likewise.
	* gcc.target/mips/branch-10.c: Likewise.
	* gcc.target/mips/mips-3d-3.c: Likewise.
	* gcc.target/mips/branch-8.c: Likewise.
	* gcc.target/mips/mips-3d-4.c: Likewise.
	* gcc.target/mips/branch-12.c: Likewise.
	* gcc.target/mips/mips-3d-5.c: Likewise.
	* gcc.target/mips/branch-2.c: Likewise.
	* gcc.target/mips/near-far-1.c: Update assembler output.
	* gcc.target/mips/near-far-2.c: Likewise.
	* gcc.target/mips/mips.exp: Define NOCOMPRESSION.

[-- Attachment #7: umips-testsuite.patch --]
[-- Type: application/octet-stream, Size: 68026 bytes --]

Index: gcc.target/mips/branch-13.c
===================================================================
--- gcc.target/mips/branch-13.c	(revision 189440)
+++ gcc.target/mips/branch-13.c	(working copy)
@@ -8,7 +8,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (void (*bar) (void), volatile int *x)
 {
   bar ();
Index: gcc.target/mips/mips-3d-6.c
===================================================================
--- gcc.target/mips/mips-3d-6.c	(revision 189440)
+++ gcc.target/mips/mips-3d-6.c	(working copy)
@@ -5,24 +5,24 @@
 #include <stdlib.h>
 #include <stdio.h>
 
-NOMIPS16 int test0 (float a, float b);
-NOMIPS16 int test1 (float a, float b);
-NOMIPS16 int test2 (float a, float b);
-NOMIPS16 int test3 (float a, float b);
-NOMIPS16 int test4 (float a, float b);
-NOMIPS16 int test5 (float a, float b);
-NOMIPS16 int test6 (float a, float b);
-NOMIPS16 int test7 (float a, float b);
-NOMIPS16 int test8 (float a, float b);
-NOMIPS16 int test9 (float a, float b);
-NOMIPS16 int test10 (float a, float b);
-NOMIPS16 int test11 (float a, float b);
-NOMIPS16 int test12 (float a, float b);
-NOMIPS16 int test13 (float a, float b);
-NOMIPS16 int test14 (float a, float b);
-NOMIPS16 int test15 (float a, float b);
+NOCOMPRESSION int test0 (float a, float b);
+NOCOMPRESSION int test1 (float a, float b);
+NOCOMPRESSION int test2 (float a, float b);
+NOCOMPRESSION int test3 (float a, float b);
+NOCOMPRESSION int test4 (float a, float b);
+NOCOMPRESSION int test5 (float a, float b);
+NOCOMPRESSION int test6 (float a, float b);
+NOCOMPRESSION int test7 (float a, float b);
+NOCOMPRESSION int test8 (float a, float b);
+NOCOMPRESSION int test9 (float a, float b);
+NOCOMPRESSION int test10 (float a, float b);
+NOCOMPRESSION int test11 (float a, float b);
+NOCOMPRESSION int test12 (float a, float b);
+NOCOMPRESSION int test13 (float a, float b);
+NOCOMPRESSION int test14 (float a, float b);
+NOCOMPRESSION int test15 (float a, float b);
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   float a, b;
   int i;
@@ -203,82 +203,82 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (float a, float b)
+NOCOMPRESSION int test0 (float a, float b)
 {
   return __builtin_mips_cabs_f_s (a, b);
 }
 
-NOMIPS16 int test1 (float a, float b)
+NOCOMPRESSION int test1 (float a, float b)
 {
   return __builtin_mips_cabs_un_s (a, b);
 }
 
-NOMIPS16 int test2 (float a, float b)
+NOCOMPRESSION int test2 (float a, float b)
 {
   return __builtin_mips_cabs_eq_s (a, b);
 }
 
-NOMIPS16 int test3 (float a, float b)
+NOCOMPRESSION int test3 (float a, float b)
 {
   return __builtin_mips_cabs_ueq_s (a, b);
 }
 
-NOMIPS16 int test4 (float a, float b)
+NOCOMPRESSION int test4 (float a, float b)
 {
   return __builtin_mips_cabs_olt_s (a, b);
 }
 
-NOMIPS16 int test5 (float a, float b)
+NOCOMPRESSION int test5 (float a, float b)
 {
   return __builtin_mips_cabs_ult_s (a, b);
 }
 
-NOMIPS16 int test6 (float a, float b)
+NOCOMPRESSION int test6 (float a, float b)
 {
   return __builtin_mips_cabs_ole_s (a, b);
 }
 
-NOMIPS16 int test7 (float a, float b)
+NOCOMPRESSION int test7 (float a, float b)
 {
   return __builtin_mips_cabs_ule_s (a, b);
 }
 
-NOMIPS16 int test8 (float a, float b)
+NOCOMPRESSION int test8 (float a, float b)
 {
   return __builtin_mips_cabs_sf_s (a, b);
 }
 
-NOMIPS16 int test9 (float a, float b)
+NOCOMPRESSION int test9 (float a, float b)
 {
   return __builtin_mips_cabs_ngle_s (a, b);
 }
 
-NOMIPS16 int test10 (float a, float b)
+NOCOMPRESSION int test10 (float a, float b)
 {
   return __builtin_mips_cabs_seq_s (a, b);
 }
 
-NOMIPS16 int test11 (float a, float b)
+NOCOMPRESSION int test11 (float a, float b)
 {
   return __builtin_mips_cabs_ngl_s (a, b);
 }
 
-NOMIPS16 int test12 (float a, float b)
+NOCOMPRESSION int test12 (float a, float b)
 {
   return __builtin_mips_cabs_lt_s (a, b);
 }
 
-NOMIPS16 int test13 (float a, float b)
+NOCOMPRESSION int test13 (float a, float b)
 {
   return __builtin_mips_cabs_nge_s (a, b);
 }
 
-NOMIPS16 int test14 (float a, float b)
+NOCOMPRESSION int test14 (float a, float b)
 {
   return __builtin_mips_cabs_le_s (a, b);
 }
 
-NOMIPS16 int test15 (float a, float b)
+NOCOMPRESSION int test15 (float a, float b)
 {
   return __builtin_mips_cabs_ngt_s (a, b);
 }
Index: gcc.target/mips/mips.exp
===================================================================
--- gcc.target/mips/mips.exp	(revision 189440)
+++ gcc.target/mips/mips.exp	(working copy)
@@ -1255,6 +1255,6 @@
 mips-dg-init
 # MIPS16 is defined by "-mips16" or "(-mips16)" in dg-options.
 dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] "" \
-    "-DNOMIPS16=__attribute__((nomips16))"
+    "-DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression))"
 mips-dg-finish
 dg-finish
Index: gcc.target/mips/mips-3d-7.c
===================================================================
--- gcc.target/mips/mips-3d-7.c	(revision 189440)
+++ gcc.target/mips/mips-3d-7.c	(working copy)
@@ -5,24 +5,24 @@
 #include <stdlib.h>
 #include <stdio.h>
 
-NOMIPS16 int test0 (double a, double b);
-NOMIPS16 int test1 (double a, double b);
-NOMIPS16 int test2 (double a, double b);
-NOMIPS16 int test3 (double a, double b);
-NOMIPS16 int test4 (double a, double b);
-NOMIPS16 int test5 (double a, double b);
-NOMIPS16 int test6 (double a, double b);
-NOMIPS16 int test7 (double a, double b);
-NOMIPS16 int test8 (double a, double b);
-NOMIPS16 int test9 (double a, double b);
-NOMIPS16 int test10 (double a, double b);
-NOMIPS16 int test11 (double a, double b);
-NOMIPS16 int test12 (double a, double b);
-NOMIPS16 int test13 (double a, double b);
-NOMIPS16 int test14 (double a, double b);
-NOMIPS16 int test15 (double a, double b);
+NOCOMPRESSION int test0 (double a, double b);
+NOCOMPRESSION int test1 (double a, double b);
+NOCOMPRESSION int test2 (double a, double b);
+NOCOMPRESSION int test3 (double a, double b);
+NOCOMPRESSION int test4 (double a, double b);
+NOCOMPRESSION int test5 (double a, double b);
+NOCOMPRESSION int test6 (double a, double b);
+NOCOMPRESSION int test7 (double a, double b);
+NOCOMPRESSION int test8 (double a, double b);
+NOCOMPRESSION int test9 (double a, double b);
+NOCOMPRESSION int test10 (double a, double b);
+NOCOMPRESSION int test11 (double a, double b);
+NOCOMPRESSION int test12 (double a, double b);
+NOCOMPRESSION int test13 (double a, double b);
+NOCOMPRESSION int test14 (double a, double b);
+NOCOMPRESSION int test15 (double a, double b);
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   double a, b;
   int i;
@@ -203,82 +203,82 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (double a, double b)
+NOCOMPRESSION int test0 (double a, double b)
 {
   return __builtin_mips_cabs_f_d (a, b);
 }
 
-NOMIPS16 int test1 (double a, double b)
+NOCOMPRESSION int test1 (double a, double b)
 {
   return __builtin_mips_cabs_un_d (a, b);
 }
 
-NOMIPS16 int test2 (double a, double b)
+NOCOMPRESSION int test2 (double a, double b)
 {
   return __builtin_mips_cabs_eq_d (a, b);
 }
 
-NOMIPS16 int test3 (double a, double b)
+NOCOMPRESSION int test3 (double a, double b)
 {
   return __builtin_mips_cabs_ueq_d (a, b);
 }
 
-NOMIPS16 int test4 (double a, double b)
+NOCOMPRESSION int test4 (double a, double b)
 {
   return __builtin_mips_cabs_olt_d (a, b);
 }
 
-NOMIPS16 int test5 (double a, double b)
+NOCOMPRESSION int test5 (double a, double b)
 {
   return __builtin_mips_cabs_ult_d (a, b);
 }
 
-NOMIPS16 int test6 (double a, double b)
+NOCOMPRESSION int test6 (double a, double b)
 {
   return __builtin_mips_cabs_ole_d (a, b);
 }
 
-NOMIPS16 int test7 (double a, double b)
+NOCOMPRESSION int test7 (double a, double b)
 {
   return __builtin_mips_cabs_ule_d (a, b);
 }
 
-NOMIPS16 int test8 (double a, double b)
+NOCOMPRESSION int test8 (double a, double b)
 {
   return __builtin_mips_cabs_sf_d (a, b);
 }
 
-NOMIPS16 int test9 (double a, double b)
+NOCOMPRESSION int test9 (double a, double b)
 {
   return __builtin_mips_cabs_ngle_d (a, b);
 }
 
-NOMIPS16 int test10 (double a, double b)
+NOCOMPRESSION int test10 (double a, double b)
 {
   return __builtin_mips_cabs_seq_d (a, b);
 }
 
-NOMIPS16 int test11 (double a, double b)
+NOCOMPRESSION int test11 (double a, double b)
 {
   return __builtin_mips_cabs_ngl_d (a, b);
 }
 
-NOMIPS16 int test12 (double a, double b)
+NOCOMPRESSION int test12 (double a, double b)
 {
   return __builtin_mips_cabs_lt_d (a, b);
 }
 
-NOMIPS16 int test13 (double a, double b)
+NOCOMPRESSION int test13 (double a, double b)
 {
   return __builtin_mips_cabs_nge_d (a, b);
 }
 
-NOMIPS16 int test14 (double a, double b)
+NOCOMPRESSION int test14 (double a, double b)
 {
   return __builtin_mips_cabs_le_d (a, b);
 }
 
-NOMIPS16 int test15 (double a, double b)
+NOCOMPRESSION int test15 (double a, double b)
 {
   return __builtin_mips_cabs_ngt_d (a, b);
 }
Index: gcc.target/mips/branch-4.c
===================================================================
--- gcc.target/mips/branch-4.c	(revision 189440)
+++ gcc.target/mips/branch-4.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (volatile int *x)
 {
   if (__builtin_expect (*x == 0, 1))
Index: gcc.target/mips/no-smartmips-lwxs.c
===================================================================
--- gcc.target/mips/no-smartmips-lwxs.c	(revision 189440)
+++ gcc.target/mips/no-smartmips-lwxs.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-O -mno-smartmips" } */
 
-NOMIPS16 int scaled_indexed_word_load (int a[], int b)
+NOCOMPRESSION int scaled_indexed_word_load (int a[], int b)
 {
   return a[b];
 }
Index: gcc.target/mips/mips-3d-8.c
===================================================================
--- gcc.target/mips/mips-3d-8.c	(revision 189440)
+++ gcc.target/mips/mips-3d-8.c	(working copy)
@@ -7,42 +7,42 @@
 
 typedef float v2sf __attribute__((vector_size(8)));
 
-NOMIPS16 v2sf test0 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test1 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test2 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test3 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test4 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test5 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test6 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test7 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test8 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test9 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test10 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test11 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test12 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test13 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test14 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test15 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test16 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test17 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test18 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test19 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test20 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test21 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test22 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test23 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test24 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test25 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test26 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test27 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test28 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test29 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test30 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test31 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test0 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test1 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test2 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test3 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test4 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test5 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test6 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test7 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test8 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test9 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test10 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test11 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test12 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test13 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test14 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test15 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test16 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test17 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test18 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test19 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test20 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test21 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test22 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test23 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test24 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test25 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test26 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test27 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test28 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test29 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test30 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test31 (v2sf a, v2sf b, v2sf c, v2sf d);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   v2sf a, b, c, d, e, f;
 
@@ -469,162 +469,162 @@
   exit (0);
 }
 
-NOMIPS16 v2sf test0 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test0 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_f_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test1 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test1 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_f_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test2 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test2 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_un_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test3 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test3 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_un_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test4 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test4 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_eq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test5 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test5 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_eq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test6 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test6 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ueq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test7 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test7 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ueq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test8 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test8 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_olt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test9 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test9 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_olt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test10 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test10 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ult_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test11 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test11 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ult_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test12 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test12 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ole_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test13 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test13 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ole_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test14 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test14 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ule_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test15 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test15 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ule_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test16 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test16 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_sf_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test17 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test17 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_sf_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test18 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test18 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ngle_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test19 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test19 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ngle_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test20 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test20 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_seq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test21 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test21 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_seq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test22 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test22 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ngl_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test23 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test23 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ngl_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test24 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test24 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_lt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test25 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test25 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_lt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test26 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test26 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_nge_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test27 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test27 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_nge_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test28 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test28 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_le_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test29 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test29 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_le_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test30 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test30 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ngt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test31 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test31 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ngt_ps (a, b, c, d);
 }
Index: gcc.target/mips/branch-5.c
===================================================================
--- gcc.target/mips/branch-5.c	(revision 189440)
+++ gcc.target/mips/branch-5.c	(working copy)
@@ -6,7 +6,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (volatile int *x)
 {
   if (__builtin_expect (*x == 0, 1))
Index: gcc.target/mips/mips-3d-1.c
===================================================================
--- gcc.target/mips/mips-3d-1.c	(revision 189440)
+++ gcc.target/mips/mips-3d-1.c	(working copy)
@@ -7,7 +7,7 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   int little_endian;
   v2sf a, b, c, d;
Index: gcc.target/mips/mips-3d-9.c
===================================================================
--- gcc.target/mips/mips-3d-9.c	(revision 189440)
+++ gcc.target/mips/mips-3d-9.c	(working copy)
@@ -19,9 +19,9 @@
 float f[4]; /* Result for matrix_multiply4() */
 
 void matrix_multiply1();
-NOMIPS16 void matrix_multiply2();
-NOMIPS16 void matrix_multiply3();
-NOMIPS16 void matrix_multiply4();
+NOCOMPRESSION void matrix_multiply2();
+NOCOMPRESSION void matrix_multiply3();
+NOCOMPRESSION void matrix_multiply4();
 
 int main ()
 {
@@ -65,7 +65,7 @@
    }
 }
 
-NOMIPS16 void matrix_multiply2()
+NOCOMPRESSION void matrix_multiply2()
 {
   int i, j;
   v2sf m1, m2;
@@ -91,7 +91,7 @@
    }
 }
 
-NOMIPS16 void matrix_multiply3()
+NOCOMPRESSION void matrix_multiply3()
 {
   int i;
   v2sf m1, m2, n1, n2;
@@ -114,7 +114,7 @@
    }
 }
 
-NOMIPS16 void matrix_multiply4()
+NOCOMPRESSION void matrix_multiply4()
 {
   v2sf m1, m2;
   v2sf n1, n2, n3, n4, n5, n6, n7, n8;
Index: gcc.target/mips/near-far-1.c
===================================================================
--- gcc.target/mips/near-far-1.c	(revision 189440)
+++ gcc.target/mips/near-far-1.c	(working copy)
@@ -16,5 +16,5 @@
 
 /* { dg-final { scan-assembler-not "\tjal\tlong_call_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal\tfar_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal\tnear_func\n" } } */
+/* { dg-final { scan-assembler     "\tjals?\tnear_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal\tnormal_func\n" } } */
Index: gcc.target/mips/branch-6.c
===================================================================
--- gcc.target/mips/branch-6.c	(revision 189440)
+++ gcc.target/mips/branch-6.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (volatile int *x)
 {
   if (__builtin_expect (*x == 0, 1))
Index: gcc.target/mips/mips-3d-2.c
===================================================================
--- gcc.target/mips/mips-3d-2.c	(revision 189440)
+++ gcc.target/mips/mips-3d-2.c	(working copy)
@@ -7,42 +7,42 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int test0 (v2sf a, v2sf b);
-NOMIPS16 int test1 (v2sf a, v2sf b);
-NOMIPS16 int test2 (v2sf a, v2sf b);
-NOMIPS16 int test3 (v2sf a, v2sf b);
-NOMIPS16 int test4 (v2sf a, v2sf b);
-NOMIPS16 int test5 (v2sf a, v2sf b);
-NOMIPS16 int test6 (v2sf a, v2sf b);
-NOMIPS16 int test7 (v2sf a, v2sf b);
-NOMIPS16 int test8 (v2sf a, v2sf b);
-NOMIPS16 int test9 (v2sf a, v2sf b);
-NOMIPS16 int test10 (v2sf a, v2sf b);
-NOMIPS16 int test11 (v2sf a, v2sf b);
-NOMIPS16 int test12 (v2sf a, v2sf b);
-NOMIPS16 int test13 (v2sf a, v2sf b);
-NOMIPS16 int test14 (v2sf a, v2sf b);
-NOMIPS16 int test15 (v2sf a, v2sf b);
-NOMIPS16 int test16 (v2sf a, v2sf b);
-NOMIPS16 int test17 (v2sf a, v2sf b);
-NOMIPS16 int test18 (v2sf a, v2sf b);
-NOMIPS16 int test19 (v2sf a, v2sf b);
-NOMIPS16 int test20 (v2sf a, v2sf b);
-NOMIPS16 int test21 (v2sf a, v2sf b);
-NOMIPS16 int test22 (v2sf a, v2sf b);
-NOMIPS16 int test23 (v2sf a, v2sf b);
-NOMIPS16 int test24 (v2sf a, v2sf b);
-NOMIPS16 int test25 (v2sf a, v2sf b);
-NOMIPS16 int test26 (v2sf a, v2sf b);
-NOMIPS16 int test27 (v2sf a, v2sf b);
-NOMIPS16 int test28 (v2sf a, v2sf b);
-NOMIPS16 int test29 (v2sf a, v2sf b);
-NOMIPS16 int test30 (v2sf a, v2sf b);
-NOMIPS16 int test31 (v2sf a, v2sf b);
+NOCOMPRESSION int test0 (v2sf a, v2sf b);
+NOCOMPRESSION int test1 (v2sf a, v2sf b);
+NOCOMPRESSION int test2 (v2sf a, v2sf b);
+NOCOMPRESSION int test3 (v2sf a, v2sf b);
+NOCOMPRESSION int test4 (v2sf a, v2sf b);
+NOCOMPRESSION int test5 (v2sf a, v2sf b);
+NOCOMPRESSION int test6 (v2sf a, v2sf b);
+NOCOMPRESSION int test7 (v2sf a, v2sf b);
+NOCOMPRESSION int test8 (v2sf a, v2sf b);
+NOCOMPRESSION int test9 (v2sf a, v2sf b);
+NOCOMPRESSION int test10 (v2sf a, v2sf b);
+NOCOMPRESSION int test11 (v2sf a, v2sf b);
+NOCOMPRESSION int test12 (v2sf a, v2sf b);
+NOCOMPRESSION int test13 (v2sf a, v2sf b);
+NOCOMPRESSION int test14 (v2sf a, v2sf b);
+NOCOMPRESSION int test15 (v2sf a, v2sf b);
+NOCOMPRESSION int test16 (v2sf a, v2sf b);
+NOCOMPRESSION int test17 (v2sf a, v2sf b);
+NOCOMPRESSION int test18 (v2sf a, v2sf b);
+NOCOMPRESSION int test19 (v2sf a, v2sf b);
+NOCOMPRESSION int test20 (v2sf a, v2sf b);
+NOCOMPRESSION int test21 (v2sf a, v2sf b);
+NOCOMPRESSION int test22 (v2sf a, v2sf b);
+NOCOMPRESSION int test23 (v2sf a, v2sf b);
+NOCOMPRESSION int test24 (v2sf a, v2sf b);
+NOCOMPRESSION int test25 (v2sf a, v2sf b);
+NOCOMPRESSION int test26 (v2sf a, v2sf b);
+NOCOMPRESSION int test27 (v2sf a, v2sf b);
+NOCOMPRESSION int test28 (v2sf a, v2sf b);
+NOCOMPRESSION int test29 (v2sf a, v2sf b);
+NOCOMPRESSION int test30 (v2sf a, v2sf b);
+NOCOMPRESSION int test31 (v2sf a, v2sf b);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   v2sf a, b, c, d;
   int i, j;
@@ -393,162 +393,162 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (v2sf a, v2sf b)
+NOCOMPRESSION int test0 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_f_ps (a, b);
 }
 
-NOMIPS16 int test1 (v2sf a, v2sf b)
+NOCOMPRESSION int test1 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_f_ps (a, b);
 }
 
-NOMIPS16 int test2 (v2sf a, v2sf b)
+NOCOMPRESSION int test2 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_un_ps (a, b);
 }
 
-NOMIPS16 int test3 (v2sf a, v2sf b)
+NOCOMPRESSION int test3 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_un_ps (a, b);
 }
 
-NOMIPS16 int test4 (v2sf a, v2sf b)
+NOCOMPRESSION int test4 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_eq_ps (a, b);
 }
 
-NOMIPS16 int test5 (v2sf a, v2sf b)
+NOCOMPRESSION int test5 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_eq_ps (a, b);
 }
 
-NOMIPS16 int test6 (v2sf a, v2sf b)
+NOCOMPRESSION int test6 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ueq_ps (a, b);
 }
 
-NOMIPS16 int test7 (v2sf a, v2sf b)
+NOCOMPRESSION int test7 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ueq_ps (a, b);
 }
 
-NOMIPS16 int test8 (v2sf a, v2sf b)
+NOCOMPRESSION int test8 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_olt_ps (a, b);
 }
 
-NOMIPS16 int test9 (v2sf a, v2sf b)
+NOCOMPRESSION int test9 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_olt_ps (a, b);
 }
 
-NOMIPS16 int test10 (v2sf a, v2sf b)
+NOCOMPRESSION int test10 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ult_ps (a, b);
 }
 
-NOMIPS16 int test11 (v2sf a, v2sf b)
+NOCOMPRESSION int test11 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ult_ps (a, b);
 }
 
-NOMIPS16 int test12 (v2sf a, v2sf b)
+NOCOMPRESSION int test12 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ole_ps (a, b);
 }
 
-NOMIPS16 int test13 (v2sf a, v2sf b)
+NOCOMPRESSION int test13 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ole_ps (a, b);
 }
 
-NOMIPS16 int test14 (v2sf a, v2sf b)
+NOCOMPRESSION int test14 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ule_ps (a, b);
 }
 
-NOMIPS16 int test15 (v2sf a, v2sf b)
+NOCOMPRESSION int test15 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ule_ps (a, b);
 }
 
-NOMIPS16 int test16 (v2sf a, v2sf b)
+NOCOMPRESSION int test16 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_sf_ps (a, b);
 }
 
-NOMIPS16 int test17 (v2sf a, v2sf b)
+NOCOMPRESSION int test17 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_sf_ps (a, b);
 }
 
-NOMIPS16 int test18 (v2sf a, v2sf b)
+NOCOMPRESSION int test18 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ngle_ps (a, b);
 }
 
-NOMIPS16 int test19 (v2sf a, v2sf b)
+NOCOMPRESSION int test19 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ngle_ps (a, b);
 }
 
-NOMIPS16 int test20 (v2sf a, v2sf b)
+NOCOMPRESSION int test20 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_seq_ps (a, b);
 }
 
-NOMIPS16 int test21 (v2sf a, v2sf b)
+NOCOMPRESSION int test21 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_seq_ps (a, b);
 }
 
-NOMIPS16 int test22 (v2sf a, v2sf b)
+NOCOMPRESSION int test22 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ngl_ps (a, b);
 }
 
-NOMIPS16 int test23 (v2sf a, v2sf b)
+NOCOMPRESSION int test23 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ngl_ps (a, b);
 }
 
-NOMIPS16 int test24 (v2sf a, v2sf b)
+NOCOMPRESSION int test24 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_lt_ps (a, b);
 }
 
-NOMIPS16 int test25 (v2sf a, v2sf b)
+NOCOMPRESSION int test25 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_lt_ps (a, b);
 }
 
-NOMIPS16 int test26 (v2sf a, v2sf b)
+NOCOMPRESSION int test26 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_nge_ps (a, b);
 }
 
-NOMIPS16 int test27 (v2sf a, v2sf b)
+NOCOMPRESSION int test27 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_nge_ps (a, b);
 }
 
-NOMIPS16 int test28 (v2sf a, v2sf b)
+NOCOMPRESSION int test28 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_le_ps (a, b);
 }
 
-NOMIPS16 int test29 (v2sf a, v2sf b)
+NOCOMPRESSION int test29 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_le_ps (a, b);
 }
 
-NOMIPS16 int test30 (v2sf a, v2sf b)
+NOCOMPRESSION int test30 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ngt_ps (a, b);
 }
 
-NOMIPS16 int test31 (v2sf a, v2sf b)
+NOCOMPRESSION int test31 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ngt_ps (a, b);
 }
Index: gcc.target/mips/near-far-2.c
===================================================================
--- gcc.target/mips/near-far-2.c	(revision 189440)
+++ gcc.target/mips/near-far-2.c	(working copy)
@@ -16,5 +16,5 @@
 
 /* { dg-final { scan-assembler-not "\tjal\tlong_call_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal\tfar_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal\tnear_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal\tnormal_func\n" } } */
+/* { dg-final { scan-assembler     "\tjals?\tnear_func\n" } } */
+/* { dg-final { scan-assembler     "\tjals?\tnormal_func\n" } } */
Index: gcc.target/mips/branch-10.c
===================================================================
--- gcc.target/mips/branch-10.c	(revision 189440)
+++ gcc.target/mips/branch-10.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (void (*bar) (void), volatile int *x)
 {
   bar ();
Index: gcc.target/mips/mips-3d-3.c
===================================================================
--- gcc.target/mips/mips-3d-3.c	(revision 189440)
+++ gcc.target/mips/mips-3d-3.c	(working copy)
@@ -7,74 +7,74 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int test0 (v2sf a, v2sf b);
-NOMIPS16 int test1 (v2sf a, v2sf b);
-NOMIPS16 int test2 (v2sf a, v2sf b);
-NOMIPS16 int test3 (v2sf a, v2sf b);
-NOMIPS16 int test4 (v2sf a, v2sf b);
-NOMIPS16 int test5 (v2sf a, v2sf b);
-NOMIPS16 int test6 (v2sf a, v2sf b);
-NOMIPS16 int test7 (v2sf a, v2sf b);
-NOMIPS16 int test8 (v2sf a, v2sf b);
-NOMIPS16 int test9 (v2sf a, v2sf b);
-NOMIPS16 int test10 (v2sf a, v2sf b);
-NOMIPS16 int test11 (v2sf a, v2sf b);
-NOMIPS16 int test12 (v2sf a, v2sf b);
-NOMIPS16 int test13 (v2sf a, v2sf b);
-NOMIPS16 int test14 (v2sf a, v2sf b);
-NOMIPS16 int test15 (v2sf a, v2sf b);
-NOMIPS16 int test16 (v2sf a, v2sf b);
-NOMIPS16 int test17 (v2sf a, v2sf b);
-NOMIPS16 int test18 (v2sf a, v2sf b);
-NOMIPS16 int test19 (v2sf a, v2sf b);
-NOMIPS16 int test20 (v2sf a, v2sf b);
-NOMIPS16 int test21 (v2sf a, v2sf b);
-NOMIPS16 int test22 (v2sf a, v2sf b);
-NOMIPS16 int test23 (v2sf a, v2sf b);
-NOMIPS16 int test24 (v2sf a, v2sf b);
-NOMIPS16 int test25 (v2sf a, v2sf b);
-NOMIPS16 int test26 (v2sf a, v2sf b);
-NOMIPS16 int test27 (v2sf a, v2sf b);
-NOMIPS16 int test28 (v2sf a, v2sf b);
-NOMIPS16 int test29 (v2sf a, v2sf b);
-NOMIPS16 int test30 (v2sf a, v2sf b);
-NOMIPS16 int test31 (v2sf a, v2sf b);
-NOMIPS16 int test32 (v2sf a, v2sf b);
-NOMIPS16 int test33 (v2sf a, v2sf b);
-NOMIPS16 int test34 (v2sf a, v2sf b);
-NOMIPS16 int test35 (v2sf a, v2sf b);
-NOMIPS16 int test36 (v2sf a, v2sf b);
-NOMIPS16 int test37 (v2sf a, v2sf b);
-NOMIPS16 int test38 (v2sf a, v2sf b);
-NOMIPS16 int test39 (v2sf a, v2sf b);
-NOMIPS16 int test40 (v2sf a, v2sf b);
-NOMIPS16 int test41 (v2sf a, v2sf b);
-NOMIPS16 int test42 (v2sf a, v2sf b);
-NOMIPS16 int test43 (v2sf a, v2sf b);
-NOMIPS16 int test44 (v2sf a, v2sf b);
-NOMIPS16 int test45 (v2sf a, v2sf b);
-NOMIPS16 int test46 (v2sf a, v2sf b);
-NOMIPS16 int test47 (v2sf a, v2sf b);
-NOMIPS16 int test48 (v2sf a, v2sf b);
-NOMIPS16 int test49 (v2sf a, v2sf b);
-NOMIPS16 int test50 (v2sf a, v2sf b);
-NOMIPS16 int test51 (v2sf a, v2sf b);
-NOMIPS16 int test52 (v2sf a, v2sf b);
-NOMIPS16 int test53 (v2sf a, v2sf b);
-NOMIPS16 int test54 (v2sf a, v2sf b);
-NOMIPS16 int test55 (v2sf a, v2sf b);
-NOMIPS16 int test56 (v2sf a, v2sf b);
-NOMIPS16 int test57 (v2sf a, v2sf b);
-NOMIPS16 int test58 (v2sf a, v2sf b);
-NOMIPS16 int test59 (v2sf a, v2sf b);
-NOMIPS16 int test60 (v2sf a, v2sf b);
-NOMIPS16 int test61 (v2sf a, v2sf b);
-NOMIPS16 int test62 (v2sf a, v2sf b);
-NOMIPS16 int test63 (v2sf a, v2sf b);
+NOCOMPRESSION int test0 (v2sf a, v2sf b);
+NOCOMPRESSION int test1 (v2sf a, v2sf b);
+NOCOMPRESSION int test2 (v2sf a, v2sf b);
+NOCOMPRESSION int test3 (v2sf a, v2sf b);
+NOCOMPRESSION int test4 (v2sf a, v2sf b);
+NOCOMPRESSION int test5 (v2sf a, v2sf b);
+NOCOMPRESSION int test6 (v2sf a, v2sf b);
+NOCOMPRESSION int test7 (v2sf a, v2sf b);
+NOCOMPRESSION int test8 (v2sf a, v2sf b);
+NOCOMPRESSION int test9 (v2sf a, v2sf b);
+NOCOMPRESSION int test10 (v2sf a, v2sf b);
+NOCOMPRESSION int test11 (v2sf a, v2sf b);
+NOCOMPRESSION int test12 (v2sf a, v2sf b);
+NOCOMPRESSION int test13 (v2sf a, v2sf b);
+NOCOMPRESSION int test14 (v2sf a, v2sf b);
+NOCOMPRESSION int test15 (v2sf a, v2sf b);
+NOCOMPRESSION int test16 (v2sf a, v2sf b);
+NOCOMPRESSION int test17 (v2sf a, v2sf b);
+NOCOMPRESSION int test18 (v2sf a, v2sf b);
+NOCOMPRESSION int test19 (v2sf a, v2sf b);
+NOCOMPRESSION int test20 (v2sf a, v2sf b);
+NOCOMPRESSION int test21 (v2sf a, v2sf b);
+NOCOMPRESSION int test22 (v2sf a, v2sf b);
+NOCOMPRESSION int test23 (v2sf a, v2sf b);
+NOCOMPRESSION int test24 (v2sf a, v2sf b);
+NOCOMPRESSION int test25 (v2sf a, v2sf b);
+NOCOMPRESSION int test26 (v2sf a, v2sf b);
+NOCOMPRESSION int test27 (v2sf a, v2sf b);
+NOCOMPRESSION int test28 (v2sf a, v2sf b);
+NOCOMPRESSION int test29 (v2sf a, v2sf b);
+NOCOMPRESSION int test30 (v2sf a, v2sf b);
+NOCOMPRESSION int test31 (v2sf a, v2sf b);
+NOCOMPRESSION int test32 (v2sf a, v2sf b);
+NOCOMPRESSION int test33 (v2sf a, v2sf b);
+NOCOMPRESSION int test34 (v2sf a, v2sf b);
+NOCOMPRESSION int test35 (v2sf a, v2sf b);
+NOCOMPRESSION int test36 (v2sf a, v2sf b);
+NOCOMPRESSION int test37 (v2sf a, v2sf b);
+NOCOMPRESSION int test38 (v2sf a, v2sf b);
+NOCOMPRESSION int test39 (v2sf a, v2sf b);
+NOCOMPRESSION int test40 (v2sf a, v2sf b);
+NOCOMPRESSION int test41 (v2sf a, v2sf b);
+NOCOMPRESSION int test42 (v2sf a, v2sf b);
+NOCOMPRESSION int test43 (v2sf a, v2sf b);
+NOCOMPRESSION int test44 (v2sf a, v2sf b);
+NOCOMPRESSION int test45 (v2sf a, v2sf b);
+NOCOMPRESSION int test46 (v2sf a, v2sf b);
+NOCOMPRESSION int test47 (v2sf a, v2sf b);
+NOCOMPRESSION int test48 (v2sf a, v2sf b);
+NOCOMPRESSION int test49 (v2sf a, v2sf b);
+NOCOMPRESSION int test50 (v2sf a, v2sf b);
+NOCOMPRESSION int test51 (v2sf a, v2sf b);
+NOCOMPRESSION int test52 (v2sf a, v2sf b);
+NOCOMPRESSION int test53 (v2sf a, v2sf b);
+NOCOMPRESSION int test54 (v2sf a, v2sf b);
+NOCOMPRESSION int test55 (v2sf a, v2sf b);
+NOCOMPRESSION int test56 (v2sf a, v2sf b);
+NOCOMPRESSION int test57 (v2sf a, v2sf b);
+NOCOMPRESSION int test58 (v2sf a, v2sf b);
+NOCOMPRESSION int test59 (v2sf a, v2sf b);
+NOCOMPRESSION int test60 (v2sf a, v2sf b);
+NOCOMPRESSION int test61 (v2sf a, v2sf b);
+NOCOMPRESSION int test62 (v2sf a, v2sf b);
+NOCOMPRESSION int test63 (v2sf a, v2sf b);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   int little_endian;
   v2sf a, b, c, d;
@@ -774,322 +774,322 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (v2sf a, v2sf b)
+NOCOMPRESSION int test0 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_f_ps (a, b);
 }
 
-NOMIPS16 int test1 (v2sf a, v2sf b)
+NOCOMPRESSION int test1 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_f_ps (a, b);
 }
 
-NOMIPS16 int test2 (v2sf a, v2sf b)
+NOCOMPRESSION int test2 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_f_ps (a, b);
 }
 
-NOMIPS16 int test3 (v2sf a, v2sf b)
+NOCOMPRESSION int test3 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_f_ps (a, b);
 }
 
-NOMIPS16 int test4 (v2sf a, v2sf b)
+NOCOMPRESSION int test4 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_un_ps (a, b);
 }
 
-NOMIPS16 int test5 (v2sf a, v2sf b)
+NOCOMPRESSION int test5 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_un_ps (a, b);
 }
 
-NOMIPS16 int test6 (v2sf a, v2sf b)
+NOCOMPRESSION int test6 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_un_ps (a, b);
 }
 
-NOMIPS16 int test7 (v2sf a, v2sf b)
+NOCOMPRESSION int test7 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_un_ps (a, b);
 }
 
-NOMIPS16 int test8 (v2sf a, v2sf b)
+NOCOMPRESSION int test8 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_eq_ps (a, b);
 }
 
-NOMIPS16 int test9 (v2sf a, v2sf b)
+NOCOMPRESSION int test9 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_eq_ps (a, b);
 }
 
-NOMIPS16 int test10 (v2sf a, v2sf b)
+NOCOMPRESSION int test10 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_eq_ps (a, b);
 }
 
-NOMIPS16 int test11 (v2sf a, v2sf b)
+NOCOMPRESSION int test11 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_eq_ps (a, b);
 }
 
-NOMIPS16 int test12 (v2sf a, v2sf b)
+NOCOMPRESSION int test12 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ueq_ps (a, b);
 }
 
-NOMIPS16 int test13 (v2sf a, v2sf b)
+NOCOMPRESSION int test13 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ueq_ps (a, b);
 }
 
-NOMIPS16 int test14 (v2sf a, v2sf b)
+NOCOMPRESSION int test14 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ueq_ps (a, b);
 }
 
-NOMIPS16 int test15 (v2sf a, v2sf b)
+NOCOMPRESSION int test15 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ueq_ps (a, b);
 }
 
-NOMIPS16 int test16 (v2sf a, v2sf b)
+NOCOMPRESSION int test16 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_olt_ps (a, b);
 }
 
-NOMIPS16 int test17 (v2sf a, v2sf b)
+NOCOMPRESSION int test17 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_olt_ps (a, b);
 }
 
-NOMIPS16 int test18 (v2sf a, v2sf b)
+NOCOMPRESSION int test18 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_olt_ps (a, b);
 }
 
-NOMIPS16 int test19 (v2sf a, v2sf b)
+NOCOMPRESSION int test19 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_olt_ps (a, b);
 }
 
-NOMIPS16 int test20 (v2sf a, v2sf b)
+NOCOMPRESSION int test20 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ult_ps (a, b);
 }
 
-NOMIPS16 int test21 (v2sf a, v2sf b)
+NOCOMPRESSION int test21 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ult_ps (a, b);
 }
 
-NOMIPS16 int test22 (v2sf a, v2sf b)
+NOCOMPRESSION int test22 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ult_ps (a, b);
 }
 
-NOMIPS16 int test23 (v2sf a, v2sf b)
+NOCOMPRESSION int test23 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ult_ps (a, b);
 }
 
-NOMIPS16 int test24 (v2sf a, v2sf b)
+NOCOMPRESSION int test24 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ole_ps (a, b);
 }
 
-NOMIPS16 int test25 (v2sf a, v2sf b)
+NOCOMPRESSION int test25 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ole_ps (a, b);
 }
 
-NOMIPS16 int test26 (v2sf a, v2sf b)
+NOCOMPRESSION int test26 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ole_ps (a, b);
 }
 
-NOMIPS16 int test27 (v2sf a, v2sf b)
+NOCOMPRESSION int test27 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ole_ps (a, b);
 }
 
-NOMIPS16 int test28 (v2sf a, v2sf b)
+NOCOMPRESSION int test28 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ule_ps (a, b);
 }
 
-NOMIPS16 int test29 (v2sf a, v2sf b)
+NOCOMPRESSION int test29 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ule_ps (a, b);
 }
 
-NOMIPS16 int test30 (v2sf a, v2sf b)
+NOCOMPRESSION int test30 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ule_ps (a, b);
 }
 
-NOMIPS16 int test31 (v2sf a, v2sf b)
+NOCOMPRESSION int test31 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ule_ps (a, b);
 }
 
-NOMIPS16 int test32 (v2sf a, v2sf b)
+NOCOMPRESSION int test32 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_sf_ps (a, b);
 }
 
-NOMIPS16 int test33 (v2sf a, v2sf b)
+NOCOMPRESSION int test33 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_sf_ps (a, b);
 }
 
-NOMIPS16 int test34 (v2sf a, v2sf b)
+NOCOMPRESSION int test34 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_sf_ps (a, b);
 }
 
-NOMIPS16 int test35 (v2sf a, v2sf b)
+NOCOMPRESSION int test35 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_sf_ps (a, b);
 }
 
-NOMIPS16 int test36 (v2sf a, v2sf b)
+NOCOMPRESSION int test36 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ngle_ps (a, b);
 }
 
-NOMIPS16 int test37 (v2sf a, v2sf b)
+NOCOMPRESSION int test37 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ngle_ps (a, b);
 }
 
-NOMIPS16 int test38 (v2sf a, v2sf b)
+NOCOMPRESSION int test38 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ngle_ps (a, b);
 }
 
-NOMIPS16 int test39 (v2sf a, v2sf b)
+NOCOMPRESSION int test39 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ngle_ps (a, b);
 }
 
-NOMIPS16 int test40 (v2sf a, v2sf b)
+NOCOMPRESSION int test40 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_seq_ps (a, b);
 }
 
-NOMIPS16 int test41 (v2sf a, v2sf b)
+NOCOMPRESSION int test41 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_seq_ps (a, b);
 }
 
-NOMIPS16 int test42 (v2sf a, v2sf b)
+NOCOMPRESSION int test42 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_seq_ps (a, b);
 }
 
-NOMIPS16 int test43 (v2sf a, v2sf b)
+NOCOMPRESSION int test43 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_seq_ps (a, b);
 }
 
-NOMIPS16 int test44 (v2sf a, v2sf b)
+NOCOMPRESSION int test44 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ngl_ps (a, b);
 }
 
-NOMIPS16 int test45 (v2sf a, v2sf b)
+NOCOMPRESSION int test45 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ngl_ps (a, b);
 }
 
-NOMIPS16 int test46 (v2sf a, v2sf b)
+NOCOMPRESSION int test46 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ngl_ps (a, b);
 }
 
-NOMIPS16 int test47 (v2sf a, v2sf b)
+NOCOMPRESSION int test47 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ngl_ps (a, b);
 }
 
-NOMIPS16 int test48 (v2sf a, v2sf b)
+NOCOMPRESSION int test48 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_lt_ps (a, b);
 }
 
-NOMIPS16 int test49 (v2sf a, v2sf b)
+NOCOMPRESSION int test49 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_lt_ps (a, b);
 }
 
-NOMIPS16 int test50 (v2sf a, v2sf b)
+NOCOMPRESSION int test50 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_lt_ps (a, b);
 }
 
-NOMIPS16 int test51 (v2sf a, v2sf b)
+NOCOMPRESSION int test51 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_lt_ps (a, b);
 }
 
-NOMIPS16 int test52 (v2sf a, v2sf b)
+NOCOMPRESSION int test52 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_nge_ps (a, b);
 }
 
-NOMIPS16 int test53 (v2sf a, v2sf b)
+NOCOMPRESSION int test53 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_nge_ps (a, b);
 }
 
-NOMIPS16 int test54 (v2sf a, v2sf b)
+NOCOMPRESSION int test54 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_nge_ps (a, b);
 }
 
-NOMIPS16 int test55 (v2sf a, v2sf b)
+NOCOMPRESSION int test55 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_nge_ps (a, b);
 }
 
-NOMIPS16 int test56 (v2sf a, v2sf b)
+NOCOMPRESSION int test56 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_le_ps (a, b);
 }
 
-NOMIPS16 int test57 (v2sf a, v2sf b)
+NOCOMPRESSION int test57 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_le_ps (a, b);
 }
 
-NOMIPS16 int test58 (v2sf a, v2sf b)
+NOCOMPRESSION int test58 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_le_ps (a, b);
 }
 
-NOMIPS16 int test59 (v2sf a, v2sf b)
+NOCOMPRESSION int test59 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_le_ps (a, b);
 }
 
-NOMIPS16 int test60 (v2sf a, v2sf b)
+NOCOMPRESSION int test60 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ngt_ps (a, b);
 }
 
-NOMIPS16 int test61 (v2sf a, v2sf b)
+NOCOMPRESSION int test61 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ngt_ps (a, b);
 }
 
-NOMIPS16 int test62 (v2sf a, v2sf b)
+NOCOMPRESSION int test62 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ngt_ps (a, b);
 }
 
-NOMIPS16 int test63 (v2sf a, v2sf b)
+NOCOMPRESSION int test63 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ngt_ps (a, b);
 }
Index: gcc.target/mips/branch-8.c
===================================================================
--- gcc.target/mips/branch-8.c	(revision 189440)
+++ gcc.target/mips/branch-8.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (void (*bar) (void), volatile int *x)
 {
   bar ();
Index: gcc.target/mips/mips-3d-4.c
===================================================================
--- gcc.target/mips/mips-3d-4.c	(revision 189440)
+++ gcc.target/mips/mips-3d-4.c	(working copy)
@@ -7,42 +7,42 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int test0 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test1 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test2 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test3 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test4 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test5 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test6 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test7 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test8 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test9 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test10 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test11 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test12 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test13 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test14 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test15 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test16 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test17 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test18 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test19 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test20 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test21 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test22 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test23 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test24 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test25 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test26 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test27 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test28 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test29 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test30 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test31 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test0 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test1 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test2 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test3 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test4 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test5 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test6 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test7 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test8 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test9 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test10 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test11 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test12 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test13 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test14 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test15 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test16 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test17 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test18 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test19 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test20 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test21 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test22 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test23 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test24 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test25 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test26 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test27 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test28 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test29 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test30 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test31 (v2sf a, v2sf b, v2sf c, v2sf d);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   v2sf a, b, c, d;
   int i, j;
@@ -429,162 +429,162 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test0 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_f_4s (a, b, c, d);
 }
 
-NOMIPS16 int test1 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test1 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_f_4s (a, b, c, d);
 }
 
-NOMIPS16 int test2 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test2 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_un_4s (a, b, c, d);
 }
 
-NOMIPS16 int test3 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test3 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_un_4s (a, b, c, d);
 }
 
-NOMIPS16 int test4 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test4 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_eq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test5 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test5 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_eq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test6 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test6 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ueq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test7 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test7 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ueq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test8 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test8 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_olt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test9 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test9 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_olt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test10 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test10 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ult_4s (a, b, c, d);
 }
 
-NOMIPS16 int test11 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test11 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ult_4s (a, b, c, d);
 }
 
-NOMIPS16 int test12 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test12 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ole_4s (a, b, c, d);
 }
 
-NOMIPS16 int test13 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test13 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ole_4s (a, b, c, d);
 }
 
-NOMIPS16 int test14 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test14 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ule_4s (a, b, c, d);
 }
 
-NOMIPS16 int test15 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test15 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ule_4s (a, b, c, d);
 }
 
-NOMIPS16 int test16 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test16 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_sf_4s (a, b, c, d);
 }
 
-NOMIPS16 int test17 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test17 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_sf_4s (a, b, c, d);
 }
 
-NOMIPS16 int test18 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test18 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ngle_4s (a, b, c, d);
 }
 
-NOMIPS16 int test19 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test19 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ngle_4s (a, b, c, d);
 }
 
-NOMIPS16 int test20 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test20 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_seq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test21 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test21 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_seq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test22 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test22 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ngl_4s (a, b, c, d);
 }
 
-NOMIPS16 int test23 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test23 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ngl_4s (a, b, c, d);
 }
 
-NOMIPS16 int test24 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test24 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_lt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test25 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test25 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_lt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test26 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test26 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_nge_4s (a, b, c, d);
 }
 
-NOMIPS16 int test27 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test27 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_nge_4s (a, b, c, d);
 }
 
-NOMIPS16 int test28 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test28 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_le_4s (a, b, c, d);
 }
 
-NOMIPS16 int test29 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test29 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_le_4s (a, b, c, d);
 }
 
-NOMIPS16 int test30 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test30 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ngt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test31 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test31 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ngt_4s (a, b, c, d);
 }
Index: gcc.target/mips/branch-12.c
===================================================================
--- gcc.target/mips/branch-12.c	(revision 189440)
+++ gcc.target/mips/branch-12.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (void (*bar) (void), volatile int *x)
 {
   bar ();
Index: gcc.target/mips/mips-3d-5.c
===================================================================
--- gcc.target/mips/mips-3d-5.c	(revision 189440)
+++ gcc.target/mips/mips-3d-5.c	(working copy)
@@ -7,42 +7,42 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int test0 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test1 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test2 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test3 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test4 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test5 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test6 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test7 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test8 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test9 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test10 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test11 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test12 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test13 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test14 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test15 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test16 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test17 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test18 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test19 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test20 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test21 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test22 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test23 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test24 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test25 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test26 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test27 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test28 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test29 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test30 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test31 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test0 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test1 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test2 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test3 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test4 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test5 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test6 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test7 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test8 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test9 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test10 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test11 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test12 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test13 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test14 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test15 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test16 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test17 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test18 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test19 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test20 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test21 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test22 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test23 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test24 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test25 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test26 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test27 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test28 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test29 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test30 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test31 (v2sf a, v2sf b, v2sf c, v2sf d);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   v2sf a, b, c, d;
   int i, j;
@@ -429,162 +429,162 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test0 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_f_4s (a, b, c, d);
 }
 
-NOMIPS16 int test1 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test1 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_f_4s (a, b, c, d);
 }
 
-NOMIPS16 int test2 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test2 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_un_4s (a, b, c, d);
 }
 
-NOMIPS16 int test3 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test3 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_un_4s (a, b, c, d);
 }
 
-NOMIPS16 int test4 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test4 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_eq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test5 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test5 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_eq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test6 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test6 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ueq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test7 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test7 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ueq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test8 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test8 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_olt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test9 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test9 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_olt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test10 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test10 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ult_4s (a, b, c, d);
 }
 
-NOMIPS16 int test11 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test11 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ult_4s (a, b, c, d);
 }
 
-NOMIPS16 int test12 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test12 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ole_4s (a, b, c, d);
 }
 
-NOMIPS16 int test13 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test13 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ole_4s (a, b, c, d);
 }
 
-NOMIPS16 int test14 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test14 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ule_4s (a, b, c, d);
 }
 
-NOMIPS16 int test15 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test15 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ule_4s (a, b, c, d);
 }
 
-NOMIPS16 int test16 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test16 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_sf_4s (a, b, c, d);
 }
 
-NOMIPS16 int test17 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test17 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_sf_4s (a, b, c, d);
 }
 
-NOMIPS16 int test18 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test18 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ngle_4s (a, b, c, d);
 }
 
-NOMIPS16 int test19 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test19 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ngle_4s (a, b, c, d);
 }
 
-NOMIPS16 int test20 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test20 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_seq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test21 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test21 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_seq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test22 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test22 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ngl_4s (a, b, c, d);
 }
 
-NOMIPS16 int test23 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test23 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ngl_4s (a, b, c, d);
 }
 
-NOMIPS16 int test24 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test24 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_lt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test25 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test25 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_lt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test26 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test26 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_nge_4s (a, b, c, d);
 }
 
-NOMIPS16 int test27 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test27 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_nge_4s (a, b, c, d);
 }
 
-NOMIPS16 int test28 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test28 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_le_4s (a, b, c, d);
 }
 
-NOMIPS16 int test29 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test29 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_le_4s (a, b, c, d);
 }
 
-NOMIPS16 int test30 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test30 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ngt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test31 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test31 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ngt_4s (a, b, c, d);
 }
Index: gcc.target/mips/branch-2.c
===================================================================
--- gcc.target/mips/branch-2.c	(revision 189440)
+++ gcc.target/mips/branch-2.c	(working copy)
@@ -5,7 +5,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (volatile int *x)
 {
   if (__builtin_expect (*x == 0, 1))
Index: gcc.c-torture/execute/ieee/ieee.exp
===================================================================
--- gcc.c-torture/execute/ieee/ieee.exp	(revision 189440)
+++ gcc.c-torture/execute/ieee/ieee.exp	(working copy)
@@ -54,6 +54,9 @@
      || [istarget "sh*-*-*"] } then {
   lappend additional_flags "-mieee"
 }
+if [istarget "mips*-sde-*"] then {
+  lappend additional_flags "-Wl,--defsym=__cs3_mips_float_type=2" "-lcs3-mips-cp1" "-lcs3-mips-fpemu"
+}
 
 # load support procs
 load_lib c-torture.exp

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2012-07-19 18:51 ` FW: [PATCH] [MIPS] microMIPS gcc support Moore, Catherine
@ 2012-07-20  0:46   ` Richard Sandiford
  2013-01-22 20:23     ` Moore, Catherine
  2013-03-04 19:43     ` Moore, Catherine
  0 siblings, 2 replies; 41+ messages in thread
From: Richard Sandiford @ 2012-07-20  0:46 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> Forgot to copy the list ...

Same with my reply...

> Here is the updated microMIPS patch.  It's been a very long time (two
> years!) since I posted the original.  Please let me know what we're
> going to need to do to get this committed.

This is looking better.  At least that huge if statement in
mips_adjust_insn_length (IIRC) is gone :-)

-------------------------------------------------------------------------
 @itemx -mno-interlink-mips16
 @opindex minterlink-mips16
 @opindex mno-interlink-mips16
-Require (do not require) that non-MIPS16 code be link-compatible with
-MIPS16 code.
+Require (do not require) that non-MIPS16/non-microMIPS code be link-compatible
+with MIPS16/microMIPS code.
 
-For example, non-MIPS16 code cannot jump directly to MIPS16 code;
+For example, non-MIPS16/non-microMIPS code cannot jump directly to
+MIPS16/microMIPS code;
 it must either use a call or an indirect jump.  @option{-minterlink-mips16}
 therefore disables direct jumps unless GCC knows that the target of the
-jump is not MIPS16.
+jump is not MIPS16/non microMIPS.
-------------------------------------------------------------------------

This doesn't read very well.  Let's add a -minterlink-compressed
option and treat -mno-interlink-mips16 as an alias of it.  So:

-------------------------------------------------------------------------
@item -minterlink-compressed
@itemx -mno-interlink-compressed
@opindex minterlink-compressed
@opindex mno-interlink-compressed
Require (do not require) that code using the standard (uncompressed)
MIPS ISA be link-compatible with MIPS16 and microMIPS code.

For example, non-MIPS16 code cannot jump directly to MIPS16 code;
it must either use a call or an indirect jump.  The same applies to
non-microMIPS jumps to microMIPS code.  @option{-minterlink-compressed}
therefore disables direct jumps unless GCC knows that the target of the
jump is not compressed.

@item -minterlink-mips16
@itemx -mno-interlink-mips16
@opindex minterlink-mips16
@opindex mno-interlink-mips16
Aliases of @option{-minterlink-compressed} and
@option{-mno-interlink-compressed}.  These options predate the mipsMIPS
ASE and are retained for backwards compatiblity.
-------------------------------------------------------------------------

Let's also make TARGET_INTERLINK_COMPRESSED the internal name.

-------------------------------------------------------------------------
+@item -mmicromips
+@itemx -mno-micromips
+@opindex mmicromips
+@opindex mno-mmicromips
+Generate (do not generate) microMIPS code.  If GCC is targetting a
+MIPS32 or MIPS64 architecture, it will make use of the microMIPS ASE@.
-------------------------------------------------------------------------

Looks like excess cut-&-paste from the MIPS16 version.  The point of the
MIPS16 documentation is to distinguish between the original MIPS16 "ASE"
and MIPS16e.  There's no such distinction here.

-------------------------------------------------------------------------
+@item -mjals
+@itemx -mno-jals
+@opindex mjals
+@opindex mno-jals
+Generate (do not generate) the @code{jals} instruction for microMIPS
+by recognizing that the branch delay slot instruction can be 16 bits.
+This implies that the funciton call cannot switch the current mode
+during the linking stage, because we don't have the @code{jalxs}
+instruction that supports 16-bit branch delay slot instructions.
-------------------------------------------------------------------------

typo: function

The assumption we're making seems to be that calls from microMIPS code
cannot go to non-microMIPS code.  If so, let's make that the option instead.
The above is too low-level.

With analogy to -minterlink-compressed, the option could be
-minterlink-uncompressed/-mno-interlink-uncompressed, with the
default being -minterlink-uncompressed.

-------------------------------------------------------------------------
+@item YC
+For MIPS, it is the same as the constraint @code{R}.  For microMIPS,
+it matches an address within a 12-bit offset that can be used for
+microMIPS @code{ll}, @code{sc}, etc.
+
+@item YD
+For MIPS, it is the same as the constraint @code{p}  For microMIPS,
+it matches a 12-bit offsest address.
+
+@item YE
+A singler register memory operand.
-------------------------------------------------------------------------

"For MIPS" is a bit vague (it actually applies to MIPS16 too).
So how about:

-------------------------------------------------------------------------
@item YC
when compiling microMIPS code, this constraint matches a memory operand
whose address is formed from a base register and a 12-bit offset.
These operands can be used for microMIPS instructions such as @code{ll}
and @code{sc}.  When not compiling for microMIPS code, @code{YC} is
equivalent to @code{R}.

@item YD
when compiling microMIPS code, this constraint matches an address
operand that is formed from a base register and a 12-bit offset.
These operands can be used for microMIPS instructions such as @code{prefetch}.
When not compiling for microMIPS code, @code{YC} is equivalent to @code{p}.
-------------------------------------------------------------------------

No need for "YE": we have "ZR" now.  I'd like to make the other constraints
"Z" rather than "Y" too -- ZC and ZD -- since "Y" is really for constants.

-------------------------------------------------------------------------
+(define_insn "*store_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "memory_operand")
+	     (match_operand:SI 2 "register_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (true, operands[0])"
+  {
+    return umips_output_save_restore (true, operands[0]);
+  }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
-------------------------------------------------------------------------

Nitlet: local style is to use "{ return ...; }" for single-line statements
and column-0 placement of "{" and "}" for multi-line ones.  Same for
rest of file.

-------------------------------------------------------------------------
+; For lwp
+(define_peephole2
+  [(set (match_operand:SI 0 "umips_lwp_register" "")
+        (match_operand:SI 1 "non_volatile_mem_operand" ""))
+   (set (match_operand:SI 2 "umips_lwp_register" "")
+        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+  "TARGET_MICROMIPS
+   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
+	&& umips_load_store_pair_p (true, false, operands[0],
+				    operands[1], operands[3]))
+       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
+	   && umips_load_store_pair_p (true, true, operands[2],
+				       operands[3], operands[1])))"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
-------------------------------------------------------------------------

Please split out this:

   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
	&& umips_load_store_pair_p (true, false, operands[0],
				    operands[1], operands[3]))
       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
	   && umips_load_store_pair_p (true, true, operands[2],
				       operands[3], operands[1])))

into a function:

bool
umips_load_store_pair_p (bool load_p, rtx reg1, rtx reg2, rtx mem1, rtx mem2)

with the current umips_load_store_pair_p being a subroutine
(umips_load_store_pair_p_1).

-------------------------------------------------------------------------
+(define_insn "*lwp"
+  [(parallel [(set (match_operand:SI 0 "umips_lwp_register")
+		   (match_operand:SI 1 "memory_operand"))
+	      (set (match_operand:SI 2 "umips_lwp_register")
+		   (match_operand:SI 3 "memory_operand"))])]
+
+  "TARGET_MICROMIPS
+   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
+	&& umips_load_store_pair_p (true, false, operands[0],
+				    operands[1], operands[3]))
+       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
+	   && umips_load_store_pair_p (true, true, operands[2],
+				       operands[3], operands[1])))"
+  {
+    if (REGNO (operands[0]) + 1 == REGNO (operands[2]))
+      return umips_output_load_store_pair (true, operands[0], operands[1]);
+    else
+      return umips_output_load_store_pair (true, operands[2], operands[3]);
+  }
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
-------------------------------------------------------------------------

Same with the output:

void
umips_output_load_store_pair (bool load_p, rtx reg1, rtx reg2,
			      rtx mem1, rtx mem2)

Why do only the stores require non_volatile_mem_operand?  It looks like
you could be reordering loads from volatile memory otherwise.

-------------------------------------------------------------------------
+; For jraddiusp
+(define_insn "mips_jraddiusp"
+  [(parallel [(return)
+              (use (reg:SI 31))
+	      (set (reg:SI 29)
+		   (plus:SI (reg:SI 29)
+			    (match_operand 0 "const_int_operand")))])]
+  "TARGET_MICROMIPS"
+  "jraddiusp\t%0"
+  [(set_attr "type" "trap")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
-------------------------------------------------------------------------

Redundant comment.

-------------------------------------------------------------------------
+; For movep
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+        (match_operand:SI 1 "movep_si_operand" ""))
+   (set (match_operand:SI 2 "register_operand" "")
+        (match_operand:SI 3 "movep_si_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SI 0 "register_operand" "")
+        (match_operand:SI 1 "movep_si_operand" ""))
+   (set (match_operand:SF 2 "register_operand" "")
+        (match_operand:SF 3 "const_0_sf_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SF 0 "register_operand" "")
+        (match_operand:SF 1 "const_0_sf_operand" ""))
+   (set (match_operand:SI 2 "register_operand" "")
+        (match_operand:SI 3 "movep_si_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_peephole2
+  [(set (match_operand:SF 0 "register_operand" "")
+        (match_operand:SF 1 "const_0_sf_operand" ""))
+   (set (match_operand:SF 2 "register_operand" "")
+        (match_operand:SF 3 "const_0_sf_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+		   (match_operand:MOVEP1 1 "movep_<MOVEP1:mode>_operand"))
+	      (set (match_operand:MOVEP2 2 "register_operand")
+		   (match_operand:MOVEP2 3 "movep_<MOVEP2:mode>_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+{
+  if (REGNO (operands[0]) < REGNO (operands[2]))
+    return "movep\t%0,%2,%z1,%z3";
+  else
+    return "movep\t%2,%0,%z3,%z1";
+}
+  [(set_attr "type" "move")
+   (set_attr "mode" "<MODE>")
+   (set_attr "can_delay" "no")])
-------------------------------------------------------------------------

Seems to be a mismatch between the peepholes (which only accept 0.0f
for SFmode) and the insn (which allows registers too).  Can't you
use MOVEP1 and MOVEP2 for the peepholes too?

-------------------------------------------------------------------------
 (define_memory_constraint "R"
   "An address that can be used in a non-macro load or store."
   (and (match_code "mem")
-       (match_test "mips_address_insns (XEXP (op, 0), mode, false) == 1")))
+       (match_test "mips_address_insns (XEXP (op, 0), mode, false)")))
-------------------------------------------------------------------------

No, this defeats the purpose of "R", which is supposed to disallow
address that require assembly macros.

-------------------------------------------------------------------------
+(define_memory_constraint "YC"
+  "For MIPS, it is the same as the constraint R.  For microMIPS, it matches
+   an address within a 12-bit offset that can be used in ll, sc, etc."
+  (and (match_code "mem")
+       (ior (and (match_test "TARGET_MICROMIPS")
+		 (match_test "umips_address_insns (XEXP (op, 0), mode, false)"))
+	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "YD"
+  "@internal
+   For MIPS, it is the same as the constraint p.  For microMIPS, it matches
+   a 12-bit offset address."
+   (ior (and (match_test "TARGET_MICROMIPS")
+	     (match_test "umips_address_insns (op, mode, false)"))
+	(match_test "mips_address_insns (op, mode, false)")))
-------------------------------------------------------------------------

Is YD internal or not?  We should remove it from the docs if so,
otherwise the @internal is wrong.

Please keep the doc strings exactly the same as the .texi version
(including @ mark-up).  I think the idea was that at some glorious
time in the future, we'd be able to auto-generate the .texi parts from
the .md doc strings.

-------------------------------------------------------------------------
+(define_predicate "gpr_operand"
+  (and (match_code "reg")
+       (match_test "GP_REG_P (REGNO (op))")))
-------------------------------------------------------------------------

This is d_operand.

-------------------------------------------------------------------------
+(define_predicate "umips_register"
+  (and (match_code "reg")
+       (match_test "M16_REG_P (REGNO (op))")))
-------------------------------------------------------------------------

I think I'd prefer to call the predicate m16_register too, for consistency.

-------------------------------------------------------------------------
+(define_predicate "umips_andi16_operand"
+  (and (match_code "const")
+       (match_test "UMIPS_ANDI16_IMM (INTVAL (op))")))
-------------------------------------------------------------------------

Looks like this should be "const_int" instead.  Same for the other
constants.  It seems on face value like some parts of the patch
weren't exercised because of this.

-------------------------------------------------------------------------
+(define_predicate "umips_add_uimm5"
+  (and (match_code "const")
+       (match_test "IN_RANGE (INTVAL (op), -8, 7)")))
-------------------------------------------------------------------------

Looks like a signed rather than unsigned immediate.  Should this be
"umips_add_imm5" instead?

-------------------------------------------------------------------------
+(define_predicate "umips_addiur2_imm3"
+  (and (match_code "const")
+       (ior (match_test "INTVAL(op) == 1")
+       (ior (match_test "INTVAL(op) == 4")
+       (ior (match_test "INTVAL(op) == 8")
+       (ior (match_test "INTVAL(op) == 12")
+       (ior (match_test "INTVAL(op) == 16")
+       (ior (match_test "INTVAL(op) == 20")
+       (ior (match_test "INTVAL(op) == 24")
+	    (match_test "INTVAL(op) == -1"))))))))))
-------------------------------------------------------------------------

(ior ...) can take any number of operands these days, so no need for
all those ")"s.  Space after INTVAL.

-------------------------------------------------------------------------
+(define_predicate "umips_lw16_memref"
+  (and (match_code "plus")
+       (match_operand 0 "umips_register" ""))
+{
+  rtx op2 = XEXP (op, 1);
+
+  return (GET_CODE (op2) == CONST_INT
+          && ((INTVAL (op2) & 3) == 0)
+	  && (IN_RANGE (INTVAL (op2), 0, 60)));
+})
-------------------------------------------------------------------------

This tests an address, whereas it sounds from the name (and looks from
the later code) like it's supposed to be testing a (mem ...) instead.
Also:

 (and (match_code "plus")
      (match_operand 0 "umips_register" ""))

tests for something that is both a PLUS and a REG, which is never true.
((match_operand X ...) doesn't test XEXP (..., X).)

-------------------------------------------------------------------------
+(define_predicate "const_0_si_operand"
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "op == CONST0_RTX (SImode)")))
+
+(define_predicate "const_0_sf_operand"
+  (and (match_code "const_int,const_double,const_vector")
+       (match_test "op == CONST0_RTX (SFmode)")))
-------------------------------------------------------------------------

Should be redundant with const_0_operand.  Modes should be checked
at the match_operand level where important.

-------------------------------------------------------------------------
+(define_predicate "movep_si_operand"
+  (ior (and (match_code "const_int,const_double,const_vector")
+	    (match_test "op == CONST0_RTX (SImode)"))
+       (and (match_code "reg")
+	    (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
+		 (match_test ("IN_RANGE (REGNO (op), 16, 20)"))))))
+
+(define_predicate "movep_sf_operand"
+  (ior (and (match_code "const_int, const_double, const_vector")
+	    (match_test "op == CONST0_RTX (SFmode)"))
+       (and (match_code "reg")
+	    (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
+		 (match_test ("IN_RANGE (REGNO (op), 16, 20)"))))))
-------------------------------------------------------------------------

These two should be combined:

-------------------------------------------------------------------------
(define_predicate "movep_register"
  (and (match_code "reg")
       (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))

(define_predicate "movep_operand"
  (ior (match_operand 0 "const_0_operand")
       (match_operand 0 "movep_register")))
-------------------------------------------------------------------------

-------------------------------------------------------------------------
+(define_predicate "umips_lwp_register"
+  (and (match_code "reg")
+       (match_test "REGNO (op) <= GP_REG_LAST")))
-------------------------------------------------------------------------

Reundant with d_operand/gpr_operand?

-------------------------------------------------------------------------
+;; Return 1 if the operand is in non-volatile memory.  Note that during the
+;; RTL generation phase, memory_operand does not return TRUE for volatile
+;; memory references.  So this function allows us to recognize volatile
+;; references where it's safe.
+(define_predicate "non_volatile_mem_operand"
+  (not (and (and (match_code "mem")
+          (match_test "MEM_VOLATILE_P (op)"))
+       (if_then_else (match_test "reload_completed")
+         (match_operand 0 "memory_operand")
+         (if_then_else (match_test "reload_in_progress")
+         (match_test "strict_memory_address_p (mode, XEXP (op, 0))")
+         (match_test "memory_address_p (mode, XEXP (op, 0))"))))))
-------------------------------------------------------------------------

This looks wrong: the whole thing is wrapped in (not ...), so it matches
something that specifically _isn't_ a memory_operand.  All that reload
stuff shouldn't be needed, plain:

(define_predicate "non_volatile_mem_operand"
  (and (match_operand 0 "memory_operand")
       (not (match_test "MEM_VOLATILE_P (op)"))))

should be OK.

-------------------------------------------------------------------------
+(define_attr "umips_not" "no, yes"
+  (if_then_else (and (eq_attr "alu_type" "not")
+		     (match_test "umips_two_reg (PATTERN (insn))"))
+  (const_string "yes")
+  (const_string "no")))
-------------------------------------------------------------------------

Looks odd: reg-to-reg is the only possiblity for "not".
Should be enough to test "alu_type" against "not" directly
and drop this attribute.

-------------------------------------------------------------------------
+(define_attr "umips_arith" "no, yes"
+  (if_then_else (and (eq_attr "type" "arith")
+		     (not (eq_attr "mode" "DI"))
+		     (match_test "umips_three_reg_match0 (PATTERN (insn))"))
+  (const_string "yes")
+  (const_string "no")))
-------------------------------------------------------------------------

Well, I suppose this OK for now, but it seems odd to be hiding
the difference from the main patterns.  Don't we want IRA+reload
to optimise for this where possible?  Or does that produce bad results?
More below.

Rather than define lots of attributes, please just use [(cond ...)]
to set the default directly:

(define_attr "umips_short_insn" "no, yes"
  (cond [(and (eq_attr "type" "arith")
	      (not (eq_attr "mode" "DI"))
 	      (match_test "umips_three_reg_match0 (PATTERN (insn))"))
	 (const_string "yes")

	 ...]
	(const_string "no")))

-------------------------------------------------------------------------
+(define_attr "umips_mfhi" "no, yes"
+  (if_then_else (and (eq_attr "move_type" "mfhilo")
+		     (match_operand 1 "gpr_operand" ""))
+  (const_string "yes")
+  (const_string "no")))
-------------------------------------------------------------------------

Patch collision: as of a couple of days ago, we now have an "mfhi"
"type" attribute.

-------------------------------------------------------------------------
+(define_attr "umips_logicals" "no, yes"
+  (if_then_else (and (ior (eq_attr "alu_type" "and")
+			  (eq_attr "alu_type" "or")
+			  (eq_attr "alu_type" "xor"))
+		     (match_test "umips_three_reg_match0 (PATTERN (insn))"))
+  (const_string "yes")
+  (const_string "no")))
-------------------------------------------------------------------------

(eq_attr "alu_type" "and,or,xor").

-------------------------------------------------------------------------
 	  ;; Direct branch instructions have a range of [-0x20000,0x1fffc],
-	  ;; relative to the address of the delay slot.  If a branch is
-	  ;; outside this range, we have a choice of two sequences.
+	  ;; relative to the address of the delay slot.
+	  ;;
+	  ;; For microMIPS the range is reduced to [-0x10000,0xfffe].
+	  ;;
+	  ;; If a branch is outside this range, we have a choice of two
+	  ;; sequences.
-------------------------------------------------------------------------

I'd prefer:
-------------------------------------------------------------------------
	  ;; Direct microMIPS branch instructions have a range of
	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
	  ;; If a branch is outside this range, we have a choice of two
	  ;; sequences.
-------------------------------------------------------------------------

-------------------------------------------------------------------------
 	  ;; pattern has no explicit delay slot, mips_adjust_insn_length
 	  ;; will add the length of the implicit nop.  The values for
 	  ;; forward and backward branches will be different as well.
+
-------------------------------------------------------------------------

Excess whitespace.

-------------------------------------------------------------------------
+	  (eq_attr "type" "multimem")
+	  (const_int 4)
-------------------------------------------------------------------------

Not necessary, 4 is the default.

-------------------------------------------------------------------------
+(define_insn "*branch_equality<mode>_micromips"
+  [(set (pc)
+	(if_then_else
+	 (match_operator 1 "equality_operator"
+			 [(match_operand:GPR 2 "register_operand" "d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
+	 (label_ref (match_operand 0 "" ""))
+	 (pc)))]
+  "TARGET_MICROMIPS"
+{
+  /* For a simple bnez or beqz microMIPS branch.  */
+  if (!TARGET_BRANCHLIKELY
+      && get_attr_length (insn) <= 8
+      && GET_CODE (operands[3]) == CONST_INT
+      && INTVAL (operands[3]) == 0)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%C1z%:\t%2,%0",
+					   "%*b%N1z%:\t%2,%0");
+
+  return mips_output_conditional_branch (insn, operands,
+					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
+					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
+}
-------------------------------------------------------------------------

This:

      && GET_CODE (operands[3]) == CONST_INT
      && INTVAL (operands[3]) == 0)

can just be:

      && operands[3] == const0_rtx)

Why the !TARGET_BRANCHLIKELY test?  You force it off anyway in
mips_set_mips16_micromips_mode (which I agree is a good thing)

-------------------------------------------------------------------------
 (define_insn "indirect_jump_<mode>"
   [(set (pc) (match_operand:P 0 "register_operand" "d"))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
-------------------------------------------------------------------------

"jr" should be fine across the board.  Same later.

-------------------------------------------------------------------------
+   microMIPS LWM and SWM support 12-bit offsets (from -2048 to 2047) and
+   to preserve the maximum stack alignment, so 0x7f0 is used when
+   TARGET_MICROMIPS.
-------------------------------------------------------------------------

I'd prefer:

-------------------------------------------------------------------------
   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
-------------------------------------------------------------------------

(where the context already describes the alignment constraint).

-------------------------------------------------------------------------
+static bool
+mips_nocompression_decl_p (const_tree decl)
+{
+  if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
+    return true;
+
+  return (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL
+          && lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL);
+}
...
+/* Similar predicates for "micromips"/"nomicromips" function attributes.  */
+
+static bool
+mips_micromips_decl_p (const_tree decl)
+{
+  return lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL;
+}
+
+static bool
+mips_nomicromips_decl_p (const_tree decl)
+{
+  return lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL;
+}
+
+/* Return true if function DECL is a microMIPS function.  Return the ambient
+   setting if DECL is null.  */
+
+static bool
+mips_use_micromips_mode_p (tree decl)
+{
+  if (decl)
+    {
+      /* Nested functions must use the same frame pointer as their
+	 parent and must therefore use the same ISA mode.  */
+      tree parent = decl_function_context (decl);
+      if (parent)
+	decl = parent;
+      if (mips_micromips_decl_p (decl))
+	return true;
+      if (mips_nomicromips_decl_p (decl))
+	return false;
+    }
+  return mips_base_micromips;
+}
-------------------------------------------------------------------------

To reduce the cut-&-paste here and elsewhere, I think it would be
better to have:

-------------------------------------------------------------------------
unsigned int mips_base_compression_flags;
-------------------------------------------------------------------------

to replace mips_base_mips16 & mips_base_micromips and:

-------------------------------------------------------------------------
/* Return the set of compression modes that are explicitly required
   by DECL.  */

static unsigned int
mips_get_compress_on_flags (tree decl)
{
  unsigned int flags = 0;

  if (lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL)
    flags |= MASK_MIPS16;

  if (lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL)
    flags |= MASK_MICROMIPS;

  return flags;
}

/* Return the set of compression modes that are explicitly forbidden
   by DECL.  */

static unsigned int
mips_get_compress_off_flags (tree decl)
{
  unsigned int flags = 0;

  if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
    flags |= MASK_MIPS16 | MASK_MICROMIPS;

  if (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL)
    flags |= MASK_MIPS16;

  if (lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL)
    flags |= MASK_MICROMIPS;

  return flags;
}

/* Return the compression mode that should be used for function DECL.
   Return the ambient setting if DECL is null.  */

static unsigned int
mips_get_compress_mode (tree decl)
{
  unsigned int flags, force_on;

  flags = mips_base_compression_flags;
  if (decl)
    {
      /* Nested functions must use the same frame pointer as their
	 parent and must therefore use the same ISA mode.  */
      tree parent = decl_function_context (decl);
      if (parent)
	decl = parent;
      force_on = mips_get_compression_on_flags (decl);
      if (force_on)
        return force_on;
      flags &= ~mips_get_compression_off_flags (decl);
    }
  return flags;
}

/* Return the name of the compression mode represented by target
   flags FLAGS.  */

static const char *
mips_get_compression_name (unsigned int flags)
{
  if (flags & TARGET_MIPS16)
    return "mips16";
  if (flags & TARGET_MICROMIPS)
    return "micromips";
  gcc_unreachable();
}
-------------------------------------------------------------------------

then use these instead of tests for individual mips16 or micromips
attributes.

-------------------------------------------------------------------------
     switch (addr.type)
       {
       case ADDRESS_REG:
+
 	if (TARGET_MIPS16
 	    && !mips16_unextended_reference_p (mode, addr.reg,
 					       UINTVAL (addr.offset)))
-------------------------------------------------------------------------

Excess whitespace.

-------------------------------------------------------------------------
+int
+umips_address_insns (rtx x, enum machine_mode mode, bool might_split_p)
+{
+  struct mips_address_info addr;
+  int factor;
+
+  /* BLKmode is used for single unaligned loads and stores and should
+     not count as a multiword mode.  (GET_MODE_SIZE (BLKmode) is pretty
+     meaningless, so we have to single it out as a special case one way
+     or the other.)  */
+  if (mode != BLKmode && might_split_p)
+    factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+  else
+    factor = 1;
+
+  if (mips_classify_address (&addr, x, mode, false))
+    switch (addr.type)
+      {
+      case ADDRESS_REG:
+	if (!CONST_INT_P (addr.offset)
+	    || INTVAL (addr.offset) < -2048
+	    || INTVAL (addr.offset) > 2047)
+	  return 0;
+
+	return factor;
+
+      default:
+	break;
+
+      }
+  return 0;
+}
-------------------------------------------------------------------------

Function lacks a comment.  It's only use is for YC/YD, which always
pass false for might_split_p, so this is really just a predicate
that tests for 12-bit offset addresses.  So:

-------------------------------------------------------------------------
/* Return true if X is a legimate address with a 12-bit offset.
   MODE is the mode of the value being accessed.  */

bool
umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
{
  struct mips_address_info addr;

  return (mips_classify_address (&addr, x, mode, false)
  	  && addr.type == ADDRESS_REG
	  && CONST_INT_P (addr.offset)
	  && IN_RANGE (INTVAL (addr.offset), -2048, 2047));
}
-------------------------------------------------------------------------

Seems like you could reuse this elsewhere in places that also
check for 12-bit offsets.

-------------------------------------------------------------------------
+/* Return true if the insn has three micromips register operands.  */
+int
+umips_three_reg (rtx insn)
+{
+   rtx op0 = XEXP (insn, 0);
+   rtx op1 = XEXP (insn, 1);
+   rtx op2 = XEXP (insn, 2);
+
+   return (op0 != NULL_RTX
+           && op1 != NULL_RTX
+	   && op2 != NULL_RTX
+	   && REG_P (op0)
+	   && M16_REG_P (REGNO (op0))
+	   && REG_P (op1)
+	   && M16_REG_P (REGNO (op1))
+	   && REG_P (op2)
+	   && M16_REG_P (REGNO (op2)));
+}
-------------------------------------------------------------------------

This doesn't look right.  You pass in a complete PATTERN,
so XEXP (insn, 1) will typically be the SET_SRC (such as a PLUS)
and XEXP (insn, 2) usually isn't valid.

I think --enable-checking=yes,rtl would have tripped over the op2
extraction and flagged it as a problem.  Could you use that option
when testing the updated patch?

Same problem with the other predicates.

Please make the predicates return bool rather than int.

Like I said above, I'd really prefer to see the register requirements
modelled in the patterns directly.  You could use the "enabled" to
prevent the new alternatives from being used by non-MIPS16 code.

-------------------------------------------------------------------------
+  if (TARGET_MICROMIPS)
+    fprintf (asm_out_file, "\t.set\tmicromips\n");
+  else
+    fprintf (asm_out_file, "\t.set\tnomicromips\n");
-------------------------------------------------------------------------

We need a configure test to see whether the assembler supports microMIPS.
We shouldn't emit ".set\tnomicromips" if it doesn't.

-------------------------------------------------------------------------
+      /* When reorder or noreorder with final_squence 0, the delay slot will
+	 be a nop, so we just use the compact version for microMIPS.  */
+      if (mips_noreorder.nesting_level == 0 || final_sequence == 0)
+	putc ('c', file);
-------------------------------------------------------------------------

Should just be "final_sequence == 0".  Same for '%!'.

-------------------------------------------------------------------------
+static void mips_save_reg (rtx reg, rtx mem);
-------------------------------------------------------------------------

Please move the functions around so that this isn't necessary.

-------------------------------------------------------------------------
+/* Build microMIPS save or restore.  FN is save or restore function.
+   OFFSET is the current stack offset.
+   Return true if we succeed creating save or restore.  */
-------------------------------------------------------------------------

/* Consider building a microMIPS LDM or STM for the current stack frame.
   FN is mips_save_reg for stores or mips_restore_reg for loads.
   OFFSET is the offset of the first register save slot from the
   current stack pointer.

   Return true on success, in which case all GPRs will have been saved.  */

-------------------------------------------------------------------------
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+			      HOST_WIDE_INT offset)
-------------------------------------------------------------------------

Odd formatting.

-------------------------------------------------------------------------
+  unsigned int type[19] = {0x00010000, 0x00030000, 0x00070000, 0x000f0000,
+			   0x001f0000, 0x003f0000, 0x007f0000, 0x00ff0000,
+			   0x40ff0000, 0x80000000, 0x80010000, 0x80030000,
+			   0x80070000, 0x800f0000, 0x801f0000, 0x803f0000,
+			   0x807f0000, 0x80ff0000, 0xc0ff0000};
+  unsigned int encode[19] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19,
+			     20, 21, 22, 23, 24, 25};
-------------------------------------------------------------------------

Make these static const arrays.

-------------------------------------------------------------------------
+  /* Try matching $16 to $31 (s0 to ra).  */
+  for (i = 0; i < 19; i++)
+    if ((cfun->machine->frame.mask & 0xffff0000) == type[i])
+      break;
-------------------------------------------------------------------------

ARRAY_SIZE (type) instead of 19 (here and elsewhere).

-------------------------------------------------------------------------
+  /* For only one register, we use normal sw/lw for speed.  */
+  if (i == 0 || i == 9)
+    return false;
-------------------------------------------------------------------------

Seems easier to drop these two elements from the array (with a comment).

-------------------------------------------------------------------------
+  /* For $31 to $24.  */
+  if (i < 8 && (cfun->machine->frame.mask & 0xff000000))
+    {
+      int regno;
+      for (regno = GP_REG_LAST; regno > GP_REG_LAST - 8; regno--)
+	if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+	  {
+	    mips_save_restore_reg (word_mode, regno, offset, fn);
+	    offset -= UNITS_PER_WORD;
+	  }
+    }
-------------------------------------------------------------------------

Rather than this, please just use:

-------------------------------------------------------------------------
  extra_regs = (cfun->machine->frame.mask & ~type[i]);
  for (regno = GP_REG_LAST; regno > GP_REG_LAST - 8; regno--)
    if (BITSET_P (extra_regs, regno - GP_REG_FIRST))
      {
	mips_save_restore_reg (word_mode, regno, offset, fn);
	offset -= UNITS_PER_WORD;
      }
-------------------------------------------------------------------------

-------------------------------------------------------------------------
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base,
+			   this_offset + j * UNITS_PER_WORD));
-------------------------------------------------------------------------

Nonstandard formatting.  Might be easiest to split out the offset calculation.

-------------------------------------------------------------------------
@@ -10050,6 +10434,13 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
   offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+
+  if (TARGET_MICROMIPS)
+    {
+      if (umips_build_save_restore (fn, offset))
+	goto save_restore_fp_reg;
+    }
+
   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
     if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
       {
@@ -10060,6 +10451,8 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
 	offset -= UNITS_PER_WORD;
       }
 
+save_restore_fp_reg:
+
   /* This loop must iterate over the same space as its companion in
      mips_compute_frame_info.  */
   offset = cfun->machine->frame.fp_sp_offset - sp_offset;
-------------------------------------------------------------------------

No!!! :-)  Just wrap the GPR save in:

  if (!(TARGET_MICROMIPS && umips_build_save_restore (fn, offset)))

Please also split out the save loop, since we now have three copies of it.

-------------------------------------------------------------------------
 static void
-mips_deallocate_stack (rtx base, rtx offset, HOST_WIDE_INT new_frame_size)
+mips_deallocate_stack (rtx base, rtx offset, HOST_WIDE_INT new_frame_size,
+                       bool use_jraddiusp_p)
 {
+  if (use_jraddiusp_p)
+    return;
+
   if (base == stack_pointer_rtx && offset == const0_rtx)
     return;
 
   mips_frame_barrier ();
+
-------------------------------------------------------------------------

Seems odd to add a parameter that causes the function to return instantly.
But...

-------------------------------------------------------------------------
   const struct mips_frame_info *frame;
   HOST_WIDE_INT step1, step2;
   rtx base, adjust, insn;
+  bool use_jraddiusp_p = false;
 
   if (!sibcall_p && mips_can_use_return_insn ())
     {
@@ -10831,7 +11230,7 @@ mips_expand_epilogue (bool sibcall_p)
       mips_emit_move (MIPS_EPILOGUE_TEMP (Pmode), adjust);
       adjust = MIPS_EPILOGUE_TEMP (Pmode);
     }
-  mips_deallocate_stack (base, adjust, step2);
+  mips_deallocate_stack (base, adjust, step2, use_jraddiusp_p);
 
   /* If we're using addressing macros, $gp is implicitly used by all
      SYMBOL_REFs.  We must emit a blockage insn before restoring $gp
@@ -10900,7 +11299,8 @@ mips_expand_epilogue (bool sibcall_p)
 
 	  /* If we don't use shoadow register set, we need to update SP.  */
 	  if (!cfun->machine->use_shadow_register_set_p)
-	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
+	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2),
+				   0, use_jraddiusp_p);
 	  else
 	    /* The choice of position is somewhat arbitrary in this case.  */
 	    mips_epilogue_emit_cfa_restores ();
@@ -10911,9 +11311,11 @@ mips_expand_epilogue (bool sibcall_p)
 	}
       else
 	/* Deallocate the final bit of the frame.  */
-	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
+	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2),
+			       0, use_jraddiusp_p);
     }
-  gcc_assert (!mips_epilogue.cfa_restores);
+  if (!use_jraddiusp_p)
+    gcc_assert (!mips_epilogue.cfa_restores);
 
   /* Add in the __builtin_eh_return stack adjustment.  We need to
      use a temporary in MIPS16 code.  */
@@ -10963,6 +11365,10 @@ mips_expand_epilogue (bool sibcall_p)
 	      rtx reg = gen_rtx_REG (Pmode, GP_REG_FIRST + 7);
 	      pat = gen_return_internal (reg);
 	    }
+	  else if (use_jraddiusp_p)
+	    {
+	      pat = gen_mips_jraddiusp (GEN_INT (step2));
+	    }
 	  else
 	    {
 	      rtx reg = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
-------------------------------------------------------------------------

...unless I'm missing something, it never gets set anyway.

-------------------------------------------------------------------------
 static void
 mips_set_current_function (tree fndecl)
 {
-  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+  mips_set_mips16_micromips_mode (mips_use_mips16_mode_p (fndecl),
+				  mips_use_micromips_mode_p (fndecl));
+
+  /* Override the default setting for function alignment once it is decided
+     which mode is in force.  */
+
+  if (fndecl
+      && TARGET_MICROMIPS
+      && optimize_size
+      && ! TARGET_INTERLINK_MIPS16
+      && lookup_attribute ("aligned", DECL_ATTRIBUTES (fndecl)) == NULL)
+    DECL_ALIGN (fndecl) = 16;
 }
-------------------------------------------------------------------------

Looks like the wrong place to do this.  Please treat this as a separate
patch and get a tree expert to comment.

-------------------------------------------------------------------------
+/* Return true if PATTERN matches the kind of instruction generated by
+   micromips_build_save_restore.  SAVE_P is true for store.  */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+  int n;
+  HOST_WIDE_INT first_offset = 0;
+  rtx first_base = 0;
+  unsigned int first_regno = 0;
+
+  for (n = 0; n < XVECLEN (pattern, 0); n++)
+    {
+      rtx set, reg, mem, this_base;
+      HOST_WIDE_INT this_offset;
+      unsigned int this_regno;
+
+      /* Check that we have a SET.  */
+      set = XVECEXP (pattern, 0, n);
+      if (GET_CODE (set) != SET)
+	return false;
+
+      /* Check that the SET is a load (if restoring) or a store
+	 (if saving).  */
+      mem = save_p ? SET_DEST (set) : SET_SRC (set);
+      if (!MEM_P (mem))
+	return false;
+
+      /* Check that the address is the sum of base and a
+	 possibly-zero constant offset.  */
+      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+      if (!REG_P (this_base))
+	return false;
+
+      if (n == 0)
+	{
+	  first_base = this_base;
+	  first_offset = this_offset;
-------------------------------------------------------------------------

Need to check the offset is in range.

-------------------------------------------------------------------------
+      /* Make sure the order of regno is "$16-$23, $30, $31", "$16-$23, $30",
+	 or "$31".  */
+      this_regno = REGNO (reg);
+      if (n == 0)
+	{
+	  if (this_regno != 16 && this_regno != 31)
+	    return false;
+	  first_regno = this_regno;
+	}
+      else if (n == 8) /* For s8.  */
+	{
+	  if (n == XVECLEN (pattern, 0) - 1)
+	    {
+	      if (this_regno != 30 && this_regno != 31)
+		return false;
+	    }
+	  else
+	    {
+	      if (this_regno != 30)
+		return false;
+	    }
+	}
+      else if (n != XVECLEN (pattern, 0) - 1)
+	{
+	  if (this_regno != first_regno + n)
+	    return false;
+	}
+      else /* The last item.  */
+	{
+	  if ((this_regno != first_regno + n) && this_regno != 31)
+	    return false;
+	}
-------------------------------------------------------------------------

Please just build a mask of the registers and check it against the
same array as the build function.

-------------------------------------------------------------------------
+      /* If any item in the list is volatile then disallow.  This is a
+         safeguard only as this is a path unlikely to be exercised since 
+         typical code only generates the instructions for stack accesses.  */
+      if (MEM_VOLATILE_P (mem))
+        return false;
-------------------------------------------------------------------------

Please add this to the earlier !MEM_P check, i.e.:

-------------------------------------------------------------------------
      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
	return false;
-------------------------------------------------------------------------

-------------------------------------------------------------------------
+/* Return the assembly instruction for microMIPS lwm or swm.
+   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+  static char buffer[300];
+  char *s;
+  int n;
+  HOST_WIDE_INT offset;
+  rtx base, mem, set, reg, last_set, last_reg;
+
+  /* Parse the pattern.  */
+  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
-------------------------------------------------------------------------

Would be nice to have a shared subroutine of this and
umips_save_restore_pattern_p that returns the type/encoding index
(or -1 if none).  That'd make this function easier to write.

-------------------------------------------------------------------------
+  mem1_temp = XEXP (mem1, 0);
+  mem2_temp = XEXP (mem2, 0);
+
+  /* Make sure memory is base plus offset.  */
+  if (GET_CODE (mem1_temp) != PLUS
+      || GET_CODE (mem2_temp) != PLUS
+      || GET_CODE (XEXP (mem1_temp, 1)) != CONST_INT
+      || GET_CODE (XEXP (mem2_temp, 1)) != CONST_INT)
+    return false;
+
+  mips_split_plus (mem1_temp, &base1, &offset1);
+  mips_split_plus (mem2_temp, &base2, &offset2);
+
+  if (!REG_P (base1) || !REG_P (base2))
+    return false;
+
+  if (REGNO (base1) != REGNO (base2))
+    return false;
-------------------------------------------------------------------------

Better as:

-------------------------------------------------------------------------
  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
    return false;
-------------------------------------------------------------------------

Note that this allows cases where mem1 or mem2 are unoffsetted registers,
which should always be (reg) rather than (plus (reg) (const_int 0)).

-------------------------------------------------------------------------
+/* Return the assembly instruction for microMIPS lwp or swp.
+   LOAD_P is true for load.  */
+
+const char *
+umips_output_load_store_pair (bool load_p, rtx reg, rtx mem)
+{
+  static char buffer[300];
+  HOST_WIDE_INT offset;
+  rtx base;
+
+  gcc_assert (REG_P (reg) && MEM_P (mem));
+
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+  gcc_assert (REG_P (base));
+
+  sprintf (buffer, "%s\t%s,%d(%s)", load_p ? "lwp" : "swp",
+	   reg_names [REGNO (reg)], (int) offset, reg_names [REGNO (base)]);
+  return buffer;
+}
-------------------------------------------------------------------------

Instead use output_asm_insn and return "".  This allows you to use
the normal assembly formatting.

-------------------------------------------------------------------------
+  int match[8] = {0x00000060,	/* 5, 6 */
+		  0x000000a0,	/* 5, 7 */
+		  0x000000c0,	/* 6, 7 */
+		  0x00200010,	/* 4, 21 */
+		  0x00400010,	/* 4, 22 */
+		  0x00000030,	/* 4, 5 */
+		  0x00000050,	/* 4, 6 */
+		  0x00000090};	/* 4, 7 */
-------------------------------------------------------------------------

static const.

-------------------------------------------------------------------------
+  for (i = 0; i < 8; i++)
+    {
+      if (pair == match[i])
+	return true;
+    }
-------------------------------------------------------------------------

ARRAY_SIZE (match) instead of 8.

-------------------------------------------------------------------------
+/* True if this constant is valid for the microMIPS andi16 insn.  */
+#define UMIPS_ANDI16_IMM(VALUE)	\
+  (((unsigned HOST_WIDE_INT) (VALUE) == 1)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 2)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 3)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 4)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 7)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 8)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 15)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 16)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 31)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 32)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 63)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 64)		\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 255)	\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 32768)	\
+    || ((unsigned HOST_WIDE_INT) (VALUE) == 65536))
-------------------------------------------------------------------------

These casts look redundant.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2012-07-20  0:46   ` Richard Sandiford
@ 2013-01-22 20:23     ` Moore, Catherine
  2013-01-22 20:27       ` Moore, Catherine
  2013-03-04 19:43     ` Moore, Catherine
  1 sibling, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-01-22 20:23 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej, Moore, Catherine

Hi Richard,
I hope that I have addressed all of your comments in this cleaned up patch.  There are a couple of items that have been omitted that I plan to submit as follow-on patches.  The use of jraddiusp and the use of short delay slots have both been deferred.  You had suggested a function named mips_get_compression_name but I did not see where this was used.  It's been omitted for now.   I cleaned up most of the gcc.target/mips tests for microMIPS, but some of the MIPS16-specific tests will fail.  It looks like an overhaul of mips.exp may be required and that is beyond the scope of this patch.
Let me know what you think.  I'll submit the optimizations once the base patch is approved.
Thanks,
Catherine

> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Thursday, July 19, 2012 8:46 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> > Forgot to copy the list ...
> 
> Same with my reply...
> 
> > Here is the updated microMIPS patch.  It's been a very long time (two
> > years!) since I posted the original.  Please let me know what we're
> > going to need to do to get this committed.
> 
> This is looking better.  At least that huge if statement in
> mips_adjust_insn_length (IIRC) is gone :-)
> 
> -------------------------------------------------------------------------
>  @itemx -mno-interlink-mips16
>  @opindex minterlink-mips16
>  @opindex mno-interlink-mips16
> -Require (do not require) that non-MIPS16 code be link-compatible with
> -MIPS16 code.
> +Require (do not require) that non-MIPS16/non-microMIPS code be
> +link-compatible with MIPS16/microMIPS code.
> 
> -For example, non-MIPS16 code cannot jump directly to MIPS16 code;
> +For example, non-MIPS16/non-microMIPS code cannot jump directly to
> +MIPS16/microMIPS code;
>  it must either use a call or an indirect jump.  @option{-minterlink-mips16}
> therefore disables direct jumps unless GCC knows that the target of the -
> jump is not MIPS16.
> +jump is not MIPS16/non microMIPS.
> -------------------------------------------------------------------------
> 
> This doesn't read very well.  Let's add a -minterlink-compressed option and
> treat -mno-interlink-mips16 as an alias of it.  So:
> 
> -------------------------------------------------------------------------
> @item -minterlink-compressed
> @itemx -mno-interlink-compressed
> @opindex minterlink-compressed
> @opindex mno-interlink-compressed
> Require (do not require) that code using the standard (uncompressed) MIPS
> ISA be link-compatible with MIPS16 and microMIPS code.
> 
> For example, non-MIPS16 code cannot jump directly to MIPS16 code; it must
> either use a call or an indirect jump.  The same applies to non-microMIPS
> jumps to microMIPS code.  @option{-minterlink-compressed} therefore
> disables direct jumps unless GCC knows that the target of the jump is not
> compressed.
> 
> @item -minterlink-mips16
> @itemx -mno-interlink-mips16
> @opindex minterlink-mips16
> @opindex mno-interlink-mips16
> Aliases of @option{-minterlink-compressed} and @option{-mno-interlink-
> compressed}.  These options predate the mipsMIPS ASE and are retained for
> backwards compatiblity.
> -------------------------------------------------------------------------
> 
> Let's also make TARGET_INTERLINK_COMPRESSED the internal name.
> 
> -------------------------------------------------------------------------
> +@item -mmicromips
> +@itemx -mno-micromips
> +@opindex mmicromips
> +@opindex mno-mmicromips
> +Generate (do not generate) microMIPS code.  If GCC is targetting a
> +MIPS32 or MIPS64 architecture, it will make use of the microMIPS ASE@.
> -------------------------------------------------------------------------
> 
> Looks like excess cut-&-paste from the MIPS16 version.  The point of the
> MIPS16 documentation is to distinguish between the original MIPS16 "ASE"
> and MIPS16e.  There's no such distinction here.
> 
> -------------------------------------------------------------------------
> +@item -mjals
> +@itemx -mno-jals
> +@opindex mjals
> +@opindex mno-jals
> +Generate (do not generate) the @code{jals} instruction for microMIPS by
> +recognizing that the branch delay slot instruction can be 16 bits.
> +This implies that the funciton call cannot switch the current mode
> +during the linking stage, because we don't have the @code{jalxs}
> +instruction that supports 16-bit branch delay slot instructions.
> -------------------------------------------------------------------------
> 
> typo: function
> 
> The assumption we're making seems to be that calls from microMIPS code
> cannot go to non-microMIPS code.  If so, let's make that the option instead.
> The above is too low-level.
> 
> With analogy to -minterlink-compressed, the option could be -minterlink-
> uncompressed/-mno-interlink-uncompressed, with the default being -
> minterlink-uncompressed.
> 
> -------------------------------------------------------------------------
> +@item YC
> +For MIPS, it is the same as the constraint @code{R}.  For microMIPS, it
> +matches an address within a 12-bit offset that can be used for
> +microMIPS @code{ll}, @code{sc}, etc.
> +
> +@item YD
> +For MIPS, it is the same as the constraint @code{p}  For microMIPS, it
> +matches a 12-bit offsest address.
> +
> +@item YE
> +A singler register memory operand.
> -------------------------------------------------------------------------
> 
> "For MIPS" is a bit vague (it actually applies to MIPS16 too).
> So how about:
> 
> -------------------------------------------------------------------------
> @item YC
> when compiling microMIPS code, this constraint matches a memory operand
> whose address is formed from a base register and a 12-bit offset.
> These operands can be used for microMIPS instructions such as @code{ll}
> and @code{sc}.  When not compiling for microMIPS code, @code{YC} is
> equivalent to @code{R}.
> 
> @item YD
> when compiling microMIPS code, this constraint matches an address operand
> that is formed from a base register and a 12-bit offset.
> These operands can be used for microMIPS instructions such as
> @code{prefetch}.
> When not compiling for microMIPS code, @code{YC} is equivalent to
> @code{p}.
> -------------------------------------------------------------------------
> 
> No need for "YE": we have "ZR" now.  I'd like to make the other constraints
> "Z" rather than "Y" too -- ZC and ZD -- since "Y" is really for constants.
> 
> -------------------------------------------------------------------------
> +(define_insn "*store_word_multiple"
> +  [(match_parallel 0 ""
> +       [(set (match_operand:SI 1 "memory_operand")
> +	     (match_operand:SI 2 "register_operand"))])]
> +  "TARGET_MICROMIPS
> +   && umips_save_restore_pattern_p (true, operands[0])"
> +  {
> +    return umips_output_save_restore (true, operands[0]);
> +  }
> +  [(set_attr "type" "multimem")
> +   (set_attr "mode" "SI")
> +   (set_attr "can_delay" "no")])
> -------------------------------------------------------------------------
> 
> Nitlet: local style is to use "{ return ...; }" for single-line statements and
> column-0 placement of "{" and "}" for multi-line ones.  Same for rest of file.
> 
> -------------------------------------------------------------------------
> +; For lwp
> +(define_peephole2
> +  [(set (match_operand:SI 0 "umips_lwp_register" "")
> +        (match_operand:SI 1 "non_volatile_mem_operand" ""))
> +   (set (match_operand:SI 2 "umips_lwp_register" "")
> +        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
> +  "TARGET_MICROMIPS
> +   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
> +	&& umips_load_store_pair_p (true, false, operands[0],
> +				    operands[1], operands[3]))
> +       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
> +	   && umips_load_store_pair_p (true, true, operands[2],
> +				       operands[3], operands[1])))"
> +  [(parallel [(set (match_dup 0) (match_dup 1))
> +              (set (match_dup 2) (match_dup 3))])]
> -------------------------------------------------------------------------
> 
> Please split out this:
> 
>    && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
> 	&& umips_load_store_pair_p (true, false, operands[0],
> 				    operands[1], operands[3]))
>        || (REGNO (operands[2]) + 1 == REGNO (operands[0])
> 	   && umips_load_store_pair_p (true, true, operands[2],
> 				       operands[3], operands[1])))
> 
> into a function:
> 
> bool
> umips_load_store_pair_p (bool load_p, rtx reg1, rtx reg2, rtx mem1, rtx
> mem2)
> 
> with the current umips_load_store_pair_p being a subroutine
> (umips_load_store_pair_p_1).
> 
> -------------------------------------------------------------------------
> +(define_insn "*lwp"
> +  [(parallel [(set (match_operand:SI 0 "umips_lwp_register")
> +		   (match_operand:SI 1 "memory_operand"))
> +	      (set (match_operand:SI 2 "umips_lwp_register")
> +		   (match_operand:SI 3 "memory_operand"))])]
> +
> +  "TARGET_MICROMIPS
> +   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
> +	&& umips_load_store_pair_p (true, false, operands[0],
> +				    operands[1], operands[3]))
> +       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
> +	   && umips_load_store_pair_p (true, true, operands[2],
> +				       operands[3], operands[1])))"
> +  {
> +    if (REGNO (operands[0]) + 1 == REGNO (operands[2]))
> +      return umips_output_load_store_pair (true, operands[0], operands[1]);
> +    else
> +      return umips_output_load_store_pair (true, operands[2],
> +operands[3]);
> +  }
> +  [(set_attr "type" "load")
> +   (set_attr "mode" "SI")
> +   (set_attr "can_delay" "no")])
> -------------------------------------------------------------------------
> 
> Same with the output:
> 
> void
> umips_output_load_store_pair (bool load_p, rtx reg1, rtx reg2,
> 			      rtx mem1, rtx mem2)
> 
> Why do only the stores require non_volatile_mem_operand?  It looks like
> you could be reordering loads from volatile memory otherwise.
> 
> -------------------------------------------------------------------------
> +; For jraddiusp
> +(define_insn "mips_jraddiusp"
> +  [(parallel [(return)
> +              (use (reg:SI 31))
> +	      (set (reg:SI 29)
> +		   (plus:SI (reg:SI 29)
> +			    (match_operand 0 "const_int_operand")))])]
> +  "TARGET_MICROMIPS"
> +  "jraddiusp\t%0"
> +  [(set_attr "type" "trap")
> +   (set_attr "mode" "SI")
> +   (set_attr "can_delay" "no")])
> -------------------------------------------------------------------------
> 
> Redundant comment.
> 
> -------------------------------------------------------------------------
> +; For movep
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +        (match_operand:SI 1 "movep_si_operand" ""))
> +   (set (match_operand:SI 2 "register_operand" "")
> +        (match_operand:SI 3 "movep_si_operand" ""))]
> +  "TARGET_MICROMIPS
> +   && umips_movep_target_p (operands[0], operands[2])"
> +  [(parallel [(set (match_dup 0) (match_dup 1))
> +              (set (match_dup 2) (match_dup 3))])]
> +)
> +
> +(define_peephole2
> +  [(set (match_operand:SI 0 "register_operand" "")
> +        (match_operand:SI 1 "movep_si_operand" ""))
> +   (set (match_operand:SF 2 "register_operand" "")
> +        (match_operand:SF 3 "const_0_sf_operand" ""))]
> +  "TARGET_MICROMIPS
> +   && umips_movep_target_p (operands[0], operands[2])"
> +  [(parallel [(set (match_dup 0) (match_dup 1))
> +              (set (match_dup 2) (match_dup 3))])]
> +)
> +
> +(define_peephole2
> +  [(set (match_operand:SF 0 "register_operand" "")
> +        (match_operand:SF 1 "const_0_sf_operand" ""))
> +   (set (match_operand:SI 2 "register_operand" "")
> +        (match_operand:SI 3 "movep_si_operand" ""))]
> +  "TARGET_MICROMIPS
> +   && umips_movep_target_p (operands[0], operands[2])"
> +  [(parallel [(set (match_dup 0) (match_dup 1))
> +              (set (match_dup 2) (match_dup 3))])]
> +)
> +
> +(define_peephole2
> +  [(set (match_operand:SF 0 "register_operand" "")
> +        (match_operand:SF 1 "const_0_sf_operand" ""))
> +   (set (match_operand:SF 2 "register_operand" "")
> +        (match_operand:SF 3 "const_0_sf_operand" ""))]
> +  "TARGET_MICROMIPS
> +   && umips_movep_target_p (operands[0], operands[2])"
> +  [(parallel [(set (match_dup 0) (match_dup 1))
> +              (set (match_dup 2) (match_dup 3))])]
> +)
> +
> +(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
> +  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
> +		   (match_operand:MOVEP1 1
> "movep_<MOVEP1:mode>_operand"))
> +	      (set (match_operand:MOVEP2 2 "register_operand")
> +		   (match_operand:MOVEP2 3
> "movep_<MOVEP2:mode>_operand"))])]
> +  "TARGET_MICROMIPS
> +   && umips_movep_target_p (operands[0], operands[2])"
> +{
> +  if (REGNO (operands[0]) < REGNO (operands[2]))
> +    return "movep\t%0,%2,%z1,%z3";
> +  else
> +    return "movep\t%2,%0,%z3,%z1";
> +}
> +  [(set_attr "type" "move")
> +   (set_attr "mode" "<MODE>")
> +   (set_attr "can_delay" "no")])
> -------------------------------------------------------------------------
> 
> Seems to be a mismatch between the peepholes (which only accept 0.0f for
> SFmode) and the insn (which allows registers too).  Can't you use MOVEP1
> and MOVEP2 for the peepholes too?
> 
> -------------------------------------------------------------------------
>  (define_memory_constraint "R"
>    "An address that can be used in a non-macro load or store."
>    (and (match_code "mem")
> -       (match_test "mips_address_insns (XEXP (op, 0), mode, false) == 1")))
> +       (match_test "mips_address_insns (XEXP (op, 0), mode, false)")))
> -------------------------------------------------------------------------
> 
> No, this defeats the purpose of "R", which is supposed to disallow address
> that require assembly macros.
> 
> -------------------------------------------------------------------------
> +(define_memory_constraint "YC"
> +  "For MIPS, it is the same as the constraint R.  For microMIPS, it matches
> +   an address within a 12-bit offset that can be used in ll, sc, etc."
> +  (and (match_code "mem")
> +       (ior (and (match_test "TARGET_MICROMIPS")
> +		 (match_test "umips_address_insns (XEXP (op, 0), mode,
> false)"))
> +	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
> +
> +(define_address_constraint "YD"
> +  "@internal
> +   For MIPS, it is the same as the constraint p.  For microMIPS, it matches
> +   a 12-bit offset address."
> +   (ior (and (match_test "TARGET_MICROMIPS")
> +	     (match_test "umips_address_insns (op, mode, false)"))
> +	(match_test "mips_address_insns (op, mode, false)")))
> -------------------------------------------------------------------------
> 
> Is YD internal or not?  We should remove it from the docs if so, otherwise the
> @internal is wrong.
> 
> Please keep the doc strings exactly the same as the .texi version (including @
> mark-up).  I think the idea was that at some glorious time in the future, we'd
> be able to auto-generate the .texi parts from the .md doc strings.
> 
> -------------------------------------------------------------------------
> +(define_predicate "gpr_operand"
> +  (and (match_code "reg")
> +       (match_test "GP_REG_P (REGNO (op))")))
> -------------------------------------------------------------------------
> 
> This is d_operand.
> 
> -------------------------------------------------------------------------
> +(define_predicate "umips_register"
> +  (and (match_code "reg")
> +       (match_test "M16_REG_P (REGNO (op))")))
> -------------------------------------------------------------------------
> 
> I think I'd prefer to call the predicate m16_register too, for consistency.
> 
> -------------------------------------------------------------------------
> +(define_predicate "umips_andi16_operand"
> +  (and (match_code "const")
> +       (match_test "UMIPS_ANDI16_IMM (INTVAL (op))")))
> -------------------------------------------------------------------------
> 
> Looks like this should be "const_int" instead.  Same for the other constants.
> It seems on face value like some parts of the patch weren't exercised
> because of this.
> 
> -------------------------------------------------------------------------
> +(define_predicate "umips_add_uimm5"
> +  (and (match_code "const")
> +       (match_test "IN_RANGE (INTVAL (op), -8, 7)")))
> -------------------------------------------------------------------------
> 
> Looks like a signed rather than unsigned immediate.  Should this be
> "umips_add_imm5" instead?
> 
> -------------------------------------------------------------------------
> +(define_predicate "umips_addiur2_imm3"
> +  (and (match_code "const")
> +       (ior (match_test "INTVAL(op) == 1")
> +       (ior (match_test "INTVAL(op) == 4")
> +       (ior (match_test "INTVAL(op) == 8")
> +       (ior (match_test "INTVAL(op) == 12")
> +       (ior (match_test "INTVAL(op) == 16")
> +       (ior (match_test "INTVAL(op) == 20")
> +       (ior (match_test "INTVAL(op) == 24")
> +	    (match_test "INTVAL(op) == -1"))))))))))
> -------------------------------------------------------------------------
> 
> (ior ...) can take any number of operands these days, so no need for all those
> ")"s.  Space after INTVAL.
> 
> -------------------------------------------------------------------------
> +(define_predicate "umips_lw16_memref"
> +  (and (match_code "plus")
> +       (match_operand 0 "umips_register" "")) {
> +  rtx op2 = XEXP (op, 1);
> +
> +  return (GET_CODE (op2) == CONST_INT
> +          && ((INTVAL (op2) & 3) == 0)
> +	  && (IN_RANGE (INTVAL (op2), 0, 60)));
> +})
> -------------------------------------------------------------------------
> 
> This tests an address, whereas it sounds from the name (and looks from the
> later code) like it's supposed to be testing a (mem ...) instead.
> Also:
> 
>  (and (match_code "plus")
>       (match_operand 0 "umips_register" ""))
> 
> tests for something that is both a PLUS and a REG, which is never true.
> ((match_operand X ...) doesn't test XEXP (..., X).)
> 
> -------------------------------------------------------------------------
> +(define_predicate "const_0_si_operand"
> +  (and (match_code "const_int,const_double,const_vector")
> +       (match_test "op == CONST0_RTX (SImode)")))
> +
> +(define_predicate "const_0_sf_operand"
> +  (and (match_code "const_int,const_double,const_vector")
> +       (match_test "op == CONST0_RTX (SFmode)")))
> -------------------------------------------------------------------------
> 
> Should be redundant with const_0_operand.  Modes should be checked at
> the match_operand level where important.
> 
> -------------------------------------------------------------------------
> +(define_predicate "movep_si_operand"
> +  (ior (and (match_code "const_int,const_double,const_vector")
> +	    (match_test "op == CONST0_RTX (SImode)"))
> +       (and (match_code "reg")
> +	    (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
> +		 (match_test ("IN_RANGE (REGNO (op), 16, 20)"))))))
> +
> +(define_predicate "movep_sf_operand"
> +  (ior (and (match_code "const_int, const_double, const_vector")
> +	    (match_test "op == CONST0_RTX (SFmode)"))
> +       (and (match_code "reg")
> +	    (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
> +		 (match_test ("IN_RANGE (REGNO (op), 16, 20)"))))))
> -------------------------------------------------------------------------
> 
> These two should be combined:
> 
> -------------------------------------------------------------------------
> (define_predicate "movep_register"
>   (and (match_code "reg")
>        (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
> 	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
> 
> (define_predicate "movep_operand"
>   (ior (match_operand 0 "const_0_operand")
>        (match_operand 0 "movep_register")))
> -------------------------------------------------------------------------
> 
> -------------------------------------------------------------------------
> +(define_predicate "umips_lwp_register"
> +  (and (match_code "reg")
> +       (match_test "REGNO (op) <= GP_REG_LAST")))
> -------------------------------------------------------------------------
> 
> Reundant with d_operand/gpr_operand?
> 
> -------------------------------------------------------------------------
> +;; Return 1 if the operand is in non-volatile memory.  Note that during
> +the ;; RTL generation phase, memory_operand does not return TRUE for
> +volatile ;; memory references.  So this function allows us to recognize
> +volatile ;; references where it's safe.
> +(define_predicate "non_volatile_mem_operand"
> +  (not (and (and (match_code "mem")
> +          (match_test "MEM_VOLATILE_P (op)"))
> +       (if_then_else (match_test "reload_completed")
> +         (match_operand 0 "memory_operand")
> +         (if_then_else (match_test "reload_in_progress")
> +         (match_test "strict_memory_address_p (mode, XEXP (op, 0))")
> +         (match_test "memory_address_p (mode, XEXP (op, 0))"))))))
> -------------------------------------------------------------------------
> 
> This looks wrong: the whole thing is wrapped in (not ...), so it matches
> something that specifically _isn't_ a memory_operand.  All that reload stuff
> shouldn't be needed, plain:
> 
> (define_predicate "non_volatile_mem_operand"
>   (and (match_operand 0 "memory_operand")
>        (not (match_test "MEM_VOLATILE_P (op)"))))
> 
> should be OK.
> 
> -------------------------------------------------------------------------
> +(define_attr "umips_not" "no, yes"
> +  (if_then_else (and (eq_attr "alu_type" "not")
> +		     (match_test "umips_two_reg (PATTERN (insn))"))
> +  (const_string "yes")
> +  (const_string "no")))
> -------------------------------------------------------------------------
> 
> Looks odd: reg-to-reg is the only possiblity for "not".
> Should be enough to test "alu_type" against "not" directly and drop this
> attribute.
> 
> -------------------------------------------------------------------------
> +(define_attr "umips_arith" "no, yes"
> +  (if_then_else (and (eq_attr "type" "arith")
> +		     (not (eq_attr "mode" "DI"))
> +		     (match_test "umips_three_reg_match0 (PATTERN
> (insn))"))
> +  (const_string "yes")
> +  (const_string "no")))
> -------------------------------------------------------------------------
> 
> Well, I suppose this OK for now, but it seems odd to be hiding the difference
> from the main patterns.  Don't we want IRA+reload to optimise for this
> where possible?  Or does that produce bad results?
> More below.
> 
> Rather than define lots of attributes, please just use [(cond ...)] to set the
> default directly:
> 
> (define_attr "umips_short_insn" "no, yes"
>   (cond [(and (eq_attr "type" "arith")
> 	      (not (eq_attr "mode" "DI"))
>  	      (match_test "umips_three_reg_match0 (PATTERN (insn))"))
> 	 (const_string "yes")
> 
> 	 ...]
> 	(const_string "no")))
> 
> -------------------------------------------------------------------------
> +(define_attr "umips_mfhi" "no, yes"
> +  (if_then_else (and (eq_attr "move_type" "mfhilo")
> +		     (match_operand 1 "gpr_operand" ""))
> +  (const_string "yes")
> +  (const_string "no")))
> -------------------------------------------------------------------------
> 
> Patch collision: as of a couple of days ago, we now have an "mfhi"
> "type" attribute.
> 
> -------------------------------------------------------------------------
> +(define_attr "umips_logicals" "no, yes"
> +  (if_then_else (and (ior (eq_attr "alu_type" "and")
> +			  (eq_attr "alu_type" "or")
> +			  (eq_attr "alu_type" "xor"))
> +		     (match_test "umips_three_reg_match0 (PATTERN
> (insn))"))
> +  (const_string "yes")
> +  (const_string "no")))
> -------------------------------------------------------------------------
> 
> (eq_attr "alu_type" "and,or,xor").
> 
> -------------------------------------------------------------------------
>  	  ;; Direct branch instructions have a range of [-0x20000,0x1fffc],
> -	  ;; relative to the address of the delay slot.  If a branch is
> -	  ;; outside this range, we have a choice of two sequences.
> +	  ;; relative to the address of the delay slot.
> +	  ;;
> +	  ;; For microMIPS the range is reduced to [-0x10000,0xfffe].
> +	  ;;
> +	  ;; If a branch is outside this range, we have a choice of two
> +	  ;; sequences.
> -------------------------------------------------------------------------
> 
> I'd prefer:
> -------------------------------------------------------------------------
> 	  ;; Direct microMIPS branch instructions have a range of
> 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
> 	  ;; If a branch is outside this range, we have a choice of two
> 	  ;; sequences.
> -------------------------------------------------------------------------
> 
> -------------------------------------------------------------------------
>  	  ;; pattern has no explicit delay slot, mips_adjust_insn_length
>  	  ;; will add the length of the implicit nop.  The values for
>  	  ;; forward and backward branches will be different as well.
> +
> -------------------------------------------------------------------------
> 
> Excess whitespace.
> 
> -------------------------------------------------------------------------
> +	  (eq_attr "type" "multimem")
> +	  (const_int 4)
> -------------------------------------------------------------------------
> 
> Not necessary, 4 is the default.
> 
> -------------------------------------------------------------------------
> +(define_insn "*branch_equality<mode>_micromips"
> +  [(set (pc)
> +	(if_then_else
> +	 (match_operator 1 "equality_operator"
> +			 [(match_operand:GPR 2 "register_operand" "d")
> +			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
> +	 (label_ref (match_operand 0 "" ""))
> +	 (pc)))]
> +  "TARGET_MICROMIPS"
> +{
> +  /* For a simple bnez or beqz microMIPS branch.  */
> +  if (!TARGET_BRANCHLIKELY
> +      && get_attr_length (insn) <= 8
> +      && GET_CODE (operands[3]) == CONST_INT
> +      && INTVAL (operands[3]) == 0)
> +    return mips_output_conditional_branch (insn, operands,
> +					   "%*b%C1z%:\t%2,%0",
> +					   "%*b%N1z%:\t%2,%0");
> +
> +  return mips_output_conditional_branch (insn, operands,
> +					 MIPS_BRANCH ("b%C1",
> "%2,%z3,%0"),
> +					 MIPS_BRANCH ("b%N1",
> "%2,%z3,%0")); }
> -------------------------------------------------------------------------
> 
> This:
> 
>       && GET_CODE (operands[3]) == CONST_INT
>       && INTVAL (operands[3]) == 0)
> 
> can just be:
> 
>       && operands[3] == const0_rtx)
> 
> Why the !TARGET_BRANCHLIKELY test?  You force it off anyway in
> mips_set_mips16_micromips_mode (which I agree is a good thing)
> 
> -------------------------------------------------------------------------
>  (define_insn "indirect_jump_<mode>"
>    [(set (pc) (match_operand:P 0 "register_operand" "d"))]
>    ""
> -  "%*j\t%0%/"
> +{
> +  if (TARGET_MICROMIPS)
> +    return "%*jr%:\t%0";
> +  else
> +    return "%*j\t%0%/";
> +}
> -------------------------------------------------------------------------
> 
> "jr" should be fine across the board.  Same later.
> 
> -------------------------------------------------------------------------
> +   microMIPS LWM and SWM support 12-bit offsets (from -2048 to 2047) and
> +   to preserve the maximum stack alignment, so 0x7f0 is used when
> +   TARGET_MICROMIPS.
> -------------------------------------------------------------------------
> 
> I'd prefer:
> 
> -------------------------------------------------------------------------
>    microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
>    so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
> -------------------------------------------------------------------------
> 
> (where the context already describes the alignment constraint).
> 
> -------------------------------------------------------------------------
> +static bool
> +mips_nocompression_decl_p (const_tree decl)
> +{
> +  if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
> +    return true;
> +
> +  return (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL
> +          && lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) !=
> NULL);
> +}
> ...
> +/* Similar predicates for "micromips"/"nomicromips" function attributes.  */
> +
> +static bool
> +mips_micromips_decl_p (const_tree decl)
> +{
> +  return lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL;
> +}
> +
> +static bool
> +mips_nomicromips_decl_p (const_tree decl)
> +{
> +  return lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) !=
> NULL;
> +}
> +
> +/* Return true if function DECL is a microMIPS function.  Return the ambient
> +   setting if DECL is null.  */
> +
> +static bool
> +mips_use_micromips_mode_p (tree decl)
> +{
> +  if (decl)
> +    {
> +      /* Nested functions must use the same frame pointer as their
> +	 parent and must therefore use the same ISA mode.  */
> +      tree parent = decl_function_context (decl);
> +      if (parent)
> +	decl = parent;
> +      if (mips_micromips_decl_p (decl))
> +	return true;
> +      if (mips_nomicromips_decl_p (decl))
> +	return false;
> +    }
> +  return mips_base_micromips;
> +}
> -------------------------------------------------------------------------
> 
> To reduce the cut-&-paste here and elsewhere, I think it would be
> better to have:
> 
> -------------------------------------------------------------------------
> unsigned int mips_base_compression_flags;
> -------------------------------------------------------------------------
> 
> to replace mips_base_mips16 & mips_base_micromips and:
> 
> -------------------------------------------------------------------------
> /* Return the set of compression modes that are explicitly required
>    by DECL.  */
> 
> static unsigned int
> mips_get_compress_on_flags (tree decl)
> {
>   unsigned int flags = 0;
> 
>   if (lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL)
>     flags |= MASK_MIPS16;
> 
>   if (lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL)
>     flags |= MASK_MICROMIPS;
> 
>   return flags;
> }
> 
> /* Return the set of compression modes that are explicitly forbidden
>    by DECL.  */
> 
> static unsigned int
> mips_get_compress_off_flags (tree decl)
> {
>   unsigned int flags = 0;
> 
>   if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
>     flags |= MASK_MIPS16 | MASK_MICROMIPS;
> 
>   if (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL)
>     flags |= MASK_MIPS16;
> 
>   if (lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL)
>     flags |= MASK_MICROMIPS;
> 
>   return flags;
> }
> 
> /* Return the compression mode that should be used for function DECL.
>    Return the ambient setting if DECL is null.  */
> 
> static unsigned int
> mips_get_compress_mode (tree decl)
> {
>   unsigned int flags, force_on;
> 
>   flags = mips_base_compression_flags;
>   if (decl)
>     {
>       /* Nested functions must use the same frame pointer as their
> 	 parent and must therefore use the same ISA mode.  */
>       tree parent = decl_function_context (decl);
>       if (parent)
> 	decl = parent;
>       force_on = mips_get_compression_on_flags (decl);
>       if (force_on)
>         return force_on;
>       flags &= ~mips_get_compression_off_flags (decl);
>     }
>   return flags;
> }
> 
> /* Return the name of the compression mode represented by target
>    flags FLAGS.  */
> 
> static const char *
> mips_get_compression_name (unsigned int flags)
> {
>   if (flags & TARGET_MIPS16)
>     return "mips16";
>   if (flags & TARGET_MICROMIPS)
>     return "micromips";
>   gcc_unreachable();
> }
> -------------------------------------------------------------------------
> 
> then use these instead of tests for individual mips16 or micromips
> attributes.
> 
> -------------------------------------------------------------------------
>      switch (addr.type)
>        {
>        case ADDRESS_REG:
> +
>  	if (TARGET_MIPS16
>  	    && !mips16_unextended_reference_p (mode, addr.reg,
>  					       UINTVAL (addr.offset)))
> -------------------------------------------------------------------------
> 
> Excess whitespace.
> 
> -------------------------------------------------------------------------
> +int
> +umips_address_insns (rtx x, enum machine_mode mode, bool
> might_split_p)
> +{
> +  struct mips_address_info addr;
> +  int factor;
> +
> +  /* BLKmode is used for single unaligned loads and stores and should
> +     not count as a multiword mode.  (GET_MODE_SIZE (BLKmode) is pretty
> +     meaningless, so we have to single it out as a special case one way
> +     or the other.)  */
> +  if (mode != BLKmode && might_split_p)
> +    factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) /
> UNITS_PER_WORD;
> +  else
> +    factor = 1;
> +
> +  if (mips_classify_address (&addr, x, mode, false))
> +    switch (addr.type)
> +      {
> +      case ADDRESS_REG:
> +	if (!CONST_INT_P (addr.offset)
> +	    || INTVAL (addr.offset) < -2048
> +	    || INTVAL (addr.offset) > 2047)
> +	  return 0;
> +
> +	return factor;
> +
> +      default:
> +	break;
> +
> +      }
> +  return 0;
> +}
> -------------------------------------------------------------------------
> 
> Function lacks a comment.  It's only use is for YC/YD, which always
> pass false for might_split_p, so this is really just a predicate
> that tests for 12-bit offset addresses.  So:
> 
> -------------------------------------------------------------------------
> /* Return true if X is a legimate address with a 12-bit offset.
>    MODE is the mode of the value being accessed.  */
> 
> bool
> umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
> {
>   struct mips_address_info addr;
> 
>   return (mips_classify_address (&addr, x, mode, false)
>   	  && addr.type == ADDRESS_REG
> 	  && CONST_INT_P (addr.offset)
> 	  && IN_RANGE (INTVAL (addr.offset), -2048, 2047));
> }
> -------------------------------------------------------------------------
> 
> Seems like you could reuse this elsewhere in places that also
> check for 12-bit offsets.
> 
> -------------------------------------------------------------------------
> +/* Return true if the insn has three micromips register operands.  */
> +int
> +umips_three_reg (rtx insn)
> +{
> +   rtx op0 = XEXP (insn, 0);
> +   rtx op1 = XEXP (insn, 1);
> +   rtx op2 = XEXP (insn, 2);
> +
> +   return (op0 != NULL_RTX
> +           && op1 != NULL_RTX
> +	   && op2 != NULL_RTX
> +	   && REG_P (op0)
> +	   && M16_REG_P (REGNO (op0))
> +	   && REG_P (op1)
> +	   && M16_REG_P (REGNO (op1))
> +	   && REG_P (op2)
> +	   && M16_REG_P (REGNO (op2)));
> +}
> -------------------------------------------------------------------------
> 
> This doesn't look right.  You pass in a complete PATTERN,
> so XEXP (insn, 1) will typically be the SET_SRC (such as a PLUS)
> and XEXP (insn, 2) usually isn't valid.
> 
> I think --enable-checking=yes,rtl would have tripped over the op2
> extraction and flagged it as a problem.  Could you use that option
> when testing the updated patch?
> 
> Same problem with the other predicates.
> 
> Please make the predicates return bool rather than int.
> 
> Like I said above, I'd really prefer to see the register requirements
> modelled in the patterns directly.  You could use the "enabled" to
> prevent the new alternatives from being used by non-MIPS16 code.
> 
> -------------------------------------------------------------------------
> +  if (TARGET_MICROMIPS)
> +    fprintf (asm_out_file, "\t.set\tmicromips\n");
> +  else
> +    fprintf (asm_out_file, "\t.set\tnomicromips\n");
> -------------------------------------------------------------------------
> 
> We need a configure test to see whether the assembler supports
> microMIPS.
> We shouldn't emit ".set\tnomicromips" if it doesn't.
> 
> -------------------------------------------------------------------------
> +      /* When reorder or noreorder with final_squence 0, the delay slot will
> +	 be a nop, so we just use the compact version for microMIPS.  */
> +      if (mips_noreorder.nesting_level == 0 || final_sequence == 0)
> +	putc ('c', file);
> -------------------------------------------------------------------------
> 
> Should just be "final_sequence == 0".  Same for '%!'.
> 
> -------------------------------------------------------------------------
> +static void mips_save_reg (rtx reg, rtx mem);
> -------------------------------------------------------------------------
> 
> Please move the functions around so that this isn't necessary.
> 
> -------------------------------------------------------------------------
> +/* Build microMIPS save or restore.  FN is save or restore function.
> +   OFFSET is the current stack offset.
> +   Return true if we succeed creating save or restore.  */
> -------------------------------------------------------------------------
> 
> /* Consider building a microMIPS LDM or STM for the current stack frame.
>    FN is mips_save_reg for stores or mips_restore_reg for loads.
>    OFFSET is the offset of the first register save slot from the
>    current stack pointer.
> 
>    Return true on success, in which case all GPRs will have been saved.  */
> 
> -------------------------------------------------------------------------
> +static bool
> +umips_build_save_restore (mips_save_restore_fn fn,
> +			      HOST_WIDE_INT offset)
> -------------------------------------------------------------------------
> 
> Odd formatting.
> 
> -------------------------------------------------------------------------
> +  unsigned int type[19] = {0x00010000, 0x00030000, 0x00070000, 0x000f0000,
> +			   0x001f0000, 0x003f0000, 0x007f0000, 0x00ff0000,
> +			   0x40ff0000, 0x80000000, 0x80010000, 0x80030000,
> +			   0x80070000, 0x800f0000, 0x801f0000, 0x803f0000,
> +			   0x807f0000, 0x80ff0000, 0xc0ff0000};
> +  unsigned int encode[19] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19,
> +			     20, 21, 22, 23, 24, 25};
> -------------------------------------------------------------------------
> 
> Make these static const arrays.
> 
> -------------------------------------------------------------------------
> +  /* Try matching $16 to $31 (s0 to ra).  */
> +  for (i = 0; i < 19; i++)
> +    if ((cfun->machine->frame.mask & 0xffff0000) == type[i])
> +      break;
> -------------------------------------------------------------------------
> 
> ARRAY_SIZE (type) instead of 19 (here and elsewhere).
> 
> -------------------------------------------------------------------------
> +  /* For only one register, we use normal sw/lw for speed.  */
> +  if (i == 0 || i == 9)
> +    return false;
> -------------------------------------------------------------------------
> 
> Seems easier to drop these two elements from the array (with a comment).
> 
> -------------------------------------------------------------------------
> +  /* For $31 to $24.  */
> +  if (i < 8 && (cfun->machine->frame.mask & 0xff000000))
> +    {
> +      int regno;
> +      for (regno = GP_REG_LAST; regno > GP_REG_LAST - 8; regno--)
> +	if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> +	  {
> +	    mips_save_restore_reg (word_mode, regno, offset, fn);
> +	    offset -= UNITS_PER_WORD;
> +	  }
> +    }
> -------------------------------------------------------------------------
> 
> Rather than this, please just use:
> 
> -------------------------------------------------------------------------
>   extra_regs = (cfun->machine->frame.mask & ~type[i]);
>   for (regno = GP_REG_LAST; regno > GP_REG_LAST - 8; regno--)
>     if (BITSET_P (extra_regs, regno - GP_REG_FIRST))
>       {
> 	mips_save_restore_reg (word_mode, regno, offset, fn);
> 	offset -= UNITS_PER_WORD;
>       }
> -------------------------------------------------------------------------
> 
> -------------------------------------------------------------------------
> +      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base,
> +			   this_offset + j * UNITS_PER_WORD));
> -------------------------------------------------------------------------
> 
> Nonstandard formatting.  Might be easiest to split out the offset calculation.
> 
> -------------------------------------------------------------------------
> @@ -10050,6 +10434,13 @@ mips_for_each_saved_gpr_and_fpr
> (HOST_WIDE_INT sp_
>       need a nop in the epilogue if at least one register is reloaded in
>       addition to return address.  */
>    offset = cfun->machine->frame.gp_sp_offset - sp_offset;
> +
> +  if (TARGET_MICROMIPS)
> +    {
> +      if (umips_build_save_restore (fn, offset))
> +	goto save_restore_fp_reg;
> +    }
> +
>    for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
>      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
>        {
> @@ -10060,6 +10451,8 @@ mips_for_each_saved_gpr_and_fpr
> (HOST_WIDE_INT sp_
>  	offset -= UNITS_PER_WORD;
>        }
> 
> +save_restore_fp_reg:
> +
>    /* This loop must iterate over the same space as its companion in
>       mips_compute_frame_info.  */
>    offset = cfun->machine->frame.fp_sp_offset - sp_offset;
> -------------------------------------------------------------------------
> 
> No!!! :-)  Just wrap the GPR save in:
> 
>   if (!(TARGET_MICROMIPS && umips_build_save_restore (fn, offset)))
> 
> Please also split out the save loop, since we now have three copies of it.
> 
> -------------------------------------------------------------------------
>  static void
> -mips_deallocate_stack (rtx base, rtx offset, HOST_WIDE_INT
> new_frame_size)
> +mips_deallocate_stack (rtx base, rtx offset, HOST_WIDE_INT
> new_frame_size,
> +                       bool use_jraddiusp_p)
>  {
> +  if (use_jraddiusp_p)
> +    return;
> +
>    if (base == stack_pointer_rtx && offset == const0_rtx)
>      return;
> 
>    mips_frame_barrier ();
> +
> -------------------------------------------------------------------------
> 
> Seems odd to add a parameter that causes the function to return instantly.
> But...
> 
> -------------------------------------------------------------------------
>    const struct mips_frame_info *frame;
>    HOST_WIDE_INT step1, step2;
>    rtx base, adjust, insn;
> +  bool use_jraddiusp_p = false;
> 
>    if (!sibcall_p && mips_can_use_return_insn ())
>      {
> @@ -10831,7 +11230,7 @@ mips_expand_epilogue (bool sibcall_p)
>        mips_emit_move (MIPS_EPILOGUE_TEMP (Pmode), adjust);
>        adjust = MIPS_EPILOGUE_TEMP (Pmode);
>      }
> -  mips_deallocate_stack (base, adjust, step2);
> +  mips_deallocate_stack (base, adjust, step2, use_jraddiusp_p);
> 
>    /* If we're using addressing macros, $gp is implicitly used by all
>       SYMBOL_REFs.  We must emit a blockage insn before restoring $gp
> @@ -10900,7 +11299,8 @@ mips_expand_epilogue (bool sibcall_p)
> 
>  	  /* If we don't use shoadow register set, we need to update SP.  */
>  	  if (!cfun->machine->use_shadow_register_set_p)
> -	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
> +	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2),
> +				   0, use_jraddiusp_p);
>  	  else
>  	    /* The choice of position is somewhat arbitrary in this case.  */
>  	    mips_epilogue_emit_cfa_restores ();
> @@ -10911,9 +11311,11 @@ mips_expand_epilogue (bool sibcall_p)
>  	}
>        else
>  	/* Deallocate the final bit of the frame.  */
> -	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
> +	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2),
> +			       0, use_jraddiusp_p);
>      }
> -  gcc_assert (!mips_epilogue.cfa_restores);
> +  if (!use_jraddiusp_p)
> +    gcc_assert (!mips_epilogue.cfa_restores);
> 
>    /* Add in the __builtin_eh_return stack adjustment.  We need to
>       use a temporary in MIPS16 code.  */
> @@ -10963,6 +11365,10 @@ mips_expand_epilogue (bool sibcall_p)
>  	      rtx reg = gen_rtx_REG (Pmode, GP_REG_FIRST + 7);
>  	      pat = gen_return_internal (reg);
>  	    }
> +	  else if (use_jraddiusp_p)
> +	    {
> +	      pat = gen_mips_jraddiusp (GEN_INT (step2));
> +	    }
>  	  else
>  	    {
>  	      rtx reg = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
> -------------------------------------------------------------------------
> 
> ...unless I'm missing something, it never gets set anyway.
> 
> -------------------------------------------------------------------------
>  static void
>  mips_set_current_function (tree fndecl)
>  {
> -  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
> +  mips_set_mips16_micromips_mode (mips_use_mips16_mode_p (fndecl),
> +				  mips_use_micromips_mode_p (fndecl));
> +
> +  /* Override the default setting for function alignment once it is decided
> +     which mode is in force.  */
> +
> +  if (fndecl
> +      && TARGET_MICROMIPS
> +      && optimize_size
> +      && ! TARGET_INTERLINK_MIPS16
> +      && lookup_attribute ("aligned", DECL_ATTRIBUTES (fndecl)) == NULL)
> +    DECL_ALIGN (fndecl) = 16;
>  }
> -------------------------------------------------------------------------
> 
> Looks like the wrong place to do this.  Please treat this as a separate
> patch and get a tree expert to comment.
> 
> -------------------------------------------------------------------------
> +/* Return true if PATTERN matches the kind of instruction generated by
> +   micromips_build_save_restore.  SAVE_P is true for store.  */
> +
> +bool
> +umips_save_restore_pattern_p (bool save_p, rtx pattern)
> +{
> +  int n;
> +  HOST_WIDE_INT first_offset = 0;
> +  rtx first_base = 0;
> +  unsigned int first_regno = 0;
> +
> +  for (n = 0; n < XVECLEN (pattern, 0); n++)
> +    {
> +      rtx set, reg, mem, this_base;
> +      HOST_WIDE_INT this_offset;
> +      unsigned int this_regno;
> +
> +      /* Check that we have a SET.  */
> +      set = XVECEXP (pattern, 0, n);
> +      if (GET_CODE (set) != SET)
> +	return false;
> +
> +      /* Check that the SET is a load (if restoring) or a store
> +	 (if saving).  */
> +      mem = save_p ? SET_DEST (set) : SET_SRC (set);
> +      if (!MEM_P (mem))
> +	return false;
> +
> +      /* Check that the address is the sum of base and a
> +	 possibly-zero constant offset.  */
> +      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
> +      if (!REG_P (this_base))
> +	return false;
> +
> +      if (n == 0)
> +	{
> +	  first_base = this_base;
> +	  first_offset = this_offset;
> -------------------------------------------------------------------------
> 
> Need to check the offset is in range.
> 
> -------------------------------------------------------------------------
> +      /* Make sure the order of regno is "$16-$23, $30, $31", "$16-$23, $30",
> +	 or "$31".  */
> +      this_regno = REGNO (reg);
> +      if (n == 0)
> +	{
> +	  if (this_regno != 16 && this_regno != 31)
> +	    return false;
> +	  first_regno = this_regno;
> +	}
> +      else if (n == 8) /* For s8.  */
> +	{
> +	  if (n == XVECLEN (pattern, 0) - 1)
> +	    {
> +	      if (this_regno != 30 && this_regno != 31)
> +		return false;
> +	    }
> +	  else
> +	    {
> +	      if (this_regno != 30)
> +		return false;
> +	    }
> +	}
> +      else if (n != XVECLEN (pattern, 0) - 1)
> +	{
> +	  if (this_regno != first_regno + n)
> +	    return false;
> +	}
> +      else /* The last item.  */
> +	{
> +	  if ((this_regno != first_regno + n) && this_regno != 31)
> +	    return false;
> +	}
> -------------------------------------------------------------------------
> 
> Please just build a mask of the registers and check it against the
> same array as the build function.
> 
> -------------------------------------------------------------------------
> +      /* If any item in the list is volatile then disallow.  This is a
> +         safeguard only as this is a path unlikely to be exercised since
> +         typical code only generates the instructions for stack accesses.  */
> +      if (MEM_VOLATILE_P (mem))
> +        return false;
> -------------------------------------------------------------------------
> 
> Please add this to the earlier !MEM_P check, i.e.:
> 
> -------------------------------------------------------------------------
>       if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
> 	return false;
> -------------------------------------------------------------------------
> 
> -------------------------------------------------------------------------
> +/* Return the assembly instruction for microMIPS lwm or swm.
> +   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
> +
> +const char *
> +umips_output_save_restore (bool save_p, rtx pattern)
> +{
> +  static char buffer[300];
> +  char *s;
> +  int n;
> +  HOST_WIDE_INT offset;
> +  rtx base, mem, set, reg, last_set, last_reg;
> +
> +  /* Parse the pattern.  */
> +  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
> -------------------------------------------------------------------------
> 
> Would be nice to have a shared subroutine of this and
> umips_save_restore_pattern_p that returns the type/encoding index
> (or -1 if none).  That'd make this function easier to write.
> 
> -------------------------------------------------------------------------
> +  mem1_temp = XEXP (mem1, 0);
> +  mem2_temp = XEXP (mem2, 0);
> +
> +  /* Make sure memory is base plus offset.  */
> +  if (GET_CODE (mem1_temp) != PLUS
> +      || GET_CODE (mem2_temp) != PLUS
> +      || GET_CODE (XEXP (mem1_temp, 1)) != CONST_INT
> +      || GET_CODE (XEXP (mem2_temp, 1)) != CONST_INT)
> +    return false;
> +
> +  mips_split_plus (mem1_temp, &base1, &offset1);
> +  mips_split_plus (mem2_temp, &base2, &offset2);
> +
> +  if (!REG_P (base1) || !REG_P (base2))
> +    return false;
> +
> +  if (REGNO (base1) != REGNO (base2))
> +    return false;
> -------------------------------------------------------------------------
> 
> Better as:
> 
> -------------------------------------------------------------------------
>   mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
>   mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
>   if (!REG_P (base1) || !rtx_equal_p (base1, base2))
>     return false;
> -------------------------------------------------------------------------
> 
> Note that this allows cases where mem1 or mem2 are unoffsetted registers,
> which should always be (reg) rather than (plus (reg) (const_int 0)).
> 
> -------------------------------------------------------------------------
> +/* Return the assembly instruction for microMIPS lwp or swp.
> +   LOAD_P is true for load.  */
> +
> +const char *
> +umips_output_load_store_pair (bool load_p, rtx reg, rtx mem)
> +{
> +  static char buffer[300];
> +  HOST_WIDE_INT offset;
> +  rtx base;
> +
> +  gcc_assert (REG_P (reg) && MEM_P (mem));
> +
> +  mips_split_plus (XEXP (mem, 0), &base, &offset);
> +  gcc_assert (REG_P (base));
> +
> +  sprintf (buffer, "%s\t%s,%d(%s)", load_p ? "lwp" : "swp",
> +	   reg_names [REGNO (reg)], (int) offset, reg_names [REGNO
> (base)]);
> +  return buffer;
> +}
> -------------------------------------------------------------------------
> 
> Instead use output_asm_insn and return "".  This allows you to use
> the normal assembly formatting.
> 
> -------------------------------------------------------------------------
> +  int match[8] = {0x00000060,	/* 5, 6 */
> +		  0x000000a0,	/* 5, 7 */
> +		  0x000000c0,	/* 6, 7 */
> +		  0x00200010,	/* 4, 21 */
> +		  0x00400010,	/* 4, 22 */
> +		  0x00000030,	/* 4, 5 */
> +		  0x00000050,	/* 4, 6 */
> +		  0x00000090};	/* 4, 7 */
> -------------------------------------------------------------------------
> 
> static const.
> 
> -------------------------------------------------------------------------
> +  for (i = 0; i < 8; i++)
> +    {
> +      if (pair == match[i])
> +	return true;
> +    }
> -------------------------------------------------------------------------
> 
> ARRAY_SIZE (match) instead of 8.
> 
> -------------------------------------------------------------------------
> +/* True if this constant is valid for the microMIPS andi16 insn.  */
> +#define UMIPS_ANDI16_IMM(VALUE)	\
> +  (((unsigned HOST_WIDE_INT) (VALUE) == 1)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 2)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 3)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 4)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 7)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 8)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 15)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 16)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 31)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 32)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 63)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 64)		\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 255)	\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 32768)	\
> +    || ((unsigned HOST_WIDE_INT) (VALUE) == 65536))
> -------------------------------------------------------------------------
> 
> These casts look redundant.
> 
> Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-01-22 20:23     ` Moore, Catherine
@ 2013-01-22 20:27       ` Moore, Catherine
  2013-01-23 20:05         ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-01-22 20:27 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej, Moore, Catherine

[-- Attachment #1: Type: text/plain, Size: 57530 bytes --]

And this time with the patches attached... Sorry

> -----Original Message-----
> From: Moore, Catherine
> Sent: Tuesday, January 22, 2013 3:25 PM
> To: Richard Sandiford
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej; Moore, Catherine
> Subject: RE: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> Hi Richard,
> I hope that I have addressed all of your comments in this cleaned up patch.
> There are a couple of items that have been omitted that I plan to submit as
> follow-on patches.  The use of jraddiusp and the use of short delay slots have
> both been deferred.  You had suggested a function named
> mips_get_compression_name but I did not see where this was used.  It's
> been omitted for now.   I cleaned up most of the gcc.target/mips tests for
> microMIPS, but some of the MIPS16-specific tests will fail.  It looks like an
> overhaul of mips.exp may be required and that is beyond the scope of this
> patch.
> Let me know what you think.  I'll submit the optimizations once the base
> patch is approved.
> Thanks,
> Catherine
> 
> > -----Original Message-----
> > From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> > Sent: Thursday, July 19, 2012 8:46 PM
> > To: Moore, Catherine
> > Cc: gcc-patches@gcc.gnu.org
> > Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> >
> > "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> > > Forgot to copy the list ...
> >
> > Same with my reply...
> >
> > > Here is the updated microMIPS patch.  It's been a very long time (two
> > > years!) since I posted the original.  Please let me know what we're
> > > going to need to do to get this committed.
> >
> > This is looking better.  At least that huge if statement in
> > mips_adjust_insn_length (IIRC) is gone :-)
> >
> > -------------------------------------------------------------------------
> >  @itemx -mno-interlink-mips16
> >  @opindex minterlink-mips16
> >  @opindex mno-interlink-mips16
> > -Require (do not require) that non-MIPS16 code be link-compatible with
> > -MIPS16 code.
> > +Require (do not require) that non-MIPS16/non-microMIPS code be
> > +link-compatible with MIPS16/microMIPS code.
> >
> > -For example, non-MIPS16 code cannot jump directly to MIPS16 code;
> > +For example, non-MIPS16/non-microMIPS code cannot jump directly to
> > +MIPS16/microMIPS code;
> >  it must either use a call or an indirect jump.  @option{-minterlink-mips16}
> > therefore disables direct jumps unless GCC knows that the target of the -
> > jump is not MIPS16.
> > +jump is not MIPS16/non microMIPS.
> > -------------------------------------------------------------------------
> >
> > This doesn't read very well.  Let's add a -minterlink-compressed option and
> > treat -mno-interlink-mips16 as an alias of it.  So:
> >
> > -------------------------------------------------------------------------
> > @item -minterlink-compressed
> > @itemx -mno-interlink-compressed
> > @opindex minterlink-compressed
> > @opindex mno-interlink-compressed
> > Require (do not require) that code using the standard (uncompressed)
> MIPS
> > ISA be link-compatible with MIPS16 and microMIPS code.
> >
> > For example, non-MIPS16 code cannot jump directly to MIPS16 code; it
> must
> > either use a call or an indirect jump.  The same applies to non-microMIPS
> > jumps to microMIPS code.  @option{-minterlink-compressed} therefore
> > disables direct jumps unless GCC knows that the target of the jump is not
> > compressed.
> >
> > @item -minterlink-mips16
> > @itemx -mno-interlink-mips16
> > @opindex minterlink-mips16
> > @opindex mno-interlink-mips16
> > Aliases of @option{-minterlink-compressed} and @option{-mno-interlink-
> > compressed}.  These options predate the mipsMIPS ASE and are retained
> for
> > backwards compatiblity.
> > -------------------------------------------------------------------------
> >
> > Let's also make TARGET_INTERLINK_COMPRESSED the internal name.
> >
> > -------------------------------------------------------------------------
> > +@item -mmicromips
> > +@itemx -mno-micromips
> > +@opindex mmicromips
> > +@opindex mno-mmicromips
> > +Generate (do not generate) microMIPS code.  If GCC is targetting a
> > +MIPS32 or MIPS64 architecture, it will make use of the microMIPS ASE@.
> > -------------------------------------------------------------------------
> >
> > Looks like excess cut-&-paste from the MIPS16 version.  The point of the
> > MIPS16 documentation is to distinguish between the original MIPS16 "ASE"
> > and MIPS16e.  There's no such distinction here.
> >
> > -------------------------------------------------------------------------
> > +@item -mjals
> > +@itemx -mno-jals
> > +@opindex mjals
> > +@opindex mno-jals
> > +Generate (do not generate) the @code{jals} instruction for microMIPS by
> > +recognizing that the branch delay slot instruction can be 16 bits.
> > +This implies that the funciton call cannot switch the current mode
> > +during the linking stage, because we don't have the @code{jalxs}
> > +instruction that supports 16-bit branch delay slot instructions.
> > -------------------------------------------------------------------------
> >
> > typo: function
> >
> > The assumption we're making seems to be that calls from microMIPS code
> > cannot go to non-microMIPS code.  If so, let's make that the option instead.
> > The above is too low-level.
> >
> > With analogy to -minterlink-compressed, the option could be -minterlink-
> > uncompressed/-mno-interlink-uncompressed, with the default being -
> > minterlink-uncompressed.
> >
> > -------------------------------------------------------------------------
> > +@item YC
> > +For MIPS, it is the same as the constraint @code{R}.  For microMIPS, it
> > +matches an address within a 12-bit offset that can be used for
> > +microMIPS @code{ll}, @code{sc}, etc.
> > +
> > +@item YD
> > +For MIPS, it is the same as the constraint @code{p}  For microMIPS, it
> > +matches a 12-bit offsest address.
> > +
> > +@item YE
> > +A singler register memory operand.
> > -------------------------------------------------------------------------
> >
> > "For MIPS" is a bit vague (it actually applies to MIPS16 too).
> > So how about:
> >
> > -------------------------------------------------------------------------
> > @item YC
> > when compiling microMIPS code, this constraint matches a memory
> operand
> > whose address is formed from a base register and a 12-bit offset.
> > These operands can be used for microMIPS instructions such as @code{ll}
> > and @code{sc}.  When not compiling for microMIPS code, @code{YC} is
> > equivalent to @code{R}.
> >
> > @item YD
> > when compiling microMIPS code, this constraint matches an address
> operand
> > that is formed from a base register and a 12-bit offset.
> > These operands can be used for microMIPS instructions such as
> > @code{prefetch}.
> > When not compiling for microMIPS code, @code{YC} is equivalent to
> > @code{p}.
> > -------------------------------------------------------------------------
> >
> > No need for "YE": we have "ZR" now.  I'd like to make the other constraints
> > "Z" rather than "Y" too -- ZC and ZD -- since "Y" is really for constants.
> >
> > -------------------------------------------------------------------------
> > +(define_insn "*store_word_multiple"
> > +  [(match_parallel 0 ""
> > +       [(set (match_operand:SI 1 "memory_operand")
> > +	     (match_operand:SI 2 "register_operand"))])]
> > +  "TARGET_MICROMIPS
> > +   && umips_save_restore_pattern_p (true, operands[0])"
> > +  {
> > +    return umips_output_save_restore (true, operands[0]);
> > +  }
> > +  [(set_attr "type" "multimem")
> > +   (set_attr "mode" "SI")
> > +   (set_attr "can_delay" "no")])
> > -------------------------------------------------------------------------
> >
> > Nitlet: local style is to use "{ return ...; }" for single-line statements and
> > column-0 placement of "{" and "}" for multi-line ones.  Same for rest of file.
> >
> > -------------------------------------------------------------------------
> > +; For lwp
> > +(define_peephole2
> > +  [(set (match_operand:SI 0 "umips_lwp_register" "")
> > +        (match_operand:SI 1 "non_volatile_mem_operand" ""))
> > +   (set (match_operand:SI 2 "umips_lwp_register" "")
> > +        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
> > +  "TARGET_MICROMIPS
> > +   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
> > +	&& umips_load_store_pair_p (true, false, operands[0],
> > +				    operands[1], operands[3]))
> > +       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
> > +	   && umips_load_store_pair_p (true, true, operands[2],
> > +				       operands[3], operands[1])))"
> > +  [(parallel [(set (match_dup 0) (match_dup 1))
> > +              (set (match_dup 2) (match_dup 3))])]
> > -------------------------------------------------------------------------
> >
> > Please split out this:
> >
> >    && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
> > 	&& umips_load_store_pair_p (true, false, operands[0],
> > 				    operands[1], operands[3]))
> >        || (REGNO (operands[2]) + 1 == REGNO (operands[0])
> > 	   && umips_load_store_pair_p (true, true, operands[2],
> > 				       operands[3], operands[1])))
> >
> > into a function:
> >
> > bool
> > umips_load_store_pair_p (bool load_p, rtx reg1, rtx reg2, rtx mem1, rtx
> > mem2)
> >
> > with the current umips_load_store_pair_p being a subroutine
> > (umips_load_store_pair_p_1).
> >
> > -------------------------------------------------------------------------
> > +(define_insn "*lwp"
> > +  [(parallel [(set (match_operand:SI 0 "umips_lwp_register")
> > +		   (match_operand:SI 1 "memory_operand"))
> > +	      (set (match_operand:SI 2 "umips_lwp_register")
> > +		   (match_operand:SI 3 "memory_operand"))])]
> > +
> > +  "TARGET_MICROMIPS
> > +   && ((REGNO (operands[0]) + 1 == REGNO (operands[2])
> > +	&& umips_load_store_pair_p (true, false, operands[0],
> > +				    operands[1], operands[3]))
> > +       || (REGNO (operands[2]) + 1 == REGNO (operands[0])
> > +	   && umips_load_store_pair_p (true, true, operands[2],
> > +				       operands[3], operands[1])))"
> > +  {
> > +    if (REGNO (operands[0]) + 1 == REGNO (operands[2]))
> > +      return umips_output_load_store_pair (true, operands[0],
> operands[1]);
> > +    else
> > +      return umips_output_load_store_pair (true, operands[2],
> > +operands[3]);
> > +  }
> > +  [(set_attr "type" "load")
> > +   (set_attr "mode" "SI")
> > +   (set_attr "can_delay" "no")])
> > -------------------------------------------------------------------------
> >
> > Same with the output:
> >
> > void
> > umips_output_load_store_pair (bool load_p, rtx reg1, rtx reg2,
> > 			      rtx mem1, rtx mem2)
> >
> > Why do only the stores require non_volatile_mem_operand?  It looks like
> > you could be reordering loads from volatile memory otherwise.
> >
> > -------------------------------------------------------------------------
> > +; For jraddiusp
> > +(define_insn "mips_jraddiusp"
> > +  [(parallel [(return)
> > +              (use (reg:SI 31))
> > +	      (set (reg:SI 29)
> > +		   (plus:SI (reg:SI 29)
> > +			    (match_operand 0 "const_int_operand")))])]
> > +  "TARGET_MICROMIPS"
> > +  "jraddiusp\t%0"
> > +  [(set_attr "type" "trap")
> > +   (set_attr "mode" "SI")
> > +   (set_attr "can_delay" "no")])
> > -------------------------------------------------------------------------
> >
> > Redundant comment.
> >
> > -------------------------------------------------------------------------
> > +; For movep
> > +(define_peephole2
> > +  [(set (match_operand:SI 0 "register_operand" "")
> > +        (match_operand:SI 1 "movep_si_operand" ""))
> > +   (set (match_operand:SI 2 "register_operand" "")
> > +        (match_operand:SI 3 "movep_si_operand" ""))]
> > +  "TARGET_MICROMIPS
> > +   && umips_movep_target_p (operands[0], operands[2])"
> > +  [(parallel [(set (match_dup 0) (match_dup 1))
> > +              (set (match_dup 2) (match_dup 3))])]
> > +)
> > +
> > +(define_peephole2
> > +  [(set (match_operand:SI 0 "register_operand" "")
> > +        (match_operand:SI 1 "movep_si_operand" ""))
> > +   (set (match_operand:SF 2 "register_operand" "")
> > +        (match_operand:SF 3 "const_0_sf_operand" ""))]
> > +  "TARGET_MICROMIPS
> > +   && umips_movep_target_p (operands[0], operands[2])"
> > +  [(parallel [(set (match_dup 0) (match_dup 1))
> > +              (set (match_dup 2) (match_dup 3))])]
> > +)
> > +
> > +(define_peephole2
> > +  [(set (match_operand:SF 0 "register_operand" "")
> > +        (match_operand:SF 1 "const_0_sf_operand" ""))
> > +   (set (match_operand:SI 2 "register_operand" "")
> > +        (match_operand:SI 3 "movep_si_operand" ""))]
> > +  "TARGET_MICROMIPS
> > +   && umips_movep_target_p (operands[0], operands[2])"
> > +  [(parallel [(set (match_dup 0) (match_dup 1))
> > +              (set (match_dup 2) (match_dup 3))])]
> > +)
> > +
> > +(define_peephole2
> > +  [(set (match_operand:SF 0 "register_operand" "")
> > +        (match_operand:SF 1 "const_0_sf_operand" ""))
> > +   (set (match_operand:SF 2 "register_operand" "")
> > +        (match_operand:SF 3 "const_0_sf_operand" ""))]
> > +  "TARGET_MICROMIPS
> > +   && umips_movep_target_p (operands[0], operands[2])"
> > +  [(parallel [(set (match_dup 0) (match_dup 1))
> > +              (set (match_dup 2) (match_dup 3))])]
> > +)
> > +
> > +(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
> > +  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
> > +		   (match_operand:MOVEP1 1
> > "movep_<MOVEP1:mode>_operand"))
> > +	      (set (match_operand:MOVEP2 2 "register_operand")
> > +		   (match_operand:MOVEP2 3
> > "movep_<MOVEP2:mode>_operand"))])]
> > +  "TARGET_MICROMIPS
> > +   && umips_movep_target_p (operands[0], operands[2])"
> > +{
> > +  if (REGNO (operands[0]) < REGNO (operands[2]))
> > +    return "movep\t%0,%2,%z1,%z3";
> > +  else
> > +    return "movep\t%2,%0,%z3,%z1";
> > +}
> > +  [(set_attr "type" "move")
> > +   (set_attr "mode" "<MODE>")
> > +   (set_attr "can_delay" "no")])
> > -------------------------------------------------------------------------
> >
> > Seems to be a mismatch between the peepholes (which only accept 0.0f
> for
> > SFmode) and the insn (which allows registers too).  Can't you use MOVEP1
> > and MOVEP2 for the peepholes too?
> >
> > -------------------------------------------------------------------------
> >  (define_memory_constraint "R"
> >    "An address that can be used in a non-macro load or store."
> >    (and (match_code "mem")
> > -       (match_test "mips_address_insns (XEXP (op, 0), mode, false) == 1")))
> > +       (match_test "mips_address_insns (XEXP (op, 0), mode, false)")))
> > -------------------------------------------------------------------------
> >
> > No, this defeats the purpose of "R", which is supposed to disallow address
> > that require assembly macros.
> >
> > -------------------------------------------------------------------------
> > +(define_memory_constraint "YC"
> > +  "For MIPS, it is the same as the constraint R.  For microMIPS, it matches
> > +   an address within a 12-bit offset that can be used in ll, sc, etc."
> > +  (and (match_code "mem")
> > +       (ior (and (match_test "TARGET_MICROMIPS")
> > +		 (match_test "umips_address_insns (XEXP (op, 0), mode,
> > false)"))
> > +	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
> > +
> > +(define_address_constraint "YD"
> > +  "@internal
> > +   For MIPS, it is the same as the constraint p.  For microMIPS, it matches
> > +   a 12-bit offset address."
> > +   (ior (and (match_test "TARGET_MICROMIPS")
> > +	     (match_test "umips_address_insns (op, mode, false)"))
> > +	(match_test "mips_address_insns (op, mode, false)")))
> > -------------------------------------------------------------------------
> >
> > Is YD internal or not?  We should remove it from the docs if so, otherwise
> the
> > @internal is wrong.
> >
> > Please keep the doc strings exactly the same as the .texi version (including
> @
> > mark-up).  I think the idea was that at some glorious time in the future,
> we'd
> > be able to auto-generate the .texi parts from the .md doc strings.
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "gpr_operand"
> > +  (and (match_code "reg")
> > +       (match_test "GP_REG_P (REGNO (op))")))
> > -------------------------------------------------------------------------
> >
> > This is d_operand.
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "umips_register"
> > +  (and (match_code "reg")
> > +       (match_test "M16_REG_P (REGNO (op))")))
> > -------------------------------------------------------------------------
> >
> > I think I'd prefer to call the predicate m16_register too, for consistency.
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "umips_andi16_operand"
> > +  (and (match_code "const")
> > +       (match_test "UMIPS_ANDI16_IMM (INTVAL (op))")))
> > -------------------------------------------------------------------------
> >
> > Looks like this should be "const_int" instead.  Same for the other constants.
> > It seems on face value like some parts of the patch weren't exercised
> > because of this.
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "umips_add_uimm5"
> > +  (and (match_code "const")
> > +       (match_test "IN_RANGE (INTVAL (op), -8, 7)")))
> > -------------------------------------------------------------------------
> >
> > Looks like a signed rather than unsigned immediate.  Should this be
> > "umips_add_imm5" instead?
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "umips_addiur2_imm3"
> > +  (and (match_code "const")
> > +       (ior (match_test "INTVAL(op) == 1")
> > +       (ior (match_test "INTVAL(op) == 4")
> > +       (ior (match_test "INTVAL(op) == 8")
> > +       (ior (match_test "INTVAL(op) == 12")
> > +       (ior (match_test "INTVAL(op) == 16")
> > +       (ior (match_test "INTVAL(op) == 20")
> > +       (ior (match_test "INTVAL(op) == 24")
> > +	    (match_test "INTVAL(op) == -1"))))))))))
> > -------------------------------------------------------------------------
> >
> > (ior ...) can take any number of operands these days, so no need for all
> those
> > ")"s.  Space after INTVAL.
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "umips_lw16_memref"
> > +  (and (match_code "plus")
> > +       (match_operand 0 "umips_register" "")) {
> > +  rtx op2 = XEXP (op, 1);
> > +
> > +  return (GET_CODE (op2) == CONST_INT
> > +          && ((INTVAL (op2) & 3) == 0)
> > +	  && (IN_RANGE (INTVAL (op2), 0, 60)));
> > +})
> > -------------------------------------------------------------------------
> >
> > This tests an address, whereas it sounds from the name (and looks from
> the
> > later code) like it's supposed to be testing a (mem ...) instead.
> > Also:
> >
> >  (and (match_code "plus")
> >       (match_operand 0 "umips_register" ""))
> >
> > tests for something that is both a PLUS and a REG, which is never true.
> > ((match_operand X ...) doesn't test XEXP (..., X).)
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "const_0_si_operand"
> > +  (and (match_code "const_int,const_double,const_vector")
> > +       (match_test "op == CONST0_RTX (SImode)")))
> > +
> > +(define_predicate "const_0_sf_operand"
> > +  (and (match_code "const_int,const_double,const_vector")
> > +       (match_test "op == CONST0_RTX (SFmode)")))
> > -------------------------------------------------------------------------
> >
> > Should be redundant with const_0_operand.  Modes should be checked at
> > the match_operand level where important.
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "movep_si_operand"
> > +  (ior (and (match_code "const_int,const_double,const_vector")
> > +	    (match_test "op == CONST0_RTX (SImode)"))
> > +       (and (match_code "reg")
> > +	    (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
> > +		 (match_test ("IN_RANGE (REGNO (op), 16, 20)"))))))
> > +
> > +(define_predicate "movep_sf_operand"
> > +  (ior (and (match_code "const_int, const_double, const_vector")
> > +	    (match_test "op == CONST0_RTX (SFmode)"))
> > +       (and (match_code "reg")
> > +	    (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
> > +		 (match_test ("IN_RANGE (REGNO (op), 16, 20)"))))))
> > -------------------------------------------------------------------------
> >
> > These two should be combined:
> >
> > -------------------------------------------------------------------------
> > (define_predicate "movep_register"
> >   (and (match_code "reg")
> >        (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
> > 	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
> >
> > (define_predicate "movep_operand"
> >   (ior (match_operand 0 "const_0_operand")
> >        (match_operand 0 "movep_register")))
> > -------------------------------------------------------------------------
> >
> > -------------------------------------------------------------------------
> > +(define_predicate "umips_lwp_register"
> > +  (and (match_code "reg")
> > +       (match_test "REGNO (op) <= GP_REG_LAST")))
> > -------------------------------------------------------------------------
> >
> > Reundant with d_operand/gpr_operand?
> >
> > -------------------------------------------------------------------------
> > +;; Return 1 if the operand is in non-volatile memory.  Note that during
> > +the ;; RTL generation phase, memory_operand does not return TRUE for
> > +volatile ;; memory references.  So this function allows us to recognize
> > +volatile ;; references where it's safe.
> > +(define_predicate "non_volatile_mem_operand"
> > +  (not (and (and (match_code "mem")
> > +          (match_test "MEM_VOLATILE_P (op)"))
> > +       (if_then_else (match_test "reload_completed")
> > +         (match_operand 0 "memory_operand")
> > +         (if_then_else (match_test "reload_in_progress")
> > +         (match_test "strict_memory_address_p (mode, XEXP (op, 0))")
> > +         (match_test "memory_address_p (mode, XEXP (op, 0))"))))))
> > -------------------------------------------------------------------------
> >
> > This looks wrong: the whole thing is wrapped in (not ...), so it matches
> > something that specifically _isn't_ a memory_operand.  All that reload stuff
> > shouldn't be needed, plain:
> >
> > (define_predicate "non_volatile_mem_operand"
> >   (and (match_operand 0 "memory_operand")
> >        (not (match_test "MEM_VOLATILE_P (op)"))))
> >
> > should be OK.
> >
> > -------------------------------------------------------------------------
> > +(define_attr "umips_not" "no, yes"
> > +  (if_then_else (and (eq_attr "alu_type" "not")
> > +		     (match_test "umips_two_reg (PATTERN (insn))"))
> > +  (const_string "yes")
> > +  (const_string "no")))
> > -------------------------------------------------------------------------
> >
> > Looks odd: reg-to-reg is the only possiblity for "not".
> > Should be enough to test "alu_type" against "not" directly and drop this
> > attribute.
> >
> > -------------------------------------------------------------------------
> > +(define_attr "umips_arith" "no, yes"
> > +  (if_then_else (and (eq_attr "type" "arith")
> > +		     (not (eq_attr "mode" "DI"))
> > +		     (match_test "umips_three_reg_match0 (PATTERN
> > (insn))"))
> > +  (const_string "yes")
> > +  (const_string "no")))
> > -------------------------------------------------------------------------
> >
> > Well, I suppose this OK for now, but it seems odd to be hiding the
> difference
> > from the main patterns.  Don't we want IRA+reload to optimise for this
> > where possible?  Or does that produce bad results?
> > More below.
> >
> > Rather than define lots of attributes, please just use [(cond ...)] to set the
> > default directly:
> >
> > (define_attr "umips_short_insn" "no, yes"
> >   (cond [(and (eq_attr "type" "arith")
> > 	      (not (eq_attr "mode" "DI"))
> >  	      (match_test "umips_three_reg_match0 (PATTERN (insn))"))
> > 	 (const_string "yes")
> >
> > 	 ...]
> > 	(const_string "no")))
> >
> > -------------------------------------------------------------------------
> > +(define_attr "umips_mfhi" "no, yes"
> > +  (if_then_else (and (eq_attr "move_type" "mfhilo")
> > +		     (match_operand 1 "gpr_operand" ""))
> > +  (const_string "yes")
> > +  (const_string "no")))
> > -------------------------------------------------------------------------
> >
> > Patch collision: as of a couple of days ago, we now have an "mfhi"
> > "type" attribute.
> >
> > -------------------------------------------------------------------------
> > +(define_attr "umips_logicals" "no, yes"
> > +  (if_then_else (and (ior (eq_attr "alu_type" "and")
> > +			  (eq_attr "alu_type" "or")
> > +			  (eq_attr "alu_type" "xor"))
> > +		     (match_test "umips_three_reg_match0 (PATTERN
> > (insn))"))
> > +  (const_string "yes")
> > +  (const_string "no")))
> > -------------------------------------------------------------------------
> >
> > (eq_attr "alu_type" "and,or,xor").
> >
> > -------------------------------------------------------------------------
> >  	  ;; Direct branch instructions have a range of [-0x20000,0x1fffc],
> > -	  ;; relative to the address of the delay slot.  If a branch is
> > -	  ;; outside this range, we have a choice of two sequences.
> > +	  ;; relative to the address of the delay slot.
> > +	  ;;
> > +	  ;; For microMIPS the range is reduced to [-0x10000,0xfffe].
> > +	  ;;
> > +	  ;; If a branch is outside this range, we have a choice of two
> > +	  ;; sequences.
> > -------------------------------------------------------------------------
> >
> > I'd prefer:
> > -------------------------------------------------------------------------
> > 	  ;; Direct microMIPS branch instructions have a range of
> > 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
> > 	  ;; If a branch is outside this range, we have a choice of two
> > 	  ;; sequences.
> > -------------------------------------------------------------------------
> >
> > -------------------------------------------------------------------------
> >  	  ;; pattern has no explicit delay slot, mips_adjust_insn_length
> >  	  ;; will add the length of the implicit nop.  The values for
> >  	  ;; forward and backward branches will be different as well.
> > +
> > -------------------------------------------------------------------------
> >
> > Excess whitespace.
> >
> > -------------------------------------------------------------------------
> > +	  (eq_attr "type" "multimem")
> > +	  (const_int 4)
> > -------------------------------------------------------------------------
> >
> > Not necessary, 4 is the default.
> >
> > -------------------------------------------------------------------------
> > +(define_insn "*branch_equality<mode>_micromips"
> > +  [(set (pc)
> > +	(if_then_else
> > +	 (match_operator 1 "equality_operator"
> > +			 [(match_operand:GPR 2 "register_operand" "d")
> > +			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
> > +	 (label_ref (match_operand 0 "" ""))
> > +	 (pc)))]
> > +  "TARGET_MICROMIPS"
> > +{
> > +  /* For a simple bnez or beqz microMIPS branch.  */
> > +  if (!TARGET_BRANCHLIKELY
> > +      && get_attr_length (insn) <= 8
> > +      && GET_CODE (operands[3]) == CONST_INT
> > +      && INTVAL (operands[3]) == 0)
> > +    return mips_output_conditional_branch (insn, operands,
> > +					   "%*b%C1z%:\t%2,%0",
> > +					   "%*b%N1z%:\t%2,%0");
> > +
> > +  return mips_output_conditional_branch (insn, operands,
> > +					 MIPS_BRANCH ("b%C1",
> > "%2,%z3,%0"),
> > +					 MIPS_BRANCH ("b%N1",
> > "%2,%z3,%0")); }
> > -------------------------------------------------------------------------
> >
> > This:
> >
> >       && GET_CODE (operands[3]) == CONST_INT
> >       && INTVAL (operands[3]) == 0)
> >
> > can just be:
> >
> >       && operands[3] == const0_rtx)
> >
> > Why the !TARGET_BRANCHLIKELY test?  You force it off anyway in
> > mips_set_mips16_micromips_mode (which I agree is a good thing)
> >
> > -------------------------------------------------------------------------
> >  (define_insn "indirect_jump_<mode>"
> >    [(set (pc) (match_operand:P 0 "register_operand" "d"))]
> >    ""
> > -  "%*j\t%0%/"
> > +{
> > +  if (TARGET_MICROMIPS)
> > +    return "%*jr%:\t%0";
> > +  else
> > +    return "%*j\t%0%/";
> > +}
> > -------------------------------------------------------------------------
> >
> > "jr" should be fine across the board.  Same later.
> >
> > -------------------------------------------------------------------------
> > +   microMIPS LWM and SWM support 12-bit offsets (from -2048 to 2047)
> and
> > +   to preserve the maximum stack alignment, so 0x7f0 is used when
> > +   TARGET_MICROMIPS.
> > -------------------------------------------------------------------------
> >
> > I'd prefer:
> >
> > -------------------------------------------------------------------------
> >    microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
> >    so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
> > -------------------------------------------------------------------------
> >
> > (where the context already describes the alignment constraint).
> >
> > -------------------------------------------------------------------------
> > +static bool
> > +mips_nocompression_decl_p (const_tree decl)
> > +{
> > +  if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) !=
> NULL)
> > +    return true;
> > +
> > +  return (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL
> > +          && lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) !=
> > NULL);
> > +}
> > ...
> > +/* Similar predicates for "micromips"/"nomicromips" function attributes.
> */
> > +
> > +static bool
> > +mips_micromips_decl_p (const_tree decl)
> > +{
> > +  return lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) !=
> NULL;
> > +}
> > +
> > +static bool
> > +mips_nomicromips_decl_p (const_tree decl)
> > +{
> > +  return lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) !=
> > NULL;
> > +}
> > +
> > +/* Return true if function DECL is a microMIPS function.  Return the
> ambient
> > +   setting if DECL is null.  */
> > +
> > +static bool
> > +mips_use_micromips_mode_p (tree decl)
> > +{
> > +  if (decl)
> > +    {
> > +      /* Nested functions must use the same frame pointer as their
> > +	 parent and must therefore use the same ISA mode.  */
> > +      tree parent = decl_function_context (decl);
> > +      if (parent)
> > +	decl = parent;
> > +      if (mips_micromips_decl_p (decl))
> > +	return true;
> > +      if (mips_nomicromips_decl_p (decl))
> > +	return false;
> > +    }
> > +  return mips_base_micromips;
> > +}
> > -------------------------------------------------------------------------
> >
> > To reduce the cut-&-paste here and elsewhere, I think it would be
> > better to have:
> >
> > -------------------------------------------------------------------------
> > unsigned int mips_base_compression_flags;
> > -------------------------------------------------------------------------
> >
> > to replace mips_base_mips16 & mips_base_micromips and:
> >
> > -------------------------------------------------------------------------
> > /* Return the set of compression modes that are explicitly required
> >    by DECL.  */
> >
> > static unsigned int
> > mips_get_compress_on_flags (tree decl)
> > {
> >   unsigned int flags = 0;
> >
> >   if (lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL)
> >     flags |= MASK_MIPS16;
> >
> >   if (lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL)
> >     flags |= MASK_MICROMIPS;
> >
> >   return flags;
> > }
> >
> > /* Return the set of compression modes that are explicitly forbidden
> >    by DECL.  */
> >
> > static unsigned int
> > mips_get_compress_off_flags (tree decl)
> > {
> >   unsigned int flags = 0;
> >
> >   if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
> >     flags |= MASK_MIPS16 | MASK_MICROMIPS;
> >
> >   if (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL)
> >     flags |= MASK_MIPS16;
> >
> >   if (lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL)
> >     flags |= MASK_MICROMIPS;
> >
> >   return flags;
> > }
> >
> > /* Return the compression mode that should be used for function DECL.
> >    Return the ambient setting if DECL is null.  */
> >
> > static unsigned int
> > mips_get_compress_mode (tree decl)
> > {
> >   unsigned int flags, force_on;
> >
> >   flags = mips_base_compression_flags;
> >   if (decl)
> >     {
> >       /* Nested functions must use the same frame pointer as their
> > 	 parent and must therefore use the same ISA mode.  */
> >       tree parent = decl_function_context (decl);
> >       if (parent)
> > 	decl = parent;
> >       force_on = mips_get_compression_on_flags (decl);
> >       if (force_on)
> >         return force_on;
> >       flags &= ~mips_get_compression_off_flags (decl);
> >     }
> >   return flags;
> > }
> >
> > /* Return the name of the compression mode represented by target
> >    flags FLAGS.  */
> >
> > static const char *
> > mips_get_compression_name (unsigned int flags)
> > {
> >   if (flags & TARGET_MIPS16)
> >     return "mips16";
> >   if (flags & TARGET_MICROMIPS)
> >     return "micromips";
> >   gcc_unreachable();
> > }
> > -------------------------------------------------------------------------
> >
> > then use these instead of tests for individual mips16 or micromips
> > attributes.
> >
> > -------------------------------------------------------------------------
> >      switch (addr.type)
> >        {
> >        case ADDRESS_REG:
> > +
> >  	if (TARGET_MIPS16
> >  	    && !mips16_unextended_reference_p (mode, addr.reg,
> >  					       UINTVAL (addr.offset)))
> > -------------------------------------------------------------------------
> >
> > Excess whitespace.
> >
> > -------------------------------------------------------------------------
> > +int
> > +umips_address_insns (rtx x, enum machine_mode mode, bool
> > might_split_p)
> > +{
> > +  struct mips_address_info addr;
> > +  int factor;
> > +
> > +  /* BLKmode is used for single unaligned loads and stores and should
> > +     not count as a multiword mode.  (GET_MODE_SIZE (BLKmode) is pretty
> > +     meaningless, so we have to single it out as a special case one way
> > +     or the other.)  */
> > +  if (mode != BLKmode && might_split_p)
> > +    factor = (GET_MODE_SIZE (mode) + UNITS_PER_WORD - 1) /
> > UNITS_PER_WORD;
> > +  else
> > +    factor = 1;
> > +
> > +  if (mips_classify_address (&addr, x, mode, false))
> > +    switch (addr.type)
> > +      {
> > +      case ADDRESS_REG:
> > +	if (!CONST_INT_P (addr.offset)
> > +	    || INTVAL (addr.offset) < -2048
> > +	    || INTVAL (addr.offset) > 2047)
> > +	  return 0;
> > +
> > +	return factor;
> > +
> > +      default:
> > +	break;
> > +
> > +      }
> > +  return 0;
> > +}
> > -------------------------------------------------------------------------
> >
> > Function lacks a comment.  It's only use is for YC/YD, which always
> > pass false for might_split_p, so this is really just a predicate
> > that tests for 12-bit offset addresses.  So:
> >
> > -------------------------------------------------------------------------
> > /* Return true if X is a legimate address with a 12-bit offset.
> >    MODE is the mode of the value being accessed.  */
> >
> > bool
> > umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
> > {
> >   struct mips_address_info addr;
> >
> >   return (mips_classify_address (&addr, x, mode, false)
> >   	  && addr.type == ADDRESS_REG
> > 	  && CONST_INT_P (addr.offset)
> > 	  && IN_RANGE (INTVAL (addr.offset), -2048, 2047));
> > }
> > -------------------------------------------------------------------------
> >
> > Seems like you could reuse this elsewhere in places that also
> > check for 12-bit offsets.
> >
> > -------------------------------------------------------------------------
> > +/* Return true if the insn has three micromips register operands.  */
> > +int
> > +umips_three_reg (rtx insn)
> > +{
> > +   rtx op0 = XEXP (insn, 0);
> > +   rtx op1 = XEXP (insn, 1);
> > +   rtx op2 = XEXP (insn, 2);
> > +
> > +   return (op0 != NULL_RTX
> > +           && op1 != NULL_RTX
> > +	   && op2 != NULL_RTX
> > +	   && REG_P (op0)
> > +	   && M16_REG_P (REGNO (op0))
> > +	   && REG_P (op1)
> > +	   && M16_REG_P (REGNO (op1))
> > +	   && REG_P (op2)
> > +	   && M16_REG_P (REGNO (op2)));
> > +}
> > -------------------------------------------------------------------------
> >
> > This doesn't look right.  You pass in a complete PATTERN,
> > so XEXP (insn, 1) will typically be the SET_SRC (such as a PLUS)
> > and XEXP (insn, 2) usually isn't valid.
> >
> > I think --enable-checking=yes,rtl would have tripped over the op2
> > extraction and flagged it as a problem.  Could you use that option
> > when testing the updated patch?
> >
> > Same problem with the other predicates.
> >
> > Please make the predicates return bool rather than int.
> >
> > Like I said above, I'd really prefer to see the register requirements
> > modelled in the patterns directly.  You could use the "enabled" to
> > prevent the new alternatives from being used by non-MIPS16 code.
> >
> > -------------------------------------------------------------------------
> > +  if (TARGET_MICROMIPS)
> > +    fprintf (asm_out_file, "\t.set\tmicromips\n");
> > +  else
> > +    fprintf (asm_out_file, "\t.set\tnomicromips\n");
> > -------------------------------------------------------------------------
> >
> > We need a configure test to see whether the assembler supports
> > microMIPS.
> > We shouldn't emit ".set\tnomicromips" if it doesn't.
> >
> > -------------------------------------------------------------------------
> > +      /* When reorder or noreorder with final_squence 0, the delay slot will
> > +	 be a nop, so we just use the compact version for microMIPS.  */
> > +      if (mips_noreorder.nesting_level == 0 || final_sequence == 0)
> > +	putc ('c', file);
> > -------------------------------------------------------------------------
> >
> > Should just be "final_sequence == 0".  Same for '%!'.
> >
> > -------------------------------------------------------------------------
> > +static void mips_save_reg (rtx reg, rtx mem);
> > -------------------------------------------------------------------------
> >
> > Please move the functions around so that this isn't necessary.
> >
> > -------------------------------------------------------------------------
> > +/* Build microMIPS save or restore.  FN is save or restore function.
> > +   OFFSET is the current stack offset.
> > +   Return true if we succeed creating save or restore.  */
> > -------------------------------------------------------------------------
> >
> > /* Consider building a microMIPS LDM or STM for the current stack frame.
> >    FN is mips_save_reg for stores or mips_restore_reg for loads.
> >    OFFSET is the offset of the first register save slot from the
> >    current stack pointer.
> >
> >    Return true on success, in which case all GPRs will have been saved.  */
> >
> > -------------------------------------------------------------------------
> > +static bool
> > +umips_build_save_restore (mips_save_restore_fn fn,
> > +			      HOST_WIDE_INT offset)
> > -------------------------------------------------------------------------
> >
> > Odd formatting.
> >
> > -------------------------------------------------------------------------
> > +  unsigned int type[19] = {0x00010000, 0x00030000, 0x00070000,
> 0x000f0000,
> > +			   0x001f0000, 0x003f0000, 0x007f0000, 0x00ff0000,
> > +			   0x40ff0000, 0x80000000, 0x80010000, 0x80030000,
> > +			   0x80070000, 0x800f0000, 0x801f0000, 0x803f0000,
> > +			   0x807f0000, 0x80ff0000, 0xc0ff0000};
> > +  unsigned int encode[19] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17, 18, 19,
> > +			     20, 21, 22, 23, 24, 25};
> > -------------------------------------------------------------------------
> >
> > Make these static const arrays.
> >
> > -------------------------------------------------------------------------
> > +  /* Try matching $16 to $31 (s0 to ra).  */
> > +  for (i = 0; i < 19; i++)
> > +    if ((cfun->machine->frame.mask & 0xffff0000) == type[i])
> > +      break;
> > -------------------------------------------------------------------------
> >
> > ARRAY_SIZE (type) instead of 19 (here and elsewhere).
> >
> > -------------------------------------------------------------------------
> > +  /* For only one register, we use normal sw/lw for speed.  */
> > +  if (i == 0 || i == 9)
> > +    return false;
> > -------------------------------------------------------------------------
> >
> > Seems easier to drop these two elements from the array (with a
> comment).
> >
> > -------------------------------------------------------------------------
> > +  /* For $31 to $24.  */
> > +  if (i < 8 && (cfun->machine->frame.mask & 0xff000000))
> > +    {
> > +      int regno;
> > +      for (regno = GP_REG_LAST; regno > GP_REG_LAST - 8; regno--)
> > +	if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> > +	  {
> > +	    mips_save_restore_reg (word_mode, regno, offset, fn);
> > +	    offset -= UNITS_PER_WORD;
> > +	  }
> > +    }
> > -------------------------------------------------------------------------
> >
> > Rather than this, please just use:
> >
> > -------------------------------------------------------------------------
> >   extra_regs = (cfun->machine->frame.mask & ~type[i]);
> >   for (regno = GP_REG_LAST; regno > GP_REG_LAST - 8; regno--)
> >     if (BITSET_P (extra_regs, regno - GP_REG_FIRST))
> >       {
> > 	mips_save_restore_reg (word_mode, regno, offset, fn);
> > 	offset -= UNITS_PER_WORD;
> >       }
> > -------------------------------------------------------------------------
> >
> > -------------------------------------------------------------------------
> > +      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base,
> > +			   this_offset + j * UNITS_PER_WORD));
> > -------------------------------------------------------------------------
> >
> > Nonstandard formatting.  Might be easiest to split out the offset
> calculation.
> >
> > -------------------------------------------------------------------------
> > @@ -10050,6 +10434,13 @@ mips_for_each_saved_gpr_and_fpr
> > (HOST_WIDE_INT sp_
> >       need a nop in the epilogue if at least one register is reloaded in
> >       addition to return address.  */
> >    offset = cfun->machine->frame.gp_sp_offset - sp_offset;
> > +
> > +  if (TARGET_MICROMIPS)
> > +    {
> > +      if (umips_build_save_restore (fn, offset))
> > +	goto save_restore_fp_reg;
> > +    }
> > +
> >    for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
> >      if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> >        {
> > @@ -10060,6 +10451,8 @@ mips_for_each_saved_gpr_and_fpr
> > (HOST_WIDE_INT sp_
> >  	offset -= UNITS_PER_WORD;
> >        }
> >
> > +save_restore_fp_reg:
> > +
> >    /* This loop must iterate over the same space as its companion in
> >       mips_compute_frame_info.  */
> >    offset = cfun->machine->frame.fp_sp_offset - sp_offset;
> > -------------------------------------------------------------------------
> >
> > No!!! :-)  Just wrap the GPR save in:
> >
> >   if (!(TARGET_MICROMIPS && umips_build_save_restore (fn, offset)))
> >
> > Please also split out the save loop, since we now have three copies of it.
> >
> > -------------------------------------------------------------------------
> >  static void
> > -mips_deallocate_stack (rtx base, rtx offset, HOST_WIDE_INT
> > new_frame_size)
> > +mips_deallocate_stack (rtx base, rtx offset, HOST_WIDE_INT
> > new_frame_size,
> > +                       bool use_jraddiusp_p)
> >  {
> > +  if (use_jraddiusp_p)
> > +    return;
> > +
> >    if (base == stack_pointer_rtx && offset == const0_rtx)
> >      return;
> >
> >    mips_frame_barrier ();
> > +
> > -------------------------------------------------------------------------
> >
> > Seems odd to add a parameter that causes the function to return instantly.
> > But...
> >
> > -------------------------------------------------------------------------
> >    const struct mips_frame_info *frame;
> >    HOST_WIDE_INT step1, step2;
> >    rtx base, adjust, insn;
> > +  bool use_jraddiusp_p = false;
> >
> >    if (!sibcall_p && mips_can_use_return_insn ())
> >      {
> > @@ -10831,7 +11230,7 @@ mips_expand_epilogue (bool sibcall_p)
> >        mips_emit_move (MIPS_EPILOGUE_TEMP (Pmode), adjust);
> >        adjust = MIPS_EPILOGUE_TEMP (Pmode);
> >      }
> > -  mips_deallocate_stack (base, adjust, step2);
> > +  mips_deallocate_stack (base, adjust, step2, use_jraddiusp_p);
> >
> >    /* If we're using addressing macros, $gp is implicitly used by all
> >       SYMBOL_REFs.  We must emit a blockage insn before restoring $gp
> > @@ -10900,7 +11299,8 @@ mips_expand_epilogue (bool sibcall_p)
> >
> >  	  /* If we don't use shoadow register set, we need to update SP.  */
> >  	  if (!cfun->machine->use_shadow_register_set_p)
> > -	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
> > +	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2),
> > +				   0, use_jraddiusp_p);
> >  	  else
> >  	    /* The choice of position is somewhat arbitrary in this case.  */
> >  	    mips_epilogue_emit_cfa_restores ();
> > @@ -10911,9 +11311,11 @@ mips_expand_epilogue (bool sibcall_p)
> >  	}
> >        else
> >  	/* Deallocate the final bit of the frame.  */
> > -	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
> > +	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2),
> > +			       0, use_jraddiusp_p);
> >      }
> > -  gcc_assert (!mips_epilogue.cfa_restores);
> > +  if (!use_jraddiusp_p)
> > +    gcc_assert (!mips_epilogue.cfa_restores);
> >
> >    /* Add in the __builtin_eh_return stack adjustment.  We need to
> >       use a temporary in MIPS16 code.  */
> > @@ -10963,6 +11365,10 @@ mips_expand_epilogue (bool sibcall_p)
> >  	      rtx reg = gen_rtx_REG (Pmode, GP_REG_FIRST + 7);
> >  	      pat = gen_return_internal (reg);
> >  	    }
> > +	  else if (use_jraddiusp_p)
> > +	    {
> > +	      pat = gen_mips_jraddiusp (GEN_INT (step2));
> > +	    }
> >  	  else
> >  	    {
> >  	      rtx reg = gen_rtx_REG (Pmode, RETURN_ADDR_REGNUM);
> > -------------------------------------------------------------------------
> >
> > ...unless I'm missing something, it never gets set anyway.
> >
> > -------------------------------------------------------------------------
> >  static void
> >  mips_set_current_function (tree fndecl)
> >  {
> > -  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
> > +  mips_set_mips16_micromips_mode (mips_use_mips16_mode_p
> (fndecl),
> > +				  mips_use_micromips_mode_p (fndecl));
> > +
> > +  /* Override the default setting for function alignment once it is decided
> > +     which mode is in force.  */
> > +
> > +  if (fndecl
> > +      && TARGET_MICROMIPS
> > +      && optimize_size
> > +      && ! TARGET_INTERLINK_MIPS16
> > +      && lookup_attribute ("aligned", DECL_ATTRIBUTES (fndecl)) == NULL)
> > +    DECL_ALIGN (fndecl) = 16;
> >  }
> > -------------------------------------------------------------------------
> >
> > Looks like the wrong place to do this.  Please treat this as a separate
> > patch and get a tree expert to comment.
> >
> > -------------------------------------------------------------------------
> > +/* Return true if PATTERN matches the kind of instruction generated by
> > +   micromips_build_save_restore.  SAVE_P is true for store.  */
> > +
> > +bool
> > +umips_save_restore_pattern_p (bool save_p, rtx pattern)
> > +{
> > +  int n;
> > +  HOST_WIDE_INT first_offset = 0;
> > +  rtx first_base = 0;
> > +  unsigned int first_regno = 0;
> > +
> > +  for (n = 0; n < XVECLEN (pattern, 0); n++)
> > +    {
> > +      rtx set, reg, mem, this_base;
> > +      HOST_WIDE_INT this_offset;
> > +      unsigned int this_regno;
> > +
> > +      /* Check that we have a SET.  */
> > +      set = XVECEXP (pattern, 0, n);
> > +      if (GET_CODE (set) != SET)
> > +	return false;
> > +
> > +      /* Check that the SET is a load (if restoring) or a store
> > +	 (if saving).  */
> > +      mem = save_p ? SET_DEST (set) : SET_SRC (set);
> > +      if (!MEM_P (mem))
> > +	return false;
> > +
> > +      /* Check that the address is the sum of base and a
> > +	 possibly-zero constant offset.  */
> > +      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
> > +      if (!REG_P (this_base))
> > +	return false;
> > +
> > +      if (n == 0)
> > +	{
> > +	  first_base = this_base;
> > +	  first_offset = this_offset;
> > -------------------------------------------------------------------------
> >
> > Need to check the offset is in range.
> >
> > -------------------------------------------------------------------------
> > +      /* Make sure the order of regno is "$16-$23, $30, $31", "$16-$23, $30",
> > +	 or "$31".  */
> > +      this_regno = REGNO (reg);
> > +      if (n == 0)
> > +	{
> > +	  if (this_regno != 16 && this_regno != 31)
> > +	    return false;
> > +	  first_regno = this_regno;
> > +	}
> > +      else if (n == 8) /* For s8.  */
> > +	{
> > +	  if (n == XVECLEN (pattern, 0) - 1)
> > +	    {
> > +	      if (this_regno != 30 && this_regno != 31)
> > +		return false;
> > +	    }
> > +	  else
> > +	    {
> > +	      if (this_regno != 30)
> > +		return false;
> > +	    }
> > +	}
> > +      else if (n != XVECLEN (pattern, 0) - 1)
> > +	{
> > +	  if (this_regno != first_regno + n)
> > +	    return false;
> > +	}
> > +      else /* The last item.  */
> > +	{
> > +	  if ((this_regno != first_regno + n) && this_regno != 31)
> > +	    return false;
> > +	}
> > -------------------------------------------------------------------------
> >
> > Please just build a mask of the registers and check it against the
> > same array as the build function.
> >
> > -------------------------------------------------------------------------
> > +      /* If any item in the list is volatile then disallow.  This is a
> > +         safeguard only as this is a path unlikely to be exercised since
> > +         typical code only generates the instructions for stack accesses.  */
> > +      if (MEM_VOLATILE_P (mem))
> > +        return false;
> > -------------------------------------------------------------------------
> >
> > Please add this to the earlier !MEM_P check, i.e.:
> >
> > -------------------------------------------------------------------------
> >       if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
> > 	return false;
> > -------------------------------------------------------------------------
> >
> > -------------------------------------------------------------------------
> > +/* Return the assembly instruction for microMIPS lwm or swm.
> > +   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
> > +
> > +const char *
> > +umips_output_save_restore (bool save_p, rtx pattern)
> > +{
> > +  static char buffer[300];
> > +  char *s;
> > +  int n;
> > +  HOST_WIDE_INT offset;
> > +  rtx base, mem, set, reg, last_set, last_reg;
> > +
> > +  /* Parse the pattern.  */
> > +  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
> > -------------------------------------------------------------------------
> >
> > Would be nice to have a shared subroutine of this and
> > umips_save_restore_pattern_p that returns the type/encoding index
> > (or -1 if none).  That'd make this function easier to write.
> >
> > -------------------------------------------------------------------------
> > +  mem1_temp = XEXP (mem1, 0);
> > +  mem2_temp = XEXP (mem2, 0);
> > +
> > +  /* Make sure memory is base plus offset.  */
> > +  if (GET_CODE (mem1_temp) != PLUS
> > +      || GET_CODE (mem2_temp) != PLUS
> > +      || GET_CODE (XEXP (mem1_temp, 1)) != CONST_INT
> > +      || GET_CODE (XEXP (mem2_temp, 1)) != CONST_INT)
> > +    return false;
> > +
> > +  mips_split_plus (mem1_temp, &base1, &offset1);
> > +  mips_split_plus (mem2_temp, &base2, &offset2);
> > +
> > +  if (!REG_P (base1) || !REG_P (base2))
> > +    return false;
> > +
> > +  if (REGNO (base1) != REGNO (base2))
> > +    return false;
> > -------------------------------------------------------------------------
> >
> > Better as:
> >
> > -------------------------------------------------------------------------
> >   mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
> >   mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
> >   if (!REG_P (base1) || !rtx_equal_p (base1, base2))
> >     return false;
> > -------------------------------------------------------------------------
> >
> > Note that this allows cases where mem1 or mem2 are unoffsetted
> registers,
> > which should always be (reg) rather than (plus (reg) (const_int 0)).
> >
> > -------------------------------------------------------------------------
> > +/* Return the assembly instruction for microMIPS lwp or swp.
> > +   LOAD_P is true for load.  */
> > +
> > +const char *
> > +umips_output_load_store_pair (bool load_p, rtx reg, rtx mem)
> > +{
> > +  static char buffer[300];
> > +  HOST_WIDE_INT offset;
> > +  rtx base;
> > +
> > +  gcc_assert (REG_P (reg) && MEM_P (mem));
> > +
> > +  mips_split_plus (XEXP (mem, 0), &base, &offset);
> > +  gcc_assert (REG_P (base));
> > +
> > +  sprintf (buffer, "%s\t%s,%d(%s)", load_p ? "lwp" : "swp",
> > +	   reg_names [REGNO (reg)], (int) offset, reg_names [REGNO
> > (base)]);
> > +  return buffer;
> > +}
> > -------------------------------------------------------------------------
> >
> > Instead use output_asm_insn and return "".  This allows you to use
> > the normal assembly formatting.
> >
> > -------------------------------------------------------------------------
> > +  int match[8] = {0x00000060,	/* 5, 6 */
> > +		  0x000000a0,	/* 5, 7 */
> > +		  0x000000c0,	/* 6, 7 */
> > +		  0x00200010,	/* 4, 21 */
> > +		  0x00400010,	/* 4, 22 */
> > +		  0x00000030,	/* 4, 5 */
> > +		  0x00000050,	/* 4, 6 */
> > +		  0x00000090};	/* 4, 7 */
> > -------------------------------------------------------------------------
> >
> > static const.
> >
> > -------------------------------------------------------------------------
> > +  for (i = 0; i < 8; i++)
> > +    {
> > +      if (pair == match[i])
> > +	return true;
> > +    }
> > -------------------------------------------------------------------------
> >
> > ARRAY_SIZE (match) instead of 8.
> >
> > -------------------------------------------------------------------------
> > +/* True if this constant is valid for the microMIPS andi16 insn.  */
> > +#define UMIPS_ANDI16_IMM(VALUE)	\
> > +  (((unsigned HOST_WIDE_INT) (VALUE) == 1)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 2)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 3)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 4)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 7)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 8)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 15)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 16)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 31)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 32)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 63)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 64)		\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 255)	\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 32768)	\
> > +    || ((unsigned HOST_WIDE_INT) (VALUE) == 65536))
> > -------------------------------------------------------------------------
> >
> > These casts look redundant.
> >
> > Richard

[-- Attachment #2: libgcc.cl --]
[-- Type: application/octet-stream, Size: 296 bytes --]

2013-01-22  Catherine Moore  <clm@codesourcery.com>
	    Chao-ying Fu  <fu@mips.com>
	    Joseph Myers  <joseph@codesourcery.com>

	* config/mips/mips16.S:  Don't build for microMIPS.
	* config/mips/linux-unwind.h: Handle microMIPS frame.
	* config/mips/crtn.S (fini, init): New labels.


[-- Attachment #3: libgcc.patch --]
[-- Type: application/octet-stream, Size: 2154 bytes --]

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 195304)
+++ ChangeLog	(working copy)
@@ -1,3 +1,9 @@
+2013-01-22  Catherine Moore  <clm@codesourcery.com>
+
+	* config/mips/mips16.S:  Don't build for microMIPS.
+	* config/mips/linux-unwind.h: Handle microMIPS frame.
+	* config/mips/crtn.S (fini, init): New labels.
+
 2013-01-17  Yufeng Zhang  <yufeng.zhang@arm.com>
 
 	* config/aarch64/sync-cache.c (__aarch64_sync_cache_range): Cast the
Index: config/mips/mips16.S
===================================================================
--- config/mips/mips16.S	(revision 195304)
+++ config/mips/mips16.S	(working copy)
@@ -22,6 +22,10 @@
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#ifdef __mips_micromips
+  /* DO NOTHING */
+#else
+
 /* This file contains mips16 floating point support functions.  These
    functions are called by mips16 code to handle floating point when
    -msoft-float is not used.  They accept the arguments and return
@@ -719,3 +723,4 @@
 #endif /* !__mips_single_float */
 
 #endif
+#endif /* __mips_micromips */
Index: config/mips/linux-unwind.h
===================================================================
--- config/mips/linux-unwind.h	(revision 195304)
+++ config/mips/linux-unwind.h	(working copy)
@@ -52,6 +52,11 @@
   _Unwind_Ptr new_cfa, reg_offset;
   int i;
 
+  /* microMIPS frame; the kernel does not have microMIPS signal
+     frames.  */
+  if ((_Unwind_Ptr) pc & 3)
+    return _URC_END_OF_STACK;
+
   /* 24021061 li v0, 0x1061 (rt_sigreturn)*/
   /* 0000000c syscall    */
   /*    or */
Index: config/mips/crtn.S
===================================================================
--- config/mips/crtn.S	(revision 195304)
+++ config/mips/crtn.S	(working copy)
@@ -31,6 +31,7 @@
 #endif
 
 	.section .init,"ax",@progbits
+init:	
 #ifdef __mips64
 	ld      RA,40($sp)
 	daddu	$sp,$sp,48
@@ -41,6 +42,7 @@
 	j	RA
 
 	.section .fini,"ax",@progbits
+fini:	
 #ifdef	__mips64
 	ld	RA,40($sp)
 	daddu	$sp,$sp,48

[-- Attachment #4: gcc.cl --]
[-- Type: application/octet-stream, Size: 5657 bytes --]

2013-01-21  Catherine Moore  <clm@codesourcery.com>
	    Chao-ying Fu <fu@mips.com>
	    Maciej W. Rozycki  <macro@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>
	    Tom de Vries  <tom@codesourcery.com>
	    Nathan Sidwell <nathan@codesourcery.com>
	    Iain Sandoe  <iain@codesourcery.com>
	
	* configure.ac (gcc_cv_as_micromis): Check if linker
	* configure: Regenerate.
	* config.in: Regenerate.
	* doc/extend.texi: (micromips, nomicromips, nocompression):
	Document new function attributes. 
	* doc/invoke.texi (minterlink-compressed, mmicromips,
	minterlink-uncompressed, m14k, m14ke, m14kec): Document new
	options.
	(minterlink-mips16): Update documentation.
	* doc/md.texi (ZC, ZD): Document new constraints.
	supports the .set micromips directive.
	* config/mips/mips-tables.opt: Regenerate.
	* config/mips/gnu-user.h (SUBTARGET_OVERRIDE_OPTIONS): Set
	TARGET_INTERLINK_COMPRESSED.
	* config/mips/micromips.md: New file.
	* constraints.md (ZC, AD): New constraints.
	* config/mips/predicates.md (movep_register): New predicate.
	(movep_operand): New predicate.
	(non_volatile_mem_operand): New predicate.
	* config/mips/mips.md (multimem): New type.
	(length): Differentiate between 17-bit and 18-bit branch offsets.
	(MOVEP1, MOVEP2): New mode iterator.
 	(mov_<load>l): Use ZC constraint.
	(mov_<load>r): Likewise.
	(mov_<store>l): Likewise.
	(mov_<store>r): Likewise.
	(*branch_equality<mode>_micromips): New insn.
	(*branch_equality<mode>_inverted_micromips): New insn.
	(*branch_equality<mode>_inverted): Disable for microMIPS.
	(*branch_equality<mode>): Likewise.
	(*jump_absolute): microMIPS variant.
	(indirect_jump_<mode>): Likewise.
	(tablejump_<mode>): Likewise.
	(<optab>_internal): Likewise.
	(sibcall_internal): Likewise.
	(sibcall_value_internal): Likewise.
	(prefetch): Use constraint ZD.
	(micromips.md): Include.
	* config/mips/mips.opt (minterlink-compressed): New option.
	(minterlink-uncompressed): New option.
	(minterlink-mips16): Now an alias for minterlink-compressed.
	(mmicromips): New option.
	* config/mips/sync.md (sync_compare_and_swap<mode>): Use ZR constraint.
	(compare_and_swap_12): Likewise.
	(sync_add<mode>): Likewise.
	(sync_<optab>_12): Likewise.
	(sync_old_<optab>_12): Likewise.
	(sync_new_<optab>_12): Likewise.
	(sync_nand_12): Likewise.
	(sync_old_nand_12): Likewise.
	(sync_new_nand_12): Likewise.
	(sync_sub<mode>): Likewise.
	(sync_old_add<mode>): Likewise.
	(sync_old_sub<mode>): Likewise.
	(sync_new_add<mode>): Likewise.
	(sync_new_sub<mode>): Likewise.
	(sync_<optab><mode>): Likewise.
	(sync_old_<optab><mode>): Likewise.
	(sync_new_<optab><mode>): Likewise.
	(sync_nand<mode>): Likewise.
	(sync_old_nand<mode>): Likewise.
	(sync_new_nand<mode>): Likewise.
	(sync_lock_test_and_set<mode>): Likewise.
	(test_and_set_12): Likewise.
	(atomic_compare_and_swap<mode>): Likewise.
	(atomic_exchange<mode>_llsc): Likewise.
	(atomic_fetch_add<mode>_llsc): Likewise.
	* config/mips/mips-cpus.def (m14kc, m14k): New processors.
	* conifg/mips/mips-protos.h (umips_output_save_restore): New prototype.
	(umips_save_restore_pattern_p): Likewise.
	(umips_load_store_pair_p): Likewise.
	(umips_output_load_store_pair): Likewise.
	(umips_movep_target_p): Likewise.
	(umips_12bit_offset_address_p): Likewise.
	* config/mips/mips.c (MIPS_MAX_FIRST_STACK_STEP): Update for microMIPS.
	* config/arm/arm.md (UNSPEC_PROLOGUE_USE): Rename this...
	(UNSPEC_REGISTER_USE): ... to this.
	(mips_base_mips16): Rename this...
	(mips_base_compression_flags): ...to this. Update all uses.
	(mips_attribute_table): Add micromips, nomicromips and nocompression.
	(mips_mips16_decl_p): Delete.
	(mips_nomips16_decl_p): Delete.
 	(mips_get_compress_on_flags): New function.
	(mips_get_compress_off_flags): New function.
	(mips_get_compress_mode): New function.
	(mips_insert_attributes): Support multiple compression types.
	(mips_merge_decl_attributes): Likewise.
	(umips_12bit_offset_address_p): New function.
	(mips_start_function_definition): Emit .set micromips directive.
	(mips_function_ok_for_sibcall): Add microMIPS support.
	(mips_print_operand_punctuation): Support short delay slots and
	compact jumps.
	(mips_save_restore_reg): Rename this...
	(mips_save_restore_single_reg): ...to this.  Update callers.
	(mips_save_restore_registers): New function.
	(type, encode): New.
	(umips_build_save_restore): New function.
	(mips_for_each_saved_gpr_and_fpr): Add microMIPS support.
	(was_micromips_p): New.
	(mips_set_mips16_mode): Rename this...
	(mips_set_mips16_micromips_mode): ...to this.  Add microMIPS support.
	Update callers.
	(umips_save_restore_pattern_p): New function.
	(umips_output_save_restore): New function.
	(umips_load_store_pair_p_1): New function.
	(umips_load_store_pair_p): New function.
	(umips_output_load_store_pair_1): New function. (bool load_p, rtx reg, rtx mem)
	(umips_output_load_store_pair): New function.
	(umips_movep_target_p): New function.
	* config/mips/mips.h (TARGET_CPU_CPP_BUILTINS): Update macro
	to use new compression flags and to support microMIPS.
	(MIPS_ISA_LEVEL_SPEC): Add m14k processors.
	(MIPS_ARCH_FLOAT_SPEC): Likewise.
	(ISA_HAS_LWXS): Include TARGET_MICROMIPS.
	(ASM_SPEC): Support mmicromips and mno-micromips.
	(M16STORE_REG_P): New macro.
	(MIPS_CALL): Support TARGET_MICROMIPS.
	(MICROMIPS_J): New macro.
	(mips_base_mips16): Rename this...
	(mips_base_compression_flags): ...to this.
	(UMIPS_12BIT_OFFSET_P): New macro.
	* config/mips/t-sde: (MULTILIB_OPTIONS): Add microMIPS.
	(MULTILIB_DIRNAMES): Likewise.


[-- Attachment #5: gcc.patch --]
[-- Type: application/octet-stream, Size: 97823 bytes --]

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 195351)
+++ doc/extend.texi	(working copy)
@@ -3053,6 +3053,25 @@ not that within individual functions.  Mixed MIPS1
 may interact badly with some GCC extensions such as @code{__builtin_apply}
 (@pxref{Constructing Calls}).
 
+@item micromips/nomicromips
+@cindex @code{micromips} attribute
+@cindex @code{nomicromips} attribute
+
+On MIPS targets, you can use the @code{micromips} and @code{nomicromips}
+function attributes to locally select or turn off microMIPS code generation.
+A function with the @code{micromips} attribute is emitted as microMIPS code,
+while microMIPS code generation is disabled for functions with the
+@code{nomicromips} attribute.  These attributes override the
+@option{-mmicromips} and @option{-mno-micromips} options on the command line
+(@pxref{MIPS Options}).
+
+When compiling files containing mixed microMIPS and non-microMIPS code, the
+preprocessor symbol @code{__mips_micromips} reflects the setting on the
+command line,
+not that within individual functions.  Mixed microMIPS and non-microMIPS code
+may interact badly with some GCC extensions such as @code{__builtin_apply}
+(@pxref{Constructing Calls}).
+
 @item model (@var{model-name})
 @cindex function addressability on the M32R/D
 @cindex variable addressability on the IA-64
@@ -3155,6 +3174,13 @@ is an NMI handler.  The compiler generates functio
 exit sequences suitable for use in an NMI handler when this
 attribute is present.
 
+@item nocompression
+@cindex @code{nocompression} attribute
+On MIPS targets, you can use the @code{nocompression} function attribute
+to locally turn off MIPS16 and microMIPS code generation.  This attribute
+overrides the @option{-mips16} and @option{-mmicromips} options on the
+command line (@pxref{MIPS Options}).
+
 @item no_instrument_function
 @cindex @code{no_instrument_function} function attribute
 @opindex finstrument-functions
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 195351)
+++ doc/invoke.texi	(working copy)
@@ -739,6 +739,8 @@ Objective-C and Objective-C++ Dialects}.
 -mips1  -mips2  -mips3  -mips4  -mips32  -mips32r2 @gol
 -mips64  -mips64r2 @gol
 -mips16  -mno-mips16  -mflip-mips16 @gol
+-minterlink-compressed -mno-interlink-compressed @gol
+-minterlink-uncompressed -mno-interlink-uncompressed @gol
 -minterlink-mips16  -mno-interlink-mips16 @gol
 -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
@@ -746,6 +748,7 @@ Objective-C and Objective-C++ Dialects}.
 -mno-float -msingle-float  -mdouble-float  @gol
 -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -mmcu -mmno-mcu @gol
+-mmicromips -mno-micromips @gol
 -mfpu=@var{fpu-type} @gol
 -msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
@@ -15878,6 +15881,7 @@ The processor names are:
 @samp{1004kc}, @samp{1004kf2_1}, @samp{1004kf1_1},
 @samp{loongson2e}, @samp{loongson2f}, @samp{loongson3a},
 @samp{m4k},
+@samp{m14k}, @samp{m14ke}, @samp{m14kec},
 @samp{octeon}, @samp{octeon+}, @samp{octeon2},
 @samp{orion},
 @samp{r2000}, @samp{r3000}, @samp{r3900}, @samp{r4000}, @samp{r4400},
@@ -15991,18 +15995,33 @@ Generate MIPS16 code on alternating functions.  Th
 for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
 not intended for ordinary use in compiling user code.
 
+@item -minterlink-compressed
+@item -mno-interlink-compressed
+@opindex minterlink-compressed
+@opindex mno-interlink-compressed
+Require (do not require) that code using the standard (uncompressed) MIPS ISA
+be link-compatible with MIPS16 and microMIPS code.
+
+For example, non-MIPS16 code cannot jump directly to MIPS16 code; it must
+either use a call or an indirect jump.  The same applies to non-microMIPS
+jumps to microMIPS code.  @option{-minterlink-compressed} therefore disables
+direct jumps unless GCC knows that the target of the jump is not compressed.
+
+@item -minterlink-uncompressed
+@item -mno-interlink-uncompressed
+@opindex minterlink-compressed
+@opindex mno-interlink-compressed
+Require (do not require) that code using microMIPS instructions be
+link-compatible with the standard (uncompressed) MIPS ISA.
+
 @item -minterlink-mips16
 @itemx -mno-interlink-mips16
 @opindex minterlink-mips16
 @opindex mno-interlink-mips16
-Require (do not require) that non-MIPS16 code be link-compatible with
-MIPS16 code.
+Aliases of @option{-minterlink-compressed} and
+@option{-mno-interlink-compressed}.  These options predate the microMIPS ASE
+and are retained for backwards compatiblity.
 
-For example, non-MIPS16 code cannot jump directly to MIPS16 code;
-it must either use a call or an indirect jump.  @option{-minterlink-mips16}
-therefore disables direct jumps unless GCC knows that the target of the
-jump is not MIPS16.
-
 @item -mabi=32
 @itemx -mabi=o64
 @itemx -mabi=n32
@@ -16216,6 +16235,16 @@ hardware floating-point support to be enabled.
 Use (do not use) the MIPS-3D ASE@.  @xref{MIPS-3D Built-in Functions}.
 The option @option{-mips3d} implies @option{-mpaired-single}.
 
+@item -mmicromips
+@itemx -mno-micromips
+@opindex mmicromips
+@opindex mno-mmicromips
+Generate (do not generate) microMIPS code.
+
+MicroMIPS code generation can also be controlled on a per-function basis
+by means of @code{micromips} and @code{nomicromips} attributes.
+@xref{Function Attributes}, for more information.
+
 @item -mmt
 @itemx -mno-mt
 @opindex mmt
Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 195351)
+++ doc/md.texi	(working copy)
@@ -2916,6 +2916,19 @@ Floating-point zero.
 
 @item R
 An address that can be used in a non-macro load or store.
+
+@item ZC
+When compiling microMIPS code, this constraing matches a memory operand
+whose address is formed from a base register and a 12-bit offset.  These
+operands can be used for microMIPS instructions such as @code{ll} and
+@code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+equivalent to @code{R}.
+
+@item ZD
+When compiling microMIPS code, this constraint matches an address operand
+that is formed from a base register and a 12-bit offset.  These operands
+can be used for microMIPS instructions such as @code{prefetch}.  When
+not compiling for microMIPS code, @code{YC} is equivalent to @code{p}.
 @end table
 
 @item Motorola 680x0---@file{config/m68k/constraints.md}
Index: configure
===================================================================
--- configure	(revision 195351)
+++ configure	(working copy)
@@ -25666,6 +25666,37 @@ $as_echo "#define HAVE_AS_GNU_ATTRIBUTE 1" >>confd
 
 fi
 
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .micromips support" >&5
+$as_echo_n "checking assembler for .micromips support... " >&6; }
+if test "${gcc_cv_as_micromips_support+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_micromips_support=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '.set micromips' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_micromips_support=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_micromips_support" >&5
+$as_echo "$gcc_cv_as_micromips_support" >&6; }
+if test $gcc_cv_as_micromips_support = yes; then
+
+$as_echo "#define HAVE_GAS_MICROMIPS 1" >>confdefs.h
+
+fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .dtprelword support" >&5
 $as_echo_n "checking assembler for .dtprelword support... " >&6; }
 if test "${gcc_cv_as_mips_dtprelword+set}" = set; then :
Index: config.in
===================================================================
--- config.in	(revision 195351)
+++ config.in	(working copy)
@@ -266,12 +266,6 @@
 #endif
 
 
-/* Define if your assembler supports SPARC4 instructions. */
-#ifndef USED_FOR_TARGET
-#undef HAVE_AS_SPARC4
-#endif
-
-
 /* Define if your assembler supports fprnd. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_FPRND
@@ -477,6 +471,12 @@
 #endif
 
 
+/* Define if your assembler supports SPARC4 instructions. */
+#ifndef USED_FOR_TARGET
+#undef HAVE_AS_SPARC4
+#endif
+
+
 /* Define if your assembler and linker support GOTDATA_OP relocs. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_AS_SPARC_GOTDATA_OP
@@ -1034,6 +1034,12 @@
 #endif
 
 
+/* Define if your assembler supports the .set micromips directive */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GAS_MICROMIPS
+#endif
+
+
 /* Define if your assembler supports .nsubspa comdat option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GAS_NSUBSPA_COMDAT
@@ -1228,7 +1234,7 @@
 #endif
 
 
-/* Define if your PowerPC64 linker supports a large TOC. */
+/* Define if your AIX linker supports a large TOC. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_LD_LARGE_TOC
 #endif
Index: configure.ac
===================================================================
--- configure.ac	(revision 195351)
+++ configure.ac	(working copy)
@@ -4020,6 +4020,12 @@ LCF0:
       [AC_DEFINE(HAVE_AS_GNU_ATTRIBUTE, 1,
 	  [Define if your assembler supports .gnu_attribute.])])
 
+    gcc_GAS_CHECK_FEATURE([.micromips support],
+      gcc_cv_as_micromips_support,,,
+      [.set micromips],,
+      [AC_DEFINE(HAVE_GAS_MICROMIPS, 1,
+          [Define if your assembler supports the .set micromips directive])])
+
     gcc_GAS_CHECK_FEATURE([.dtprelword support],
       gcc_cv_as_mips_dtprelword, [2,18,0],,
       [.section .tdata,"awT",@progbits
Index: config/mips/mips-tables.opt
===================================================================
--- config/mips/mips-tables.opt	(revision 195351)
+++ config/mips/mips-tables.opt	(working copy)
@@ -373,254 +373,260 @@ EnumValue
 Enum(mips_arch_opt_value) String(m4k) Value(39) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kec) Value(40) Canonical
+Enum(mips_arch_opt_value) String(m14kc) Value(40) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kec) Value(40)
+Enum(mips_arch_opt_value) String(m14k) Value(41) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kem) Value(41) Canonical
+Enum(mips_arch_opt_value) String(4kec) Value(42) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kem) Value(41)
+Enum(mips_arch_opt_value) String(r4kec) Value(42)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kep) Value(42) Canonical
+Enum(mips_arch_opt_value) String(4kem) Value(43) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kep) Value(42)
+Enum(mips_arch_opt_value) String(r4kem) Value(43)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4ksd) Value(43) Canonical
+Enum(mips_arch_opt_value) String(4kep) Value(44) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4ksd) Value(43)
+Enum(mips_arch_opt_value) String(r4kep) Value(44)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kc) Value(44) Canonical
+Enum(mips_arch_opt_value) String(4ksd) Value(45) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kc) Value(44)
+Enum(mips_arch_opt_value) String(r4ksd) Value(45)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf2_1) Value(45) Canonical
+Enum(mips_arch_opt_value) String(24kc) Value(46) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf2_1) Value(45)
+Enum(mips_arch_opt_value) String(r24kc) Value(46)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf) Value(46) Canonical
+Enum(mips_arch_opt_value) String(24kf2_1) Value(47) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf) Value(46)
+Enum(mips_arch_opt_value) String(r24kf2_1) Value(47)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf1_1) Value(47) Canonical
+Enum(mips_arch_opt_value) String(24kf) Value(48) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf1_1) Value(47)
+Enum(mips_arch_opt_value) String(r24kf) Value(48)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kfx) Value(48) Canonical
+Enum(mips_arch_opt_value) String(24kf1_1) Value(49) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kfx) Value(48)
+Enum(mips_arch_opt_value) String(r24kf1_1) Value(49)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kx) Value(49) Canonical
+Enum(mips_arch_opt_value) String(24kfx) Value(50) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kx) Value(49)
+Enum(mips_arch_opt_value) String(r24kfx) Value(50)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kec) Value(50) Canonical
+Enum(mips_arch_opt_value) String(24kx) Value(51) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kec) Value(50)
+Enum(mips_arch_opt_value) String(r24kx) Value(51)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef2_1) Value(51) Canonical
+Enum(mips_arch_opt_value) String(24kec) Value(52) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef2_1) Value(51)
+Enum(mips_arch_opt_value) String(r24kec) Value(52)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef) Value(52) Canonical
+Enum(mips_arch_opt_value) String(24kef2_1) Value(53) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef) Value(52)
+Enum(mips_arch_opt_value) String(r24kef2_1) Value(53)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef1_1) Value(53) Canonical
+Enum(mips_arch_opt_value) String(24kef) Value(54) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef1_1) Value(53)
+Enum(mips_arch_opt_value) String(r24kef) Value(54)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kefx) Value(54) Canonical
+Enum(mips_arch_opt_value) String(24kef1_1) Value(55) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kefx) Value(54)
+Enum(mips_arch_opt_value) String(r24kef1_1) Value(55)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kex) Value(55) Canonical
+Enum(mips_arch_opt_value) String(24kefx) Value(56) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kex) Value(55)
+Enum(mips_arch_opt_value) String(r24kefx) Value(56)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kc) Value(56) Canonical
+Enum(mips_arch_opt_value) String(24kex) Value(57) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kc) Value(56)
+Enum(mips_arch_opt_value) String(r24kex) Value(57)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf2_1) Value(57) Canonical
+Enum(mips_arch_opt_value) String(34kc) Value(58) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf2_1) Value(57)
+Enum(mips_arch_opt_value) String(r34kc) Value(58)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf) Value(58) Canonical
+Enum(mips_arch_opt_value) String(34kf2_1) Value(59) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf) Value(58)
+Enum(mips_arch_opt_value) String(r34kf2_1) Value(59)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf1_1) Value(59) Canonical
+Enum(mips_arch_opt_value) String(34kf) Value(60) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf1_1) Value(59)
+Enum(mips_arch_opt_value) String(r34kf) Value(60)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kfx) Value(60) Canonical
+Enum(mips_arch_opt_value) String(34kf1_1) Value(61) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kfx) Value(60)
+Enum(mips_arch_opt_value) String(r34kf1_1) Value(61)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kx) Value(61) Canonical
+Enum(mips_arch_opt_value) String(34kfx) Value(62) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kx) Value(61)
+Enum(mips_arch_opt_value) String(r34kfx) Value(62)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kn) Value(62) Canonical
+Enum(mips_arch_opt_value) String(34kx) Value(63) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kn) Value(62)
+Enum(mips_arch_opt_value) String(r34kx) Value(63)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kc) Value(63) Canonical
+Enum(mips_arch_opt_value) String(34kn) Value(64) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kc) Value(63)
+Enum(mips_arch_opt_value) String(r34kn) Value(64)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf2_1) Value(64) Canonical
+Enum(mips_arch_opt_value) String(74kc) Value(65) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf2_1) Value(64)
+Enum(mips_arch_opt_value) String(r74kc) Value(65)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf) Value(65) Canonical
+Enum(mips_arch_opt_value) String(74kf2_1) Value(66) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf) Value(65)
+Enum(mips_arch_opt_value) String(r74kf2_1) Value(66)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf1_1) Value(66) Canonical
+Enum(mips_arch_opt_value) String(74kf) Value(67) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf1_1) Value(66)
+Enum(mips_arch_opt_value) String(r74kf) Value(67)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kfx) Value(67) Canonical
+Enum(mips_arch_opt_value) String(74kf1_1) Value(68) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kfx) Value(67)
+Enum(mips_arch_opt_value) String(r74kf1_1) Value(68)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kx) Value(68) Canonical
+Enum(mips_arch_opt_value) String(74kfx) Value(69) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kx) Value(68)
+Enum(mips_arch_opt_value) String(r74kfx) Value(69)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf3_2) Value(69) Canonical
+Enum(mips_arch_opt_value) String(74kx) Value(70) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf3_2) Value(69)
+Enum(mips_arch_opt_value) String(r74kx) Value(70)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kc) Value(70) Canonical
+Enum(mips_arch_opt_value) String(74kf3_2) Value(71) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kc) Value(70)
+Enum(mips_arch_opt_value) String(r74kf3_2) Value(71)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf2_1) Value(71) Canonical
+Enum(mips_arch_opt_value) String(1004kc) Value(72) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf2_1) Value(71)
+Enum(mips_arch_opt_value) String(r1004kc) Value(72)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf) Value(72) Canonical
+Enum(mips_arch_opt_value) String(1004kf2_1) Value(73) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf) Value(72)
+Enum(mips_arch_opt_value) String(r1004kf2_1) Value(73)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf1_1) Value(73) Canonical
+Enum(mips_arch_opt_value) String(1004kf) Value(74) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf1_1) Value(73)
+Enum(mips_arch_opt_value) String(r1004kf) Value(74)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kc) Value(74) Canonical
+Enum(mips_arch_opt_value) String(1004kf1_1) Value(75) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kc) Value(74)
+Enum(mips_arch_opt_value) String(r1004kf1_1) Value(75)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kf) Value(75) Canonical
+Enum(mips_arch_opt_value) String(5kc) Value(76) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kf) Value(75)
+Enum(mips_arch_opt_value) String(r5kc) Value(76)
 
 EnumValue
-Enum(mips_arch_opt_value) String(20kc) Value(76) Canonical
+Enum(mips_arch_opt_value) String(5kf) Value(77) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r20kc) Value(76)
+Enum(mips_arch_opt_value) String(r5kf) Value(77)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1) Value(77) Canonical
+Enum(mips_arch_opt_value) String(20kc) Value(78) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1a) Value(78) Canonical
+Enum(mips_arch_opt_value) String(r20kc) Value(78)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71000) Value(79) Canonical
+Enum(mips_arch_opt_value) String(sb1) Value(79) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71k) Value(79)
+Enum(mips_arch_opt_value) String(sb1a) Value(80) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlr) Value(80) Canonical
+Enum(mips_arch_opt_value) String(sr71000) Value(81) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(loongson3a) Value(81) Canonical
+Enum(mips_arch_opt_value) String(sr71k) Value(81)
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon) Value(82) Canonical
+Enum(mips_arch_opt_value) String(xlr) Value(82) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon+) Value(83) Canonical
+Enum(mips_arch_opt_value) String(loongson3a) Value(83) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon2) Value(84) Canonical
+Enum(mips_arch_opt_value) String(octeon) Value(84) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlp) Value(85) Canonical
+Enum(mips_arch_opt_value) String(octeon+) Value(85) Canonical
 
+EnumValue
+Enum(mips_arch_opt_value) String(octeon2) Value(86) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(xlp) Value(87) Canonical
+
Index: config/mips/gnu-user.h
===================================================================
--- config/mips/gnu-user.h	(revision 195351)
+++ config/mips/gnu-user.h	(working copy)
@@ -137,3 +137,12 @@ extern const char *host_detect_local_cpu (int argc
 #define ENDFILE_SPEC \
   GNU_USER_TARGET_MATHFILE_SPEC " " \
   GNU_USER_TARGET_ENDFILE_SPEC
+
+#undef SUBTARGET_OVERRIDE_OPTIONS
+#define SUBTARGET_OVERRIDE_OPTIONS                              \
+do {                                                            \
+  /* microMIPS PLT entries are non-microMIPS.  */               \
+  TARGET_INTERLINK_COMPRESSED = 1;                              \
+} while (0)
+
+
Index: config/mips/micromips.md
===================================================================
--- config/mips/micromips.md	(revision 0)
+++ config/mips/micromips.md	(revision 0)
@@ -0,0 +1,118 @@
+(define_insn "*store_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "memory_operand")
+	     (match_operand:SI 2 "register_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (true, operands[0])"
+  { return umips_output_save_restore (true, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+(define_insn "*load_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "register_operand")
+	     (match_operand:SI 2 "memory_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (false, operands[0])"
+  { return umips_output_save_restore (false, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For lwp
+(define_peephole2
+  [(set (match_operand:SI 0 "d_operand" "")
+        (match_operand:SI 1 "non_volatile_mem_operand" ""))
+   (set (match_operand:SI 2 "d_operand" "")
+        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*lwp"
+  [(parallel [(set (match_operand:SI 0 "d_operand")
+		   (match_operand:SI 1 "non_volatile_mem_operand"))
+	      (set (match_operand:SI 2 "d_operand")
+		   (match_operand:SI 3 "non_volatile_mem_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+  {
+    umips_output_load_store_pair (true, operands);
+    return "";
+  }
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For swp
+(define_peephole2
+  [(set (match_operand:SI 0 "non_volatile_mem_operand" "")
+        (match_operand:SI 1 "d_operand" ""))
+   (set (match_operand:SI 2 "non_volatile_mem_operand" "")
+        (match_operand:SI 3 "d_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*swp"
+  [(parallel [(set (match_operand:SI 0 "non_volatile_mem_operand")
+		   (match_operand:SI 1 "d_operand"))
+	      (set (match_operand:SI 2 "non_volatile_mem_operand")
+		   (match_operand:SI 3 "d_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+  {
+    umips_output_load_store_pair (false, operands);
+    return "";
+  }
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+(define_insn "mips_jraddiusp"
+  [(parallel [(return)
+              (use (reg:SI 31))
+	      (set (reg:SI 29)
+		   (plus:SI (reg:SI 29)
+			    (match_operand 0 "const_int_operand")))])]
+  "TARGET_MICROMIPS"
+  "jraddiusp\t%0"
+  [(set_attr "type" "trap")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For movep
+(define_peephole2
+  [(set (match_operand:MOVEP1 0 "register_operand" "")
+        (match_operand:MOVEP1 1 "movep_operand" ""))
+   (set (match_operand:MOVEP2 2 "register_operand" "")
+        (match_operand:MOVEP2 3 "movep_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+		   (match_operand:MOVEP1 1 "movep_operand"))
+	      (set (match_operand:MOVEP2 2 "register_operand")
+		   (match_operand:MOVEP2 3 "movep_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+{
+  if (REGNO (operands[0]) < REGNO (operands[2]))
+    return "movep\t%0,%2,%z1,%z3";
+  else
+    return "movep\t%2,%0,%z3,%z1";
+}
+  [(set_attr "type" "move")
+   (set_attr "mode" "<MODE>")
+   (set_attr "can_delay" "no")])
Index: config/mips/constraints.md
===================================================================
--- config/mips/constraints.md	(revision 195351)
+++ config/mips/constraints.md	(working copy)
@@ -232,6 +232,26 @@
    "@internal"
    (match_operand 0 "low_bitmask_operand"))
 
+(define_memory_constraint "ZC"
+  "When compiling microMIPS code, this constraing matches a memory operand
+   whose address is formed from a base register and a 12-bit offset.  These
+   operands can be used for microMIPS instructions such as @code{ll} and
+   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+   equivalent to @code{R}."
+  (and (match_code "mem")
+       (ior (and (match_test "TARGET_MICROMIPS")
+		 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)"))
+	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "ZD"
+  "When compiling microMIPS code, this constraint matches an address operand
+   that is formed from a base register and a 12-bit offset.  These operands
+   can be used for microMIPS instructions such as @code{prefetch}.  When
+   not compiling for microMIPS code, @code{YC} is equivalent to @code{p}."
+   (ior (and (match_test "TARGET_MICROMIPS")
+	     (match_test "umips_12bit_offset_address_p (op, mode)"))
+	(match_test "mips_address_insns (op, mode, false)")))
+
 (define_memory_constraint "ZR"
  "@internal
   An address valid for loading/storing register exclusive"
Index: config/mips/predicates.md
===================================================================
--- config/mips/predicates.md	(revision 195351)
+++ config/mips/predicates.md	(working copy)
@@ -122,6 +122,15 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "movep_register"
+  (and (match_code "reg")
+       (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
+	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
+
+(define_predicate "movep_operand"
+  (ior (match_operand 0 "const_0_operand")
+       (match_operand 0 "movep_register")))
+
 (define_predicate "lo_operand"
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
@@ -371,3 +380,11 @@
 (define_predicate "mem_noofs_operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
+
+;; Return 1 if the operand is in non-volatile memory.  Note that during the
+;; RTL generation phase, memory_operand does not return TRUE for volatile
+;; memory references.  So this function allows us to recognize volatile
+;; references where it's safe.
+(define_predicate "non_volatile_mem_operand"
+  (and (match_operand 0 "memory_operand")
+       (not (match_test "MEM_VOLATILE_P (op)"))))
Index: config/mips/mips.md
===================================================================
--- config/mips/mips.md	(revision 195351)
+++ config/mips/mips.md	(working copy)
@@ -342,13 +342,14 @@
 ;; syncloop	memory atomic operation implemented as a sync loop
 ;; nop		no operation
 ;; ghost	an instruction that produces no real code
+;; multimem	microMIPS multiword load and store
 (define_attr "type"
   "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
    prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
    shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
    fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
    frsqrt,frsqrt1,frsqrt2,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat,
-   multi,atomic,syncloop,nop,ghost"
+   multi,atomic,syncloop,nop,ghost,multimem"
   (cond [(eq_attr "jal" "!unset") (const_string "call")
 	 (eq_attr "got" "load") (const_string "load")
 
@@ -413,9 +414,15 @@
 
 ;; Length of instruction in bytes.
 (define_attr "length" ""
-   (cond [;; Direct branch instructions have a range of [-0x20000,0x1fffc],
-	  ;; relative to the address of the delay slot.  If a branch is
-	  ;; outside this range, we have a choice of two sequences.
+   (cond [(and (eq_attr "extended_mips16" "yes")
+	       (match_test "TARGET_MIPS16"))
+	  (const_int 8)
+
+	  ;; Direct microMIPS branch instructions have a range of
+	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
+	  ;; If a branch is outside this range, we have a choice of two
+	  ;; sequences.
+	  ;;
 	  ;; For PIC, an out-of-range branch like:
 	  ;;
 	  ;;	bne	r1,r2,target
@@ -451,10 +458,17 @@
 	  ;; from the shorten_branches reference address.
 	  (and (eq_attr "type" "branch")
 	       (not (match_test "TARGET_MIPS16")))
-	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
-		      (le (minus (pc) (match_dup 0)) (const_int 131068)))
+	  	 ;; any variant can handle the 17-bit range
+	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 65532))
+		      (le (minus (pc) (match_dup 0)) (const_int 65534)))
 		   (const_int 4)
 
+		 ;; The 18-bit range is OK other than for microMIPS.
+		 (and (eq (symbol_ref "TARGET_MICROMIPS") (const_int 0))
+		      (and (le (minus (match_dup 0) (pc)) (const_int 131064))
+		      	   (le (minus (pc) (match_dup 0)) (const_int 131068))))
+		   (const_int 4)
+
 		 ;; The non-PIC case: branch, first delay slot, and J.
 		 (match_test "TARGET_ABSOLUTE_JUMPS")
 		   (const_int 12)]
@@ -712,6 +726,9 @@
 ;; modes.
 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
 
+(define_mode_iterator MOVEP1 [SI SF])
+(define_mode_iterator MOVEP2 [SI SF])
+
 ;; This mode iterator allows :HILO to be used as the mode of the
 ;; concatenated HI and LO registers.
 (define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
@@ -3937,7 +3954,7 @@
 (define_insn "mov_<load>l"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_LOAD_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
   "<load>l\t%0,%2"
@@ -3947,7 +3964,7 @@
 (define_insn "mov_<load>r"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_operand:GPR 3 "register_operand" "0")]
 		    UNSPEC_LOAD_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
@@ -3958,7 +3975,7 @@
 (define_insn "mov_<store>l"
   [(set (match_operand:BLK 0 "memory_operand" "=m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_STORE_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
   "<store>l\t%z1,%2"
@@ -3968,7 +3985,7 @@
 (define_insn "mov_<store>r"
   [(set (match_operand:BLK 0 "memory_operand" "+m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_dup 0)]
 		    UNSPEC_STORE_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
@@ -5445,12 +5462,35 @@
 			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
 	 (label_ref (match_operand 0 "" ""))
 	 (pc)))]
-  "!TARGET_MIPS16"
+  "!TARGET_MIPS16 && !TARGET_MICROMIPS"
 {
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
 }
+  [(set_attr "type" "branch")
+   (set_attr "mode" "none")])
+
+(define_insn "*branch_equality<mode>_micromips"
+  [(set (pc)
+	(if_then_else
+	 (match_operator 1 "equality_operator"
+			 [(match_operand:GPR 2 "register_operand" "d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
+	 (label_ref (match_operand 0 "" ""))
+	 (pc)))]
+  "TARGET_MICROMIPS"
+{
+  /* For a simple bnez or beqz microMIPS branch.  */
+  if (operands[3] == const0_rtx && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%C1z%:\t%2,%0",
+					   "%*b%N1z%:\t%2,%0");
+
+  return mips_output_conditional_branch (insn, operands,
+					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
+					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
+}
   [(set_attr "type" "branch")])
 
 (define_insn "*branch_equality<mode>_inverted"
@@ -5461,7 +5501,7 @@
 			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
 	 (pc)
 	 (label_ref (match_operand 0 "" ""))))]
-  "!TARGET_MIPS16"
+  "!TARGET_MIPS16 && !TARGET_MICROMIPS"
 {
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
@@ -5532,6 +5572,29 @@
 		      (label_ref (match_operand 1))
 		      (pc)))])
 
+(define_insn "*branch_equality<mode>_inverted_micromips"
+  [(set (pc)
+	(if_then_else
+	 (match_operator 0 "equality_operator"
+			 [(match_operand:GPR 2 "register_operand" "d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
+	 (pc)
+	 (label_ref (match_operand 1 "" ""))))]
+  "TARGET_MICROMIPS"
+{
+  /* For a simple bnez or beqz microMIPS branch.  */
+  if (operands[3] == const0_rtx && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%N0z%:\t%2,%1",
+					   "%*b%C0z%:\t%2,%1");
+
+  return mips_output_conditional_branch (insn, operands,
+					 MIPS_BRANCH ("b%N0", "%2,%z3,%1"),
+					 MIPS_BRANCH ("b%C0", "%2,%z3,%1"));
+}
+  [(set_attr "type" "branch")
+   (set_attr "mode" "none")])
+
 ;; Branch if bit is set/clear.
 
 (define_insn "*branch_bit<bbv><mode>"
@@ -5766,7 +5829,14 @@
   [(set (pc)
 	(label_ref (match_operand 0)))]
   "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
-  { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
+{
+  /* Use a branch for microMIPS.  The assembler will choose
+     a 16-bit branch, a 32-bit branch, or a 32-bit jump.  */
+  if (TARGET_MICROMIPS && !TARGET_ABICALLS_PIC2)
+    return "%*b\t%l0%/";
+  else
+    return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+}
   [(set_attr "type" "jump")])
 
 (define_insn "*jump_pic"
@@ -5829,7 +5899,12 @@
 (define_insn "indirect_jump_<mode>"
   [(set (pc) (match_operand:P 0 "register_operand" "d"))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -5873,7 +5948,12 @@
 	(match_operand:P 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -6094,7 +6174,12 @@
   [(any_return)
    (use (match_operand 0 "pmode_register_operand" ""))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type"	"jump")
    (set_attr "mode"	"none")])
 
@@ -6350,7 +6435,12 @@
   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
 	 (match_operand 1 "" ""))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 0, 1); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J (operands, 0);
+    else
+      return MIPS_CALL ("j", operands, 0, 1);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6371,7 +6461,12 @@
         (call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
               (match_operand 2 "" "")))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J (operands, 1);
+    else
+      return MIPS_CALL ("j", operands, 1, 2);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6383,7 +6478,12 @@
 	(call (mem:SI (match_dup 1))
 	      (match_dup 2)))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J (operands, 1);
+    else
+      return MIPS_CALL ("j", operands, 1, 2);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6629,7 +6729,7 @@
 
 
 (define_insn "prefetch"
-  [(prefetch (match_operand:QI 0 "address_operand" "p")
+  [(prefetch (match_operand:QI 0 "address_operand" "ZD")
 	     (match_operand 1 "const_int_operand" "n")
 	     (match_operand 2 "const_int_operand" "n"))]
   "ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
@@ -6922,6 +7022,9 @@
 ; MIPS fixed-point instructions.
 (include "mips-fixed.md")
 
+; microMIPS patterns.
+(include "micromips.md")
+
 ; ST-Microelectronics Loongson-2E/2F-specific patterns.
 (include "loongson.md")
 
Index: config/mips/mips.opt
===================================================================
--- config/mips/mips.opt	(revision 195351)
+++ config/mips/mips.opt	(working copy)
@@ -217,9 +217,18 @@ mhard-float
 Target Report RejectNegative InverseMask(SOFT_FLOAT_ABI, HARD_FLOAT_ABI)
 Allow the use of hardware floating-point ABI and instructions
 
+minterlink-compressed
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+Generate code that is link-compatible with MIPS16 and microMIPS code.
+
+minterlink-uncompressed
+Target Report Var(TARGET_INTERLINK_UNCOMPRESSED) Init(1)
+Generated code that is link-compatible with the standard (uncompressed)
+MIPS ISA.
+
 minterlink-mips16
-Target Report Var(TARGET_INTERLINK_MIPS16) Init(0)
-Generate code that can be safely linked with MIPS16 code.
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+An alias for minterlink-compressed provided for backward-compatibility.
 
 mips
 Target RejectNegative Joined ToLower Enum(mips_mips_opt_value) Var(mips_isa_option)
@@ -261,6 +270,10 @@ mmemcpy
 Target Report Mask(MEMCPY)
 Don't optimize block moves
 
+mmicromips
+Target Report Mask(MICROMIPS)
+Use microMIPS instructions
+
 mmt
 Target Report Var(TARGET_MT)
 Allow the use of MT instructions
Index: config/mips/sync.md
===================================================================
--- config/mips/sync.md	(revision 195351)
+++ config/mips/sync.md	(working copy)
@@ -59,7 +59,7 @@
 ;; Can be removed in favor of atomic_compare_and_swap below.
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
 			      (match_operand:GPR 3 "arith_operand" "I,d")]
@@ -89,7 +89,7 @@
 ;; Helper insn for mips_expand_atomic_qihi.
 (define_insn "compare_and_swap_12"
   [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-	(match_operand:SI 1 "memory_operand" "+R,R"))
+	(match_operand:SI 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
 			     (match_operand:SI 3 "register_operand" "d,d")
@@ -106,7 +106,7 @@
    (set_attr "sync_insn1_op2" "5")])
 
 (define_insn "sync_add<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 0)
 		     (match_operand:GPR 1 "arith_operand" "I,d"))]
@@ -134,7 +134,7 @@
 
 ;; Helper insn for sync_<optab><mode>
 (define_insn "sync_<optab>_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -174,7 +174,7 @@
 ;; Helper insn for sync_old_<optab><mode>
 (define_insn "sync_old_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -217,7 +217,7 @@
 (define_insn "sync_new_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
@@ -257,7 +257,7 @@
 
 ;; Helper insn for sync_nand<mode>
 (define_insn "sync_nand_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -296,7 +296,7 @@
 ;; Helper insn for sync_old_nand<mode>
 (define_insn "sync_old_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -337,7 +337,7 @@
 (define_insn "sync_new_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (match_operand:SI 4 "reg_or_0_operand" "dJ")]
@@ -360,7 +360,7 @@
    (set_attr "sync_insn1_op2" "4")])
 
 (define_insn "sync_sub<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR")
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 0)
 		      (match_operand:GPR 1 "register_operand" "d"))]
@@ -374,7 +374,7 @@
 ;; Can be removed in favor of atomic_fetch_add below.
 (define_insn "sync_old_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 1)
@@ -389,7 +389,7 @@
 
 (define_insn "sync_old_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-	(match_operand:GPR 1 "memory_operand" "+R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 1)
@@ -404,7 +404,7 @@
 
 (define_insn "sync_new_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-        (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+        (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZR,ZR")
 		  (match_operand:GPR 2 "arith_operand" "I,d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -420,7 +420,7 @@
 
 (define_insn "sync_new_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-        (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+        (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZR")
 		   (match_operand:GPR 2 "register_operand" "d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -435,7 +435,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_<optab><mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
 			      (match_dup 0))]
@@ -448,7 +448,7 @@
 
 (define_insn "sync_old_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -463,7 +463,7 @@
 
 (define_insn "sync_new_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -478,7 +478,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_nand<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
@@ -490,7 +490,7 @@
 
 (define_insn "sync_old_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
@@ -504,7 +504,7 @@
 
 (define_insn "sync_new_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_NEW_OP))]
@@ -519,7 +519,7 @@
 
 (define_insn "sync_lock_test_and_set<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
 	 UNSPEC_SYNC_EXCHANGE))]
@@ -546,7 +546,7 @@
 
 (define_insn "test_and_set_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
 			     (match_operand:SI 3 "register_operand" "d")
@@ -576,7 +576,7 @@
 	;; TODO: the obscuring unspec can be relaxed for permissive memory
 	;; models.
 	;; Same applies to other atomic_* patterns.
-	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+R,R")
+	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZR,ZR")
 			      (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
 	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
    (set (match_operand:GPR 1 "register_operand" "=&d,&d")
@@ -629,7 +629,7 @@
 
 (define_insn "atomic_exchange<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_EXCHANGE))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
@@ -684,7 +684,7 @@
 
 (define_insn "atomic_fetch_add<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_FETCH_OP))
    (set (match_dup 1)
 	(unspec_volatile:GPR
Index: config/mips/mips-cpus.def
===================================================================
--- config/mips/mips-cpus.def	(revision 195351)
+++ config/mips/mips-cpus.def	(working copy)
@@ -92,6 +92,8 @@ MIPS_CPU ("4ksc", PROCESSOR_4KC, 32, 0)
 
 /* MIPS32 Release 2 processors.  */
 MIPS_CPU ("m4k", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14kc", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14k", PROCESSOR_M4K, 33, 0)
 MIPS_CPU ("4kec", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kem", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kep", PROCESSOR_4KP, 33, 0)
Index: config/mips/mips-protos.h
===================================================================
--- config/mips/mips-protos.h	(revision 195351)
+++ config/mips/mips-protos.h	(working copy)
@@ -350,6 +350,12 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern const char *umips_output_save_restore (bool, rtx);
+extern bool umips_save_restore_pattern_p (bool, rtx);
+extern bool umips_load_store_pair_p (bool, rtx *);
+extern void umips_output_load_store_pair (bool, rtx *);
+extern bool umips_movep_target_p (rtx, rtx);
+extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 195351)
+++ config/mips/mips.c	(working copy)
@@ -77,6 +77,9 @@ along with GCC; see the file COPYING3.  If not see
    preserve the maximum stack alignment.  We therefore use a value
    of 0x7ff0 in this case.
 
+   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
+   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
+
    MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
    up to 0x7f8 bytes and can usually save or restore all the registers
    that we need to save or restore.  (Note that we can only use these
@@ -87,7 +90,8 @@ along with GCC; see the file COPYING3.  If not see
    to save and restore registers, and to allocate and deallocate the top
    part of the frame.  */
 #define MIPS_MAX_FIRST_STACK_STEP					\
-  (!TARGET_MIPS16 ? 0x7ff0						\
+  ((!TARGET_MIPS16 && !TARGET_MICROMIPS) ? 0x7ff0			\
+   : TARGET_MICROMIPS ? 0x7f0						\
    : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8				\
    : TARGET_64BIT ? 0x100 : 0x400)
 
@@ -560,8 +564,8 @@ static const struct mips_rtx_cost_data *mips_cost;
 /* The ambient target flags, excluding MASK_MIPS16.  */
 static int mips_base_target_flags;
 
-/* True if MIPS16 is the default mode.  */
-bool mips_base_mips16;
+/* The default compression mode.  */
+unsigned int mips_base_compression_flags;
 
 /* The ambient values of other global variables.  */
 static int mips_base_schedule_insns; /* flag_schedule_insns */
@@ -672,8 +676,11 @@ static const struct attribute_spec mips_attribute_
      attributes, but GCC doesn't provide the hooks we need to support
      the right conversion rules.  As declaration attributes, they affect
      code generation but don't carry other semantics.  */
-  { "mips16", 	   0, 0, true,  false, false, NULL, false },
-  { "nomips16",    0, 0, true,  false, false, NULL, false },
+  { "mips16",	     0, 0, true,  false, false, NULL, false },
+  { "nomips16",	     0, 0, true,  false, false, NULL, false },
+  { "micromips",     0, 0, true,  false, false, NULL, false },
+  { "nomicromips",   0, 0, true,  false, false, NULL, false },
+  { "nocompression", 0, 0, true,  false, false, NULL, false },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 0, false, true,  true, NULL, false },
   { "use_shadow_register_set",	0, 0, false, true,  true, NULL, false },
@@ -1167,10 +1174,11 @@ mflip_mips16_use_mips16_p (tree decl)
   const char *name;
   hashval_t hash;
   void **slot;
+  bool base_is_mips16 = mips_base_compression_flags & MASK_MIPS16;
 
   /* Use the opposite of the command-line setting for anonymous decls.  */
   if (!DECL_NAME (decl))
-    return !mips_base_mips16;
+    return !base_is_mips16;
 
   if (!mflip_mips16_htab)
     mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
@@ -1185,7 +1193,7 @@ mflip_mips16_use_mips16_p (tree decl)
       mips16_flipper = !mips16_flipper;
       entry = ggc_alloc_mflip_mips16_entry ();
       entry->name = name;
-      entry->mips16_p = mips16_flipper ? !mips_base_mips16 : mips_base_mips16;
+      entry->mips16_p = mips16_flipper ? !base_is_mips16 : base_is_mips16;
       *slot = entry;
     }
   return entry->mips16_p;
@@ -1207,20 +1215,7 @@ mips_far_type_p (const_tree type)
 	  || lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
 }
 
-/* Similar predicates for "mips16"/"nomips16" function attributes.  */
 
-static bool
-mips_mips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
-static bool
-mips_nomips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
 /* Check if the interrupt attribute is set for a function.  */
 
 static bool
@@ -1257,12 +1252,57 @@ mips_use_debug_exception_return_p (tree type)
 			   TYPE_ATTRIBUTES (type)) != NULL;
 }
 
-/* Return true if function DECL is a MIPS16 function.  Return the ambient
-   setting if DECL is null.  */
+/* Return the set of compression modes that are explicitly required
+   by DECL.  */
 
-static bool
-mips_use_mips16_mode_p (tree decl)
+static unsigned int
+mips_get_compress_on_flags (tree decl)
 {
+  unsigned int flags = 0;
+
+  if (!decl || !DECL_P (decl))
+    return flags;
+
+  if (lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the set of compression modes that are explicitly forbidden
+   by DECL.  */
+
+static unsigned int
+mips_get_compress_off_flags (tree decl)
+{
+  unsigned int flags = 0;
+
+  if (!decl || !DECL_P (decl))
+    return flags;
+
+  if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MIPS16 | MASK_MICROMIPS;
+
+  if (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the compression mode that should be used for function DECL.
+   Return the ambient setting if DECL is null.  */
+static unsigned int
+mips_get_compress_mode (tree decl)
+{
+  unsigned int flags, force_on;
+
+  flags = mips_base_compression_flags;
   if (decl)
     {
       /* Nested functions must use the same frame pointer as their
@@ -1270,12 +1310,12 @@ mips_use_debug_exception_return_p (tree type)
       tree parent = decl_function_context (decl);
       if (parent)
 	decl = parent;
-      if (mips_mips16_decl_p (decl))
-	return true;
-      if (mips_nomips16_decl_p (decl))
-	return false;
+      force_on = mips_get_compress_on_flags (decl);
+      if (force_on)
+	return force_on;
+      flags &= ~mips_get_compress_off_flags (decl);
     }
-  return mips_base_mips16;
+  return flags;
 }
 
 /* Implement TARGET_COMP_TYPE_ATTRIBUTES.  */
@@ -1297,29 +1337,47 @@ static void
 mips_insert_attributes (tree decl, tree *attributes)
 {
   const char *name;
-  bool mips16_p, nomips16_p;
+  unsigned int compression_p, nocompression_p;
 
   /* Check for "mips16" and "nomips16" attributes.  */
-  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
-  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+  compression_p = mips_get_compress_on_flags (decl);
+  nocompression_p = mips_get_compress_off_flags (decl);
+
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
-      if (mips16_p)
+      if (compression_p & MASK_MIPS16)
 	error ("%qs attribute only applies to functions", "mips16");
-      if (nomips16_p)
+      if (nocompression_p & MASK_MIPS16)
 	error ("%qs attribute only applies to functions", "nomips16");
+
+      if (nocompression_p & MASK_MICROMIPS
+	  && nocompression_p & MASK_MIPS16)
+	error ("%qs attribute only applies to functions", "nocompression");
+      else
+	{
+	  if (compression_p & MASK_MICROMIPS)
+	    error ("%qs attribute only applies to functions", "micromips");
+	  if (nocompression_p & MASK_MICROMIPS)
+	    error ("%qs attribute only applies to functions", "nomicromips");
+	}
     }
   else
     {
-      mips16_p |= mips_mips16_decl_p (decl);
-      nomips16_p |= mips_nomips16_decl_p (decl);
-      if (mips16_p || nomips16_p)
+      if (compression_p & MASK_MIPS16
+           && nocompression_p & (MASK_MIPS16 | MASK_MICROMIPS))
 	{
+	  /* DECL cannot be simultaneously "mips16" and "nocompression".  */
+	  error ("%qE cannot have both %<mips16%> and "
+		 "%<nocompression%> attributes",
+		 DECL_NAME (decl));
+	}
+      else if (compression_p & MASK_MIPS16
+		&& nocompression_p & MASK_MIPS16)
+	{
 	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
-	  if (mips16_p && nomips16_p)
-	    error ("%qE cannot have both %<mips16%> and "
-		   "%<nomips16%> attributes",
-		   DECL_NAME (decl));
+	  error ("%qE cannot have both %<mips16%> and "
+		 "%<nomips16%> attributes",
+		 DECL_NAME (decl));
 	}
       else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
 	{
@@ -1329,6 +1387,39 @@ mips_insert_attributes (tree decl, tree *attribute
 	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
 	}
+
+      if (compression_p & MASK_MICROMIPS
+           && nocompression_p & (MASK_MIPS16 | MASK_MICROMIPS))
+	{
+	  /* DECL cannot be simultaneously "micromips" and "nocompression".  */
+	  error ("%qE cannot have both %<micromips%> and "
+		 "%<nocompression%> attributes",
+		 DECL_NAME (decl));
+	}
+      else if (compression_p & MASK_MICROMIPS
+		&& nocompression_p & MASK_MICROMIPS)
+	{
+	  /* DECL cannot be simultaneously "micromips" and "nomicromips".  */
+	  error ("%qs cannot have both %<micromips%> and "
+		 "%<nomicromips%> attributes",
+		 IDENTIFIER_POINTER (DECL_NAME (decl)));
+	}
+
+      if (compression_p & MASK_MIPS16
+          && compression_p & MASK_MICROMIPS)
+	error ("%qs cannot have both %<mips16%> and %<micromips%> attributes",
+	       IDENTIFIER_POINTER (DECL_NAME (decl)));
+
+      /* If DECL is "nocompression" set the "nomips16" and 
+	 "nomicromips" attributes.  */
+      if (nocompression_p & MASK_MIPS16
+          && nocompression_p & MASK_MICROMIPS)
+	{
+	  name = "nomips16";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	  name = "nomicromips";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	}
     }
 }
 
@@ -1338,12 +1429,9 @@ static tree
 mips_merge_decl_attributes (tree olddecl, tree newdecl)
 {
   /* The decls' "mips16" and "nomips16" attributes must match exactly.  */
-  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
+  if (mips_get_compress_mode (olddecl) != mips_get_compress_mode (newdecl))
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "mips16");
-  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
-    error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "nomips16");
+	   DECL_NAME (newdecl), "compression");
 
   return merge_attributes (DECL_ATTRIBUTES (olddecl),
 			   DECL_ATTRIBUTES (newdecl));
@@ -1550,7 +1638,7 @@ mips16_local_function_p (const_rtx x)
   return (GET_CODE (x) == SYMBOL_REF
 	  && SYMBOL_REF_LOCAL_P (x)
 	  && !SYMBOL_REF_EXTERNAL_P (x)
-	  && mips_use_mips16_mode_p (SYMBOL_REF_DECL (x)));
+	  && (mips_get_compress_mode (SYMBOL_REF_DECL (x)) & MASK_MIPS16));
 }
 
 /* Return true if SYMBOL_REF X binds locally.  */
@@ -2300,6 +2388,20 @@ mips_address_insns (rtx x, enum machine_mode mode,
   return 0;
 }
 
+/* Return true if X is a legitimate address with a 12-bit offset.
+   MODE is the mode of the value being accessed.  */
+
+bool
+umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address(&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && CONST_INT_P (addr.offset)
+	  && UMIPS_12BIT_OFFSET_P (addr.offset));
+}
+
 /* Return the number of instructions needed to load constant X.
    Return 0 if X isn't a valid constant.  */
 
@@ -6097,6 +6199,13 @@ mips_start_function_definition (const char *name,
   else
     fprintf (asm_out_file, "\t.set\tnomips16\n");
 
+  if (TARGET_MICROMIPS)
+    fprintf (asm_out_file, "\t.set\tmicromips\n");
+#ifdef HAVE_GAS_MICROMIPS
+  else 
+    fprintf (asm_out_file, "\t.set\tnomicromips\n");
+#endif
+
   if (!flag_inhibit_size_directive)
     {
       fputs ("\t.ent\t", asm_out_file);
@@ -6908,6 +7017,8 @@ mips_split_call (rtx insn, rtx call_pattern)
 static bool
 mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
+  unsigned int compression_mode = mips_get_compress_mode (decl);
+
   if (!TARGET_SIBCALLS)
     return false;
 
@@ -6916,22 +7027,45 @@ mips_function_ok_for_sibcall (tree decl, tree exp
   if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
     return false;
 
+  if (TARGET_MICROMIPS)
+    {
+      /* We can't do a sibcall if the called function is a MIPS32 function.  */
+      if (decl
+	  && (compression_mode & MASK_MICROMIPS) == 0
+	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+	return false;
+
+      /* When -minterlink-compressed is in effect, assume that non-locally-binding
+	 functions could be MIPS32 ones unless an attribute explicitly tells
+	 us otherwise.  */
+      if (TARGET_INTERLINK_COMPRESSED
+	  && decl
+	  && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
+	  && (compression_mode & MASK_MICROMIPS) == 0
+	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+	return false;
+
+      /* Otherwise OK.  */
+      return true;
+    }
+
   /* We can't do a sibcall if the called function is a MIPS16 function
      because there is no direct "jx" instruction equivalent to "jalx" to
      switch the ISA mode.  We only care about cases where the sibling
      and normal calls would both be direct.  */
   if (decl
-      && mips_use_mips16_mode_p (decl)
+      && ((compression_mode & (MASK_MIPS16 | MASK_MICROMIPS)) != 0)
       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
     return false;
 
-  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
-     functions could be MIPS16 ones unless an attribute explicitly tells
+  /* When -minterlink-compressed is in effect, assume that non-locally-binding
+     functions could be MIPS16 or microMIPS unless an attribute explicitly tells
      us otherwise.  */
-  if (TARGET_INTERLINK_MIPS16
+  if (TARGET_INTERLINK_COMPRESSED
       && decl
       && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
-      && !mips_nomips16_decl_p (decl)
+      && (compression_mode & MASK_MICROMIPS) == 0
+      && (compression_mode & MASK_MIPS16) == 0
       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
     return false;
 
@@ -7798,6 +7932,9 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_s
    '^'	Print the name of the pic call-through register (t9 or $25).
    '+'	Print the name of the gp register (usually gp or $28).
    '$'	Print the name of the stack pointer register (sp or $29).
+   ':'  Print "c" to use the compact version if the delay slot is a nop.
+   '!'  Print "s" to use the short version if the delay slot contains a
+	16-bit instruction.
 
    See also mips_init_print_operand_pucnt.  */
 
@@ -7881,6 +8018,20 @@ mips_print_operand_punctuation (FILE *file, int ch
       fputs (reg_names[STACK_POINTER_REGNUM], file);
       break;
 
+    case ':':
+      /* When reorder or noreorder with final_squence 0, the delay slot will
+	 be a nop, so we just use the compact version for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('c', file);
+      break;
+
+    case '!':
+      /* When reorder or noreorder with final_squence 0, the delay slot will
+	 be a nop, so we just use the compact version for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('s', file);
+      break;
+
     default:
       gcc_unreachable ();
       break;
@@ -7894,7 +8045,7 @@ mips_init_print_operand_punct (void)
 {
   const char *p;
 
-  for (p = "()[]<>*#/?~.@^+$"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$:!"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -10198,7 +10349,7 @@ typedef void (*mips_save_restore_fn) (rtx, rtx);
    stack pointer.  */
 
 static void
-mips_save_restore_reg (enum machine_mode mode, int regno,
+mips_save_restore_single_reg (enum machine_mode mode, int regno,
 		       HOST_WIDE_INT offset, mips_save_restore_fn fn)
 {
   rtx mem;
@@ -10208,6 +10359,23 @@ static void
   fn (gen_rtx_REG (mode, regno), mem);
 }
 
+static void
+mips_save_restore_registers (int start_reg, int end_reg, HOST_WIDE_INT *offset,
+			     mips_save_restore_fn fn, HOST_WIDE_INT sp_offset)
+{
+  int regno;
+
+  for (regno = start_reg; regno > end_reg; regno--)
+    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+      {
+        /* Record the ra offset for use by mips_function_profiler.  */
+        if (regno == RETURN_ADDR_REGNUM)
+          cfun->machine->frame.ra_fp_offset = *offset + sp_offset;
+	mips_save_restore_single_reg (word_mode, regno, *offset, fn);
+	*offset -= UNITS_PER_WORD;
+      }
+}
+
 /* Call FN for each accumlator that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -10221,9 +10389,9 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset,
   offset = cfun->machine->frame.acc_sp_offset - sp_offset;
   if (BITSET_P (cfun->machine->frame.acc_mask, 0))
     {
-      mips_save_restore_reg (word_mode, LO_REGNUM, offset, fn);
+      mips_save_restore_single_reg (word_mode, LO_REGNUM, offset, fn);
       offset -= UNITS_PER_WORD;
-      mips_save_restore_reg (word_mode, HI_REGNUM, offset, fn);
+      mips_save_restore_single_reg (word_mode, HI_REGNUM, offset, fn);
       offset -= UNITS_PER_WORD;
     }
 
@@ -10231,11 +10399,145 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset,
     if (BITSET_P (cfun->machine->frame.acc_mask,
 		  ((regno - DSP_ACC_REG_FIRST) / 2) + 1))
       {
-	mips_save_restore_reg (word_mode, regno, offset, fn);
+	mips_save_restore_single_reg (word_mode, regno, offset, fn);
 	offset -= UNITS_PER_WORD;
       }
 }
 
+/* Save register REG to MEM.  Make the instruction frame-related.  */
+
+static void
+mips_save_reg (rtx reg, rtx mem)
+{
+  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
+    {
+      rtx x1, x2;
+
+      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
+
+      x1 = mips_frame_set (mips_subword (mem, false),
+			   mips_subword (reg, false));
+      x2 = mips_frame_set (mips_subword (mem, true),
+			   mips_subword (reg, true));
+      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
+    }
+  else
+    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
+}
+
+static const unsigned int type[19] = { 0x00010000, 0x00030000, 0x00070000,
+				       0x000f0000, 0x001f0000, 0x003f0000,
+				       0x007f0000, 0x00ff0000, 0x40ff0000,
+				       0x80000000, 0x80010000, 0x80030000,
+				       0x80070000, 0x800f0000, 0x801f0000,
+				       0x803f0000, 0x807f0000, 0x80ff0000,
+				       0xc0ff0000 };
+
+static const unsigned int encode[19] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17,
+					 18, 19, 20, 21, 22, 23, 24, 25};
+
+/* Build microMIPS save or restore.  FN is save or restore function.
+   OFFSET is the current stack offset.
+   Return true if we succeed creating save or restore.  */
+
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+			  HOST_WIDE_INT offset, HOST_WIDE_INT sp_offset)
+{
+  int i, num_of_reg;
+  unsigned int j;
+  rtx pattern, set, reg, mem;
+  HOST_WIDE_INT this_offset;
+  rtx this_base;
+
+  /* LWM/SWM can only support offsets from -2048 to 2047.  */
+  if (!UMIPS_12BIT_OFFSET_P (offset))
+    return false;
+
+  /* Try matching $16 to $31 (s0 to ra).  */
+  for (i = 0; i < ARRAY_SIZE (type); i++)
+    if ((cfun->machine->frame.mask & 0xffff0000) == type[i])
+      break;
+
+  if (i == ARRAY_SIZE (type))
+    {
+      /* Try matching $16 to $23 (s0 to s7) only.  */
+      for (i = 0; i < 8; i ++)
+	if ((cfun->machine->frame.mask & 0x00ff0000) == type[i])
+	  break;
+
+      if (i == 8)
+	return false;
+    }
+
+  /* For only one register, we use normal sw/lw for speed.  */
+  if (i == 0 || i == 9)
+    return false;
+
+  if (i < 8 && (cfun->machine->frame.mask & 0xff000000))
+    mips_save_restore_registers (GP_REG_LAST, GP_REG_LAST - 8,
+				 &offset, fn, sp_offset);
+
+  /* Adjust offset for output.  */
+  num_of_reg = (encode[i] & 0xf) + (encode[i] >> 4);
+  offset -= (UNITS_PER_WORD * (num_of_reg - 1));
+
+  /* Create the final PARALLEL.  */
+  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_of_reg));
+
+  this_base = stack_pointer_rtx;
+  this_offset = offset;
+
+  /* For $16-$23, $30.  */
+  for (j = 0; j < (encode[i] & 0xf); j++)
+    {
+      unsigned int regno;
+      long long offset = this_offset + j * UNITS_PER_WORD;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      regno = (j != 8) ? 16 + j : 30;
+      reg = gen_rtx_REG (SImode, regno);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  /* For $31.  */
+  if (encode[i] >> 4)
+    {
+      long long offset = this_offset + j * UNITS_PER_WORD;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      reg = gen_rtx_REG (SImode, 31);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  pattern = emit_insn (pattern);
+  if (fn == mips_save_reg)
+    RTX_FRAME_RELATED_P(pattern) = 1;  
+
+  /* Adjust the last offset.  */
+  offset -= UNITS_PER_WORD;
+
+  /* For $15 to $0.  */
+  if (cfun->machine->frame.mask & 0xffff)
+    {
+      mips_save_restore_registers (GP_REG_FIRST + 15, GP_REG_FIRST,
+				   &offset, fn, sp_offset);
+    }
+
+  return true;
+}
 /* Call FN for each register that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -10253,16 +10555,13 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
   offset = cfun->machine->frame.gp_sp_offset - sp_offset;
-  for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
-    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
-      {
-	/* Record the ra offset for use by mips_function_profiler.  */
-	if (regno == RETURN_ADDR_REGNUM)
-	  cfun->machine->frame.ra_fp_offset = offset + sp_offset;
-	mips_save_restore_reg (word_mode, regno, offset, fn);
-	offset -= UNITS_PER_WORD;
-      }
 
+  if (!TARGET_MICROMIPS
+      || (TARGET_MICROMIPS
+          && !umips_build_save_restore (fn, offset, sp_offset)))
+    mips_save_restore_registers (GP_REG_LAST, GP_REG_FIRST,
+				 &offset, fn, sp_offset);
+
   /* This loop must iterate over the same space as its companion in
      mips_compute_frame_info.  */
   offset = cfun->machine->frame.fp_sp_offset - sp_offset;
@@ -10272,7 +10571,7 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
        regno -= MAX_FPRS_PER_FMT)
     if (BITSET_P (cfun->machine->frame.fmask, regno - FP_REG_FIRST))
       {
-	mips_save_restore_reg (fpr_mode, regno, offset, fn);
+	mips_save_restore_single_reg (fpr_mode, regno, offset, fn);
 	offset -= GET_MODE_SIZE (fpr_mode);
       }
 }
@@ -10501,27 +10800,7 @@ mips_frame_barrier (void)
   emit_clobber (gen_frame_mem (BLKmode, stack_pointer_rtx));
 }
 
-/* Save register REG to MEM.  Make the instruction frame-related.  */
 
-static void
-mips_save_reg (rtx reg, rtx mem)
-{
-  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
-    {
-      rtx x1, x2;
-
-      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
-
-      x1 = mips_frame_set (mips_subword (mem, false),
-			   mips_subword (reg, false));
-      x2 = mips_frame_set (mips_subword (mem, true),
-			   mips_subword (reg, true));
-      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
-    }
-  else
-    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
-}
-
 /* The __gnu_local_gp symbol.  */
 
 static GTY(()) rtx mips_gnu_local_gp;
@@ -10790,8 +11069,8 @@ mips_expand_prologue (void)
  	    if (BITSET_P (mask, regno - GP_REG_FIRST))
  	      {
 		offset -= UNITS_PER_WORD;
-		mips_save_restore_reg (word_mode, regno,
-				       offset, mips_save_reg);
+		mips_save_restore_single_reg (word_mode, regno,
+					      offset, mips_save_reg);
  	      }
  	}
       else
@@ -11078,6 +11357,7 @@ mips_deallocate_stack (rtx base, rtx offset, HOST_
     return;
 
   mips_frame_barrier ();
+
   if (offset == const0_rtx)
     {
       emit_move_insn (stack_pointer_rtx, base);
@@ -11196,9 +11476,9 @@ mips_expand_epilogue (bool sibcall_p)
  	if (BITSET_P (mask, regno - GP_REG_FIRST))
  	  {
  	    offset -= UNITS_PER_WORD;
- 	    mips_save_restore_reg (word_mode, regno, offset, mips_restore_reg);
+ 	    mips_save_restore_single_reg (word_mode, regno,
+                                          offset, mips_restore_reg);
  	  }
-
       /* Restore the remaining registers and deallocate the final bit
 	 of the frame.  */
       mips_frame_barrier ();
@@ -11211,7 +11491,6 @@ mips_expand_epilogue (bool sibcall_p)
       mips_for_each_saved_acc (frame->total_size - step2, mips_restore_reg);
       mips_for_each_saved_gpr_and_fpr (frame->total_size - step2,
 				       mips_restore_reg);
-
       if (cfun->machine->interrupt_handler_p)
 	{
 	  HOST_WIDE_INT offset;
@@ -11254,7 +11533,6 @@ mips_expand_epilogue (bool sibcall_p)
 	/* Deallocate the final bit of the frame.  */
 	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
     }
-  gcc_assert (!mips_epilogue.cfa_restores);
 
   /* Add in the __builtin_eh_return stack adjustment.  We need to
      use a temporary in MIPS16 code.  */
@@ -16211,17 +16489,19 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndec
   reload_completed = 0;
 }
 \f
-/* The last argument passed to mips_set_mips16_mode, or negative if the
-   function hasn't been called yet.  */
+/* The last argument passed to mips_set_mips16_micromips_mode,
+   or negative if the function hasn't been called yet.  */
 static int was_mips16_p = -1;
+static int was_micromips_p = -1;
 
 /* Set up the target-dependent global state so that it matches the
    current function's ISA mode.  */
 
 static void
-mips_set_mips16_mode (int mips16_p)
+mips_set_mips16_micromips_mode (int mips16_p, int micromips_p)
 {
-  if (mips16_p == was_mips16_p)
+  if (mips16_p == was_mips16_p
+      && micromips_p == was_micromips_p)
     return;
 
   /* Restore base settings of various flags.  */
@@ -16290,6 +16570,18 @@ static void
       /* Switch to normal (non-MIPS16) mode.  */
       target_flags &= ~MASK_MIPS16;
 
+      if (micromips_p)
+	{
+	  /* Switch to microMIPS mode.  */
+	  target_flags |= MASK_MICROMIPS;
+
+	  /* Avoid branch likely.  */
+	  target_flags &= ~MASK_BRANCHLIKELY;
+	}
+      else
+	/* Switch to normal (non-microMIPS) mode.  */
+	target_flags &= ~MASK_MICROMIPS;
+
       /* Provide default values for align_* for 64-bit targets.  */
       if (TARGET_64BIT)
 	{
@@ -16321,15 +16613,22 @@ static void
     restore_target_globals (&default_target_globals);
 
   was_mips16_p = mips16_p;
+  was_micromips_p = micromips_p;
 }
 
 /* Implement TARGET_SET_CURRENT_FUNCTION.  Decide whether the current
-   function should use the MIPS16 ISA and switch modes accordingly.  */
+   function should use the MIPS16 or microMIPS ISA and switch modes
+   accordingly.  */
 
 static void
 mips_set_current_function (tree fndecl)
 {
-  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+
+  unsigned int compression_p = mips_get_compress_mode (fndecl);
+
+  mips_set_mips16_micromips_mode (compression_p & MASK_MIPS16,
+				  compression_p & MASK_MICROMIPS);
+
 }
 \f
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -16437,14 +16736,24 @@ mips_option_override (void)
   if (global_options_set.x_mips_isa_option)
     mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
 
-  /* Process flags as though we were generating non-MIPS16 code.  */
-  mips_base_mips16 = TARGET_MIPS16;
-  target_flags &= ~MASK_MIPS16;
-
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
+  /* MIPS16 and microMIPS cannot coexist  */
+  if (TARGET_MICROMIPS && TARGET_MIPS16)
+    error ("unsupported combination: %s", "-mips16 -mmicromips");
+
+  /* Save the base compression state and process flags as though we
+     are generating uncompressed code.  */
+  if (TARGET_MIPS16)
+    mips_base_compression_flags |= MASK_MIPS16;
+  if (TARGET_MICROMIPS)
+    mips_base_compression_flags |= MASK_MICROMIPS;
+
+  target_flags &= ~MASK_MIPS16;
+  target_flags &= ~MASK_MICROMIPS;
+
   /* -mno-float overrides -mhard-float and -msoft-float.  */
   if (TARGET_NO_FLOAT)
     {
@@ -16453,7 +16762,7 @@ mips_option_override (void)
     }
 
   if (TARGET_FLIP_MIPS16)
-    TARGET_INTERLINK_MIPS16 = 1;
+    TARGET_INTERLINK_COMPRESSED = 1;
 
   /* Set the small data limit.  */
   mips_small_data_threshold = (global_options_set.x_g_switch_value
@@ -16826,9 +17135,9 @@ mips_option_override (void)
 
   /* Now select the ISA mode.
 
-     Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
-     MIPS16 mode afterwards if need be.  */
-  mips_set_mips16_mode (false);
+     Do all CPP-sensitive stuff in non-MIPS16/non-microMIPS mode;
+     We'll switch modes later if required.  */
+  mips_set_mips16_micromips_mode (false, false);
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -17088,6 +17397,316 @@ mips_mulsidi3_gen_fn (enum rtx_code ext_code)
       return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
     }
 }
+
+
+/* Return true if PATTERN matches the kind of instruction generated by
+   micromips_build_save_restore.  SAVE_P is true for store.  */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+  int n;
+  HOST_WIDE_INT first_offset = 0;
+  rtx first_base = 0;
+  unsigned int first_regno = 0;
+
+  for (n = 0; n < XVECLEN (pattern, 0); n++)
+    {
+      rtx set, reg, mem, this_base;
+      HOST_WIDE_INT this_offset;
+      unsigned int this_regno;
+
+      /* Check that we have a SET.  */
+      set = XVECEXP (pattern, 0, n);
+      if (GET_CODE (set) != SET)
+	return false;
+
+      /* Check that the SET is a load (if restoring) or a store
+	 (if saving).  */
+      mem = save_p ? SET_DEST (set) : SET_SRC (set);
+      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
+	return false;
+
+      /* Check that the address is the sum of base and a possibly-zero
+	 constant offset.  Determine if the offset is in range.  */
+      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+      if (!REG_P (this_base)
+	  && UMIPS_12BIT_OFFSET_P (this_offset))
+	return false;
+
+      if (n == 0)
+	{
+	  first_base = this_base;
+	  first_offset = this_offset;
+	}
+      else
+	{
+	  /* Check if this_base is the same as first_base.  */
+	  if (REGNO (this_base) != REGNO (first_base))
+	    return false;
+
+	  /* Check if this_offset is first_offset + UNITS_PER_WORD * n.  */
+	  if (this_offset != first_offset + UNITS_PER_WORD * n)
+	    return false;
+	}
+
+      /* Check that SET's other operand is a register.  */
+      reg = save_p ? SET_SRC (set) : SET_DEST (set);
+      if (!REG_P (reg))
+	return false;
+
+      /* Make sure the order of regno is "$16-$23, $30, $31", "$16-$23, $30",
+	 or "$31".  */
+      this_regno = REGNO (reg);
+      if (n == 0)
+	{
+	  if (this_regno != 16 && this_regno != 31)
+	    return false;
+	  first_regno = this_regno;
+	}
+      else if (n == 8) /* For s8.  */
+	{
+	  if (n == XVECLEN (pattern, 0) - 1)
+	    {
+	      if (this_regno != 30 && this_regno != 31)
+		return false;
+	    }
+	  else
+	    {
+	      if (this_regno != 30)
+		return false;
+	    }
+	}
+      else if (n != XVECLEN (pattern, 0) - 1)
+	{
+	  if (this_regno != first_regno + n)
+	    return false;
+	}
+      else /* The last item.  */
+	{
+	  if ((this_regno != first_regno + n) && this_regno != 31)
+	    return false;
+	}
+    }
+
+  return true;
+}
+/* Return the assembly instruction for microMIPS lwm or swm.
+   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+  static char buffer[300];
+  char *s;
+  int n;
+  HOST_WIDE_INT offset;
+  rtx base, mem, set, reg, last_set, last_reg;
+
+  /* Parse the pattern.  */
+  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
+
+  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
+  s += strlen (s);
+  n = XVECLEN (pattern, 0);
+
+  set = XVECEXP (pattern, 0, 0);
+  reg = save_p ? SET_SRC (set) : SET_DEST (set);
+  mem = save_p ? SET_DEST (set) : SET_SRC (set);
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+
+  last_set = XVECEXP (pattern, 0, n - 1);
+  last_reg = save_p ? SET_SRC (last_set) : SET_DEST (last_set);
+
+  if (REGNO (last_reg) == 31)
+    n--;
+
+  gcc_assert (n <= 9);
+  if (n == 0)
+    ;
+  else if (n == 1)
+    s += sprintf (s, "%s,", reg_names[16]);
+  else if (n < 9)
+    s += sprintf (s, "%s-%s,", reg_names[16], reg_names[15 + n]);
+  else if (n == 9)
+    s += sprintf (s, "%s-%s,%s,", reg_names[16], reg_names[23],
+		  reg_names[30]);
+
+  if (REGNO (last_reg) == 31)
+    s += sprintf (s, "%s,", reg_names[31]);
+
+  s += sprintf (s, "%d(%s)", (int)offset, reg_names[REGNO (base)]);
+  return buffer;
+}
+/* Return true if MEM1 and MEM2 use the same base register, and the
+   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
+   register into (from) which the contents of MEM1 will be loaded
+   (stored), depending on the value of LOAD_P.
+   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
+
+static bool
+umips_load_store_pair_p_1 (bool load_p, bool swap_p, rtx first_reg,
+			   rtx mem1, rtx mem2)
+{
+  rtx base1, base2;
+  HOST_WIDE_INT offset1, offset2;
+
+  if (!MEM_P (mem1) || !MEM_P (mem2))
+    return false;
+
+  /* Make sure memory is base plus offset.  */
+  if (GET_CODE (XEXP (mem1, 0)) != PLUS
+      || GET_CODE (XEXP (mem2, 0)) != PLUS
+      || GET_CODE (XEXP (XEXP (mem1, 0), 1)) != CONST_INT
+      || GET_CODE (XEXP (XEXP (mem2, 0), 1)) != CONST_INT)
+    return false;
+
+  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
+  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
+
+  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
+    return false;
+
+  /* Avoid invalid load pair instructions.  */
+  if (load_p && REGNO (first_reg) == REGNO (base1))
+    return false;
+
+  /* We must avoid this case for anti-dependence.
+     Ex:  lw $3, 4($3)
+          lw $2, 0($3)
+     first_reg is $2, but the base is $3.  */
+  if (load_p && swap_p && (REGNO (first_reg) + 1) == REGNO (base1))
+    return false;
+
+  if (swap_p
+      && offset2 + 4 != offset1)
+    return false;
+
+  if (offset1 + 4 != offset2)
+    return false;
+
+  if (!UMIPS_12BIT_OFFSET_P (offset1))
+    return false;
+
+  return true;
+}
+
+bool
+umips_load_store_pair_p (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+      return umips_load_store_pair_p_1 (load_p, false, reg1, mem1, mem2);
+
+  else if (REGNO (reg1) == REGNO (reg2) + 1)
+      return umips_load_store_pair_p_1 (load_p, true, reg2, mem1, mem2);
+
+  return false;
+}
+
+/* Return the assembly instruction for microMIPS lwp or swp.
+   LOAD_P is true for load.  */
+
+static void
+umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
+{
+  HOST_WIDE_INT offset;
+  rtx base, local_ops[3];
+
+  gcc_assert (REG_P (reg) && MEM_P (mem));
+
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+  gcc_assert (REG_P (base));
+
+  local_ops[0] = reg;
+  local_ops[1] = gen_rtx_CONST_INT (Pmode, offset);
+  local_ops[2] = base;
+  if (load_p)
+    output_asm_insn ("lwp %0,%1(%2)", local_ops);
+  else
+    output_asm_insn ("swp %0,%1(%2)", local_ops);
+}
+
+void
+umips_output_load_store_pair (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+   
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    {
+      umips_output_load_store_pair_1 (load_p, reg1, mem1);
+      return;
+    }
+
+  gcc_assert (REGNO (reg1) == REGNO (reg2) + 1);
+  umips_output_load_store_pair_1 (load_p, reg2, mem2);
+}
+
+/* Return true if reg1 and reg2 can be target of movep.  */
+
+bool
+umips_movep_target_p (rtx reg1, rtx reg2)
+{
+  int regno1, regno2, pair;
+  unsigned int i;
+  static const int match[8] = {0x00000060,	/* 5, 6 */
+			       0x000000a0,	/* 5, 7 */
+			       0x000000c0,	/* 6, 7 */
+			       0x00200010,	/* 4, 21 */
+			       0x00400010,	/* 4, 22 */
+			       0x00000030,	/* 4, 5 */
+			       0x00000050,	/* 4, 6 */
+			       0x00000090};	/* 4, 7 */
+
+  if (!REG_P (reg1) || !REG_P (reg2))
+    return false;
+
+  regno1 = REGNO (reg1);
+  regno2 = REGNO (reg2);
+
+  if (!GP_REG_P (regno1)  || !GP_REG_P (regno2))
+    return false;
+
+  pair = (1 << regno1) | (1 << regno2);
+
+  for (i = 0; i < ARRAY_SIZE (match); i++)
+    {
+      if (pair == match[i])
+	return true;
+    }
+
+  return false;
+}
 \f
 /* Return the size in bytes of the trampoline code, padded to
    TRAMPOLINE_ALIGNMENT bits.  The static chain pointer and target
@@ -17342,7 +17961,7 @@ mips_prepare_pch_save (void)
      It therefore seems best to switch back to non-MIPS16 mode at
      save time, and to ensure that mips16_globals remains null after
      a PCH load.  */
-  mips_set_mips16_mode (false);
+  mips_set_mips16_micromips_mode (false, false);
   mips16_globals = 0;
 }
 \f
Index: config/mips/mips.h
===================================================================
--- config/mips/mips.h	(revision 195351)
+++ config/mips/mips.h	(working copy)
@@ -374,7 +374,7 @@ struct mips_cpu_info {
       else								\
 	builtin_define ("__mips_fpr=32");				\
 									\
-      if (mips_base_mips16)						\
+      if (mips_base_compression_flags & MASK_MIPS16)			\
 	builtin_define ("__mips16");					\
 									\
       if (TARGET_MIPS3D)						\
@@ -383,6 +383,9 @@ struct mips_cpu_info {
       if (TARGET_SMARTMIPS)						\
 	builtin_define ("__mips_smartmips");				\
 									\
+      if (mips_base_compression_flags & MASK_MICROMIPS)			\
+	builtin_define ("__mips_micromips");				\
+									\
       if (TARGET_MCU)							\
 	builtin_define ("__mips_mcu");					\
 									\
@@ -702,7 +705,7 @@ struct mips_cpu_info {
        |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
      %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
      %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
-       |march=34k*|march=74k*|march=1004k*: -mips32r2} \
+       |march=34k*|march=74k*|march=m14k*|march=1004k*: -mips32r2} \
      %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
        |march=xlr|march=loongson3a: -mips64} \
      %{march=mips64r2|march=octeon|march=xlp: -mips64r2} \
@@ -716,7 +719,7 @@ struct mips_cpu_info {
   "%{mhard-float|msoft-float|mno-float|march=mips*:; \
      march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
      |march=34kc|march=34kn|march=74kc|march=1004kc|march=5kc \
-     |march=octeon|march=xlr: -msoft-float;		  \
+     |march=m14k*|march=octeon|march=xlr: -msoft-float;		  \
      march=*: -mhard-float}"
 
 /* A spec condition that matches 32-bit options.  It only works if
@@ -989,7 +992,8 @@ struct mips_cpu_info {
 				     || ISA_MIPS64R2))
 
 /* ISA has lwxs instruction (load w/scaled index address.  */
-#define ISA_HAS_LWXS		(TARGET_SMARTMIPS && !TARGET_MIPS16)
+#define ISA_HAS_LWXS		((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
+				 && !TARGET_MIPS16)
 
 /* ISA has lbx, lbux, lhx, lhx, lhux, lwx, lwux, or ldx instruction. */
 #define ISA_HAS_LBX		(TARGET_OCTEON2)
@@ -1123,6 +1127,7 @@ struct mips_cpu_info {
 %{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
 %{mips32*} %{mips64*} \
 %{mips16} %{mno-mips16:-no-mips16} \
+%{mmicromips} %{mno-micromips} \
 %{mips3d} %{mno-mips3d:-no-mips3d} \
 %{mdmx} %{mno-mdmx:-no-mdmx} \
 %{mdsp} %{mno-dsp} \
@@ -1672,6 +1677,8 @@ struct mips_cpu_info {
   ((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define M16_REG_P(REGNO) \
   (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 16 || (REGNO) == 17)
+#define M16STORE_REG_P(REGNO) \
+  (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 0 || (REGNO) == 17)
 #define FP_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
 #define MD_REG_P(REGNO) \
@@ -2452,18 +2459,48 @@ typedef struct mips_args {
    all calls should use assembly macros.  Otherwise, all indirect
    calls should use "jr" or "jalr"; we will arrange to restore $gp
    afterwards if necessary.  Finally, we can only generate direct
-   calls for -mabicalls by temporarily switching to non-PIC mode.  */
+   calls for -mabicalls by temporarily switching to non-PIC mode.
+
+   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+   instruction is in the delay slot of jal(r).  */
 #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
+  (TARGET_MICROMIPS						\
+   ? (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
+      ? (TARGET_INTERLINK_UNCOMPRESSED				\
+	 ? "%*" INSN "%!\t%" #TARGET_OPNO "%/"			\
+	 : "%*" INSN "\t%" #TARGET_OPNO "%/")			\
+      : (REG_P (OPERANDS[TARGET_OPNO])				\
+         && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
+      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
+         "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
+      : REG_P (OPERANDS[TARGET_OPNO])				\
+      ? (TARGET_INTERLINK_UNCOMPRESSED				\
+	 ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"			\
+	 : "%*" INSN "r\t%" #TARGET_OPNO "%/")			\
+      : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))	\
+  : (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
+     ? "%*" INSN "\t%" #TARGET_OPNO "%/"			\
+     : (REG_P (OPERANDS[TARGET_OPNO])				\
+        && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
+     ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
+        "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
+     : REG_P (OPERANDS[TARGET_OPNO])				\
+     ? "%*" INSN "r\t%" #TARGET_OPNO "%/"			\
+     : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/")))
+\f
+/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
+   "jrc" when nop is in the delay slot of "jr".  */
+#define MICROMIPS_J(OPERANDS, OPNO)				\
   (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
-   ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
-   : (REG_P (OPERANDS[TARGET_OPNO])				\
-      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
-   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
-      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
-   : REG_P (OPERANDS[TARGET_OPNO])				\
-   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"				\
-   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
-\f
+   ? "%*j\t%" #OPNO "%/"					\
+   : REG_P (OPERANDS[OPNO])					\
+   ? "%*jr%:\t%" #OPNO						\
+   : TARGET_ABICALLS && flag_pic				\
+   ? (".option\tpic0\n\t"					\
+      "%*j\t%" #OPNO "%/\n\t"					\
+      ".option\tpic2")						\
+   : "%*j\t%" #OPNO "%/")
+
 /* Control the assembler format that we output.  */
 
 /* Output to assembler file text saying following lines
@@ -2877,7 +2914,7 @@ extern enum processor mips_tune;        /* which c
 extern int mips_isa;			/* architectural level */
 extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
-extern bool mips_base_mips16;
+extern unsigned int mips_base_compression_flags;
 extern GTY(()) struct target_globals *mips16_globals;
 #endif
 
@@ -2923,3 +2960,5 @@ extern GTY(()) struct target_globals *mips16_globa
    with arguments ARGS.  */
 #define PMODE_INSN(NAME, ARGS) \
   (Pmode == SImode ? NAME ## _si ARGS : NAME ## _di ARGS)
+
+#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))
Index: config/mips/t-sde
===================================================================
--- config/mips/t-sde	(revision 195351)
+++ config/mips/t-sde	(working copy)
@@ -16,8 +16,8 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16 msoft-float/mfp64 mcode-readable=no
-MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 sof f64 spram
+MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16/mmicromips msoft-float/mfp64 mcode-readable=no
+MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 micromips sof f64 spram
 MULTILIB_MATCHES = EL=mel EB=meb
 
 # The -mfp64 option is only valid in conjunction with -mips32r2.
@@ -33,3 +33,6 @@ MULTILIB_EXCLUSIONS += !mips32/!mips32r2/mips16
 else
 MULTILIB_EXCLUSIONS += mips64/mips16 mips64r2/mips16
 endif
+
+# The -mcode-readable=no is only in conjunction with -mips16.
+MULTILIB_EXCLUSIONS += mcode-readable=no/!mips16

[-- Attachment #6: gcc-testsuite.cl --]
[-- Type: application/octet-stream, Size: 3848 bytes --]

2013-01-22  Catherine Moore  <clm@codesourcery.com>

	* gcc.target/mips/branch-2.c: Change NOMIPS16 to NOCOMPRESSION.
	* gcc.target/mips/branch-4.c: Likewise.
	* gcc.target/mips/branch-5.c: Likewise.
	* gcc.target/mips/branch-6.c: Likewise.
	* gcc.target/mips/branch-8.c: Likewise.
	* gcc.target/mips/branch-10.c: Likewise.
	* gcc.target/mips/branch-12.c: Likewise.
	* gcc.target/mips/branch-13.c: Likewise.
	* gcc.target/mips/call-1.c: Change NOMIPS16 to NOCOMPRESSION.
	* gcc.target/mips/call-saved-1.c: Add attribute NOMICROMIPS.
	* gcc.target/mips/call-saved-2.c: Likewise.
	* gcc.target/mips/call-saved-3.c: Likewise.
	* gcc.target/mips/gcc-have-sync-compare-and-swap-4.c: Compile with -mno-micromips.
	* gcc.target/mips/lazy-binding-1.c: Change NOMIPS16 to NOCOMPRESSION.
	* gcc.target/mips/long-calls-pg.c: Likewise.
	* gcc.target/mips/loongson-muldiv-1.c: Likewise.
	* gcc.target/mips/loongson-muldiv-2.c: Likewise.
	* gcc.target/mips/loongson3a-muldiv-1.c: Likewise.
	* gcc.target/mips/loongson3a-muldiv-2.c: Likewise.
	* gcc.target/mips/loongson-shift-count-truncated-1.c: Add NOMICROMIPS attribute.
	* gcc.target/mips/loongson-simd.c: Compile with -mno-compression.
	* gcc.target/mips/micromips-lwp-swp-volatile.c: New test.
	* gcc.target/mips/mips-3d-1.c: Change NOMIPS16 to NOCOMPRESSION.
	* gcc.target/mips/mips-3d-2.c: Likewise.
	* gcc.target/mips/mips-3d-3.c: Likewise.
	* gcc.target/mips/mips-3d-4.c: Likewise.
	* gcc.target/mips/mips-3d-5.c: Likewise.
	* gcc.target/mips/mips-3d-6.c: Likewise.
	* gcc.target/mips/mips-3d-9.c: Likewise.
	* gcc.target/mips/mips-3d-7.c: Likewise.
	* gcc.target/mips/mips-3d-8.c: Likewise.
	* gcc.target/mips/mmcount-ra-address-1.c: Likewise.
	* gcc.target/mips/mmcount-ra-address-3.c: Likewise.
	* gcc.target/mips/near-far-1.c
	* gcc.target/mips/near-far-2.c
	* gcc.target/mips/no-smartmips-lwxs.c: Likewise.
	* gcc.target/mips/octeon-baddu-1.c: Change NOMIPS16 to NOCOMPRESSION.
	* gcc.target/mips/octeon-bbit-1.c: Likewise.
	* gcc.target/mips/octeon-bbit-2.c: Likewise.
	* gcc.target/mips/octeon-bbit-3.c: Likewise.
	* gcc.target/mips/octeon-cins-1.c: Likewise.
	* gcc.target/mips/octeon-cins-2.c: Likewise.
	* gcc.target/mips/octeon-dmul-1.c: Likewise.
	* gcc.target/mips/octeon-dmul-2.c: Likewise.
	* gcc.target/mips/octeon-dmul-3.c: Likewise.
	* gcc.target/mips/octeon-exts-1.c: Likewise.
	* gcc.target/mips/octeon-exts-2.c: Likewise.
	* gcc.target/mips/octeon-exts-3.c: Likewise.
	* gcc.target/mips/octeon-exts-5.c: Likewise.
	* gcc.target/mips/octeon-exts-7.c: Likewise.
	* gcc.target/mips/octeon-pipe-1.c: Likewise.
	* gcc.target/mips/octeon-pop-1.c: Likewise.
	* gcc.target/mips/octeon-pop-2.c: Likewise.
	* gcc.target/mips/octeon-seq-3.c: Likewise.
	* gcc.target/mips/octeon-seq-4.c: Likewise.
	* gcc.target/mips/octeon2-lx-2.c: Use attribute NOMICROMIPS.
	* gcc.target/mips/octeon2-lx-3.c: Likewise.
	* gcc.target/mips/octeon2-pipe-1.c: Change NOMIPS16 to NOCOMPRESSION.
	* gcc.target/mips/r10k-cache-barrier-1.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-2.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-3.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-4.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-5.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-6.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-7.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-8.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-9.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-10.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-11.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-12.c: Likewise.
	* gcc.target/mips/r10k-cache-barrier-13.c: Likewise.
	* gcc.target/mips/mips.exp (mips_option_groups): Add -mmicromips
	and -mno-micromips. Pass nomicromips and nocompression attributes
	to all tests.

[-- Attachment #7: gcc-testsuite.patch --]
[-- Type: application/octet-stream, Size: 100417 bytes --]

Index: gcc.target/mips/octeon-pop-1.c
===================================================================
--- gcc.target/mips/octeon-pop-1.c	(revision 195378)
+++ gcc.target/mips/octeon-pop-1.c	(working copy)
@@ -3,13 +3,13 @@
 /* { dg-final { scan-assembler "\tpop\t" } } */
 /* { dg-final { scan-assembler "\tdpop\t" } } */
 
-NOMIPS16 int
+NOCOMPRESSION int
 f (long long a)
 {
   return __builtin_popcountll (a);
 }
 
-NOMIPS16 int
+NOCOMPRESSION int
 g (int a)
 {
   return __builtin_popcount (a);
Index: gcc.target/mips/octeon-dmul-1.c
===================================================================
--- gcc.target/mips/octeon-dmul-1.c	(revision 195378)
+++ gcc.target/mips/octeon-dmul-1.c	(working copy)
@@ -4,7 +4,7 @@
 /* { dg-final { scan-assembler-not "\tdmult\t" } } */
 /* { dg-final { scan-assembler-not "\tmflo\t" } } */
 
-NOMIPS16 long long
+NOCOMPRESSION long long
 f (long long a, long long b)
 {
   return a * b;
Index: gcc.target/mips/loongson-simd.c
===================================================================
--- gcc.target/mips/loongson-simd.c	(revision 195378)
+++ gcc.target/mips/loongson-simd.c	(working copy)
@@ -19,10 +19,10 @@
 <http://www.gnu.org/licenses/>.  */
 
 /* { dg-do run } */
-/* loongson.h does not handle or check for MIPS16ness.  There doesn't
+/* loongson.h does not handle or check for MIPS16 or microMIPS  There doesn't
    seem any good reason for it to, given that the Loongson processors
-   do not support MIPS16.  */
-/* { dg-options "isa=loongson -mhard-float -mno-mips16 -flax-vector-conversions" } */
+   do not support them.  */
+/* { dg-options "isa=loongson -mhard-float -mno-compression -flax-vector-conversions" } */
 
 #include "loongson.h"
 #include <stdio.h>
Index: gcc.target/mips/r10k-cache-barrier-1.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-1.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-1.c	(working copy)
@@ -4,7 +4,7 @@
    cache barriers.  */
 
 #define TEST(ADDR)					\
-  NOMIPS16 void						\
+  NOCOMPRESSION void						\
   test_##ADDR (int n)					\
   {							\
     while (n--)						\
Index: gcc.target/mips/octeon-exts-1.c
===================================================================
--- gcc.target/mips/octeon-exts-1.c	(revision 195378)
+++ gcc.target/mips/octeon-exts-1.c	(working copy)
@@ -9,7 +9,7 @@
   long long c:38;
 };
 
-NOMIPS16 int
+NOCOMPRESSION int
 f (struct foo s)
 {
   return s.b;
Index: gcc.target/mips/r10k-cache-barrier-9.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-9.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-9.c	(working copy)
@@ -5,7 +5,7 @@
 
 struct { struct { char i[4]; } a; struct { char j[4]; } b; } s;
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int sel1, int sel2, int sel3)
 {
   if (sel1)
Index: gcc.target/mips/call-saved-3.c
===================================================================
--- gcc.target/mips/call-saved-3.c	(revision 195378)
+++ gcc.target/mips/call-saved-3.c	(working copy)
@@ -5,7 +5,7 @@
 void bar (void);
 extern int buf[];
 
-MIPS16 void
+MIPS16 NOMICROMIPS void
 foo (int x)
 {
   if (__builtin_setjmp (buf) == 0)
Index: gcc.target/mips/loongson3a-muldiv-1.c
===================================================================
--- gcc.target/mips/loongson3a-muldiv-1.c	(revision 195378)
+++ gcc.target/mips/loongson3a-muldiv-1.c	(working copy)
@@ -3,11 +3,11 @@
 typedef int st;
 typedef unsigned int ut;
 
-NOMIPS16 st smul (st x, st y) { return x * y; }
-NOMIPS16 st sdiv (st x, st y) { return x / y + x % y; }
+NOCOMPRESSION st smul (st x, st y) { return x * y; }
+NOCOMPRESSION st sdiv (st x, st y) { return x / y + x % y; }
 
-NOMIPS16 ut umul (ut x, ut y) { return x * y; }
-NOMIPS16 ut udiv (ut x, ut y) { return x / y + x % y; }
+NOCOMPRESSION ut umul (ut x, ut y) { return x * y; }
+NOCOMPRESSION ut udiv (ut x, ut y) { return x / y + x % y; }
 
 /* { dg-final { scan-assembler-times "\tgsmultu\t" 2 } } */
 /* { dg-final { scan-assembler-times "\tgsdivu\t" 1 } } */
Index: gcc.target/mips/branch-13.c
===================================================================
--- gcc.target/mips/branch-13.c	(revision 195378)
+++ gcc.target/mips/branch-13.c	(working copy)
@@ -8,7 +8,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int (*bar) (void), int *x)
 {
   *x = bar ();
Index: gcc.target/mips/mips-3d-6.c
===================================================================
--- gcc.target/mips/mips-3d-6.c	(revision 195378)
+++ gcc.target/mips/mips-3d-6.c	(working copy)
@@ -5,24 +5,24 @@
 #include <stdlib.h>
 #include <stdio.h>
 
-NOMIPS16 int test0 (float a, float b);
-NOMIPS16 int test1 (float a, float b);
-NOMIPS16 int test2 (float a, float b);
-NOMIPS16 int test3 (float a, float b);
-NOMIPS16 int test4 (float a, float b);
-NOMIPS16 int test5 (float a, float b);
-NOMIPS16 int test6 (float a, float b);
-NOMIPS16 int test7 (float a, float b);
-NOMIPS16 int test8 (float a, float b);
-NOMIPS16 int test9 (float a, float b);
-NOMIPS16 int test10 (float a, float b);
-NOMIPS16 int test11 (float a, float b);
-NOMIPS16 int test12 (float a, float b);
-NOMIPS16 int test13 (float a, float b);
-NOMIPS16 int test14 (float a, float b);
-NOMIPS16 int test15 (float a, float b);
+NOCOMPRESSION int test0 (float a, float b);
+NOCOMPRESSION int test1 (float a, float b);
+NOCOMPRESSION int test2 (float a, float b);
+NOCOMPRESSION int test3 (float a, float b);
+NOCOMPRESSION int test4 (float a, float b);
+NOCOMPRESSION int test5 (float a, float b);
+NOCOMPRESSION int test6 (float a, float b);
+NOCOMPRESSION int test7 (float a, float b);
+NOCOMPRESSION int test8 (float a, float b);
+NOCOMPRESSION int test9 (float a, float b);
+NOCOMPRESSION int test10 (float a, float b);
+NOCOMPRESSION int test11 (float a, float b);
+NOCOMPRESSION int test12 (float a, float b);
+NOCOMPRESSION int test13 (float a, float b);
+NOCOMPRESSION int test14 (float a, float b);
+NOCOMPRESSION int test15 (float a, float b);
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   float a, b;
   int i;
@@ -203,82 +203,82 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (float a, float b)
+NOCOMPRESSION int test0 (float a, float b)
 {
   return __builtin_mips_cabs_f_s (a, b);
 }
 
-NOMIPS16 int test1 (float a, float b)
+NOCOMPRESSION int test1 (float a, float b)
 {
   return __builtin_mips_cabs_un_s (a, b);
 }
 
-NOMIPS16 int test2 (float a, float b)
+NOCOMPRESSION int test2 (float a, float b)
 {
   return __builtin_mips_cabs_eq_s (a, b);
 }
 
-NOMIPS16 int test3 (float a, float b)
+NOCOMPRESSION int test3 (float a, float b)
 {
   return __builtin_mips_cabs_ueq_s (a, b);
 }
 
-NOMIPS16 int test4 (float a, float b)
+NOCOMPRESSION int test4 (float a, float b)
 {
   return __builtin_mips_cabs_olt_s (a, b);
 }
 
-NOMIPS16 int test5 (float a, float b)
+NOCOMPRESSION int test5 (float a, float b)
 {
   return __builtin_mips_cabs_ult_s (a, b);
 }
 
-NOMIPS16 int test6 (float a, float b)
+NOCOMPRESSION int test6 (float a, float b)
 {
   return __builtin_mips_cabs_ole_s (a, b);
 }
 
-NOMIPS16 int test7 (float a, float b)
+NOCOMPRESSION int test7 (float a, float b)
 {
   return __builtin_mips_cabs_ule_s (a, b);
 }
 
-NOMIPS16 int test8 (float a, float b)
+NOCOMPRESSION int test8 (float a, float b)
 {
   return __builtin_mips_cabs_sf_s (a, b);
 }
 
-NOMIPS16 int test9 (float a, float b)
+NOCOMPRESSION int test9 (float a, float b)
 {
   return __builtin_mips_cabs_ngle_s (a, b);
 }
 
-NOMIPS16 int test10 (float a, float b)
+NOCOMPRESSION int test10 (float a, float b)
 {
   return __builtin_mips_cabs_seq_s (a, b);
 }
 
-NOMIPS16 int test11 (float a, float b)
+NOCOMPRESSION int test11 (float a, float b)
 {
   return __builtin_mips_cabs_ngl_s (a, b);
 }
 
-NOMIPS16 int test12 (float a, float b)
+NOCOMPRESSION int test12 (float a, float b)
 {
   return __builtin_mips_cabs_lt_s (a, b);
 }
 
-NOMIPS16 int test13 (float a, float b)
+NOCOMPRESSION int test13 (float a, float b)
 {
   return __builtin_mips_cabs_nge_s (a, b);
 }
 
-NOMIPS16 int test14 (float a, float b)
+NOCOMPRESSION int test14 (float a, float b)
 {
   return __builtin_mips_cabs_le_s (a, b);
 }
 
-NOMIPS16 int test15 (float a, float b)
+NOCOMPRESSION int test15 (float a, float b)
 {
   return __builtin_mips_cabs_ngt_s (a, b);
 }
Index: gcc.target/mips/loongson-muldiv-2.c
===================================================================
--- gcc.target/mips/loongson-muldiv-2.c	(revision 195378)
+++ gcc.target/mips/loongson-muldiv-2.c	(working copy)
@@ -3,11 +3,11 @@
 typedef long long st;
 typedef unsigned long long ut;
 
-NOMIPS16 st smul (st x, st y) { return x * y; }
-NOMIPS16 st sdiv (st x, st y) { return x / y + x % y; }
+NOCOMPRESSION st smul (st x, st y) { return x * y; }
+NOCOMPRESSION st sdiv (st x, st y) { return x / y + x % y; }
 
-NOMIPS16 ut umul (ut x, ut y) { return x * y; }
-NOMIPS16 ut udiv (ut x, ut y) { return x / y + x % y; }
+NOCOMPRESSION ut umul (ut x, ut y) { return x * y; }
+NOCOMPRESSION ut udiv (ut x, ut y) { return x / y + x % y; }
 
 /* { dg-final { scan-assembler-times "\tdmultu.g\t" 2 } } */
 /* { dg-final { scan-assembler-times "\tddivu.g\t" 1 } } */
Index: gcc.target/mips/call-1.c
===================================================================
--- gcc.target/mips/call-1.c	(revision 195378)
+++ gcc.target/mips/call-1.c	(working copy)
@@ -10,7 +10,7 @@
 int normal ();
 void normal2 ();
 
-NOMIPS16 f (int *p)
+NOCOMPRESSION f (int *p)
 {
   *p = normal ();
   normal2 ();
@@ -20,14 +20,14 @@
 
 int tail ();
 
-NOMIPS16 h ()
+NOCOMPRESSION h ()
 {
   return tail ();
 }
 
 void tail2 ();
 
-NOMIPS16 void g ()
+NOCOMPRESSION void g ()
 {
   tail2 ();
 }
Index: gcc.target/mips/mips.exp
===================================================================
--- gcc.target/mips/mips.exp	(revision 195378)
+++ gcc.target/mips/mips.exp	(working copy)
@@ -238,6 +238,7 @@
     fp "-mfp(32|64)"
     gp "-mgp(32|64)"
     long "-mlong(32|64)"
+    micromips "-mmicromips|-mno-micromips"
     mips16 "-mips16|-mno-mips16|-mflip-mips16"
     mips3d "-mips3d|-mno-mips3d"
     pic "-f(no-|)(pic|PIC)"
@@ -1275,6 +1276,6 @@
 dg-init
 mips-dg-init
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
-    "-DNOMIPS16=__attribute__((nomips16))"
+    "-DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression))"
 mips-dg-finish
 dg-finish
Index: gcc.target/mips/octeon-pop-2.c
===================================================================
--- gcc.target/mips/octeon-pop-2.c	(revision 195378)
+++ gcc.target/mips/octeon-pop-2.c	(working copy)
@@ -4,7 +4,7 @@
 /* The pop instruction does not depend on the word value to be sign extended. */
 /* { dg-final { scan-assembler-not "sll\t" } } */
 
-NOMIPS16 long long f(long long i)
+NOCOMPRESSION long long f(long long i)
 {
   return __builtin_popcount (i);
 }
Index: gcc.target/mips/octeon-dmul-2.c
===================================================================
--- gcc.target/mips/octeon-dmul-2.c	(revision 195378)
+++ gcc.target/mips/octeon-dmul-2.c	(working copy)
@@ -3,7 +3,7 @@
 /* { dg-skip-if "using DMUL is no worse size-wise, and can be better if the constant is used elsewhere" { *-*-* } { "-Os" } { "" } } */
 /* { dg-final { scan-assembler-not "\tdmul" } } */
 
-NOMIPS16 long long
+NOCOMPRESSION long long
 f (long long a)
 {
   return a * 7;
Index: gcc.target/mips/octeon2-lx-2.c
===================================================================
--- gcc.target/mips/octeon2-lx-2.c	(revision 195378)
+++ gcc.target/mips/octeon2-lx-2.c	(working copy)
@@ -3,8 +3,8 @@
 /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
 
 #define TEST(N, T) \
-  T f##N (T *p, int i) { return p[i]; } \
-  unsigned T g##N (unsigned T *p, int i) { return p[i]; }
+  T NOMICROMIPS f##N (T *p, int i) { return p[i]; } \
+  unsigned T NOMICROMIPS g##N (unsigned T *p, int i) { return p[i]; }
 
 TEST (1, char)
 /* { dg-final { scan-assembler-times "\tlbu?x\t" 2 } } */
Index: gcc.target/mips/r10k-cache-barrier-2.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-2.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-2.c	(working copy)
@@ -4,7 +4,7 @@
    by cache barriers.  */
 
 #define TEST(ADDR)					\
-  NOMIPS16 void						\
+  NOCOMPRESSION void						\
   test_##ADDR (int n)					\
   {							\
     *(volatile int *) (0x##ADDR##UL) = 1;		\
Index: gcc.target/mips/octeon2-pipe-1.c
===================================================================
--- gcc.target/mips/octeon2-pipe-1.c	(revision 195378)
+++ gcc.target/mips/octeon2-pipe-1.c	(working copy)
@@ -3,7 +3,7 @@
 /* { dg-options "-fschedule-insns2 -fdump-rtl-sched2 -march=octeon2" } */
 /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
 
-NOMIPS16 int f (int a, int b)
+NOCOMPRESSION int f (int a, int b)
 {
   return a / b;
 }
Index: gcc.target/mips/octeon-exts-2.c
===================================================================
--- gcc.target/mips/octeon-exts-2.c	(revision 195378)
+++ gcc.target/mips/octeon-exts-2.c	(working copy)
@@ -11,19 +11,19 @@
   long long d:1;
 };
 
-NOMIPS16 int
+NOCOMPRESSION int
 f1 (struct bar *s, int a)
 {
   return (int) s->b + a;
 }
 
-NOMIPS16 char
+NOCOMPRESSION char
 f2 (struct bar *s)
 {
   return s->d + 1;
 }
 
-NOMIPS16 int
+NOCOMPRESSION int
 f3 ()
 {
   struct bar s;
@@ -31,7 +31,7 @@
   return (int) s.b + 1;
 }
 
-NOMIPS16 long long
+NOCOMPRESSION long long
 f4 (struct bar *s)
 {
   return s->d;
Index: gcc.target/mips/loongson3a-muldiv-2.c
===================================================================
--- gcc.target/mips/loongson3a-muldiv-2.c	(revision 195378)
+++ gcc.target/mips/loongson3a-muldiv-2.c	(working copy)
@@ -3,11 +3,11 @@
 typedef long long st;
 typedef unsigned long long ut;
 
-NOMIPS16 st smul (st x, st y) { return x * y; }
-NOMIPS16 st sdiv (st x, st y) { return x / y + x % y; }
+NOCOMPRESSION st smul (st x, st y) { return x * y; }
+NOCOMPRESSION st sdiv (st x, st y) { return x / y + x % y; }
 
-NOMIPS16 ut umul (ut x, ut y) { return x * y; }
-NOMIPS16 ut udiv (ut x, ut y) { return x / y + x % y; }
+NOCOMPRESSION ut umul (ut x, ut y) { return x * y; }
+NOCOMPRESSION ut udiv (ut x, ut y) { return x / y + x % y; }
 
 /* { dg-final { scan-assembler-times "\tgsdmultu\t" 2 } } */
 /* { dg-final { scan-assembler-times "\tgsddivu\t" 1 } } */
Index: gcc.target/mips/mips-3d-7.c
===================================================================
--- gcc.target/mips/mips-3d-7.c	(revision 195378)
+++ gcc.target/mips/mips-3d-7.c	(working copy)
@@ -5,24 +5,24 @@
 #include <stdlib.h>
 #include <stdio.h>
 
-NOMIPS16 int test0 (double a, double b);
-NOMIPS16 int test1 (double a, double b);
-NOMIPS16 int test2 (double a, double b);
-NOMIPS16 int test3 (double a, double b);
-NOMIPS16 int test4 (double a, double b);
-NOMIPS16 int test5 (double a, double b);
-NOMIPS16 int test6 (double a, double b);
-NOMIPS16 int test7 (double a, double b);
-NOMIPS16 int test8 (double a, double b);
-NOMIPS16 int test9 (double a, double b);
-NOMIPS16 int test10 (double a, double b);
-NOMIPS16 int test11 (double a, double b);
-NOMIPS16 int test12 (double a, double b);
-NOMIPS16 int test13 (double a, double b);
-NOMIPS16 int test14 (double a, double b);
-NOMIPS16 int test15 (double a, double b);
+NOCOMPRESSION int test0 (double a, double b);
+NOCOMPRESSION int test1 (double a, double b);
+NOCOMPRESSION int test2 (double a, double b);
+NOCOMPRESSION int test3 (double a, double b);
+NOCOMPRESSION int test4 (double a, double b);
+NOCOMPRESSION int test5 (double a, double b);
+NOCOMPRESSION int test6 (double a, double b);
+NOCOMPRESSION int test7 (double a, double b);
+NOCOMPRESSION int test8 (double a, double b);
+NOCOMPRESSION int test9 (double a, double b);
+NOCOMPRESSION int test10 (double a, double b);
+NOCOMPRESSION int test11 (double a, double b);
+NOCOMPRESSION int test12 (double a, double b);
+NOCOMPRESSION int test13 (double a, double b);
+NOCOMPRESSION int test14 (double a, double b);
+NOCOMPRESSION int test15 (double a, double b);
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   double a, b;
   int i;
@@ -203,82 +203,82 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (double a, double b)
+NOCOMPRESSION int test0 (double a, double b)
 {
   return __builtin_mips_cabs_f_d (a, b);
 }
 
-NOMIPS16 int test1 (double a, double b)
+NOCOMPRESSION int test1 (double a, double b)
 {
   return __builtin_mips_cabs_un_d (a, b);
 }
 
-NOMIPS16 int test2 (double a, double b)
+NOCOMPRESSION int test2 (double a, double b)
 {
   return __builtin_mips_cabs_eq_d (a, b);
 }
 
-NOMIPS16 int test3 (double a, double b)
+NOCOMPRESSION int test3 (double a, double b)
 {
   return __builtin_mips_cabs_ueq_d (a, b);
 }
 
-NOMIPS16 int test4 (double a, double b)
+NOCOMPRESSION int test4 (double a, double b)
 {
   return __builtin_mips_cabs_olt_d (a, b);
 }
 
-NOMIPS16 int test5 (double a, double b)
+NOCOMPRESSION int test5 (double a, double b)
 {
   return __builtin_mips_cabs_ult_d (a, b);
 }
 
-NOMIPS16 int test6 (double a, double b)
+NOCOMPRESSION int test6 (double a, double b)
 {
   return __builtin_mips_cabs_ole_d (a, b);
 }
 
-NOMIPS16 int test7 (double a, double b)
+NOCOMPRESSION int test7 (double a, double b)
 {
   return __builtin_mips_cabs_ule_d (a, b);
 }
 
-NOMIPS16 int test8 (double a, double b)
+NOCOMPRESSION int test8 (double a, double b)
 {
   return __builtin_mips_cabs_sf_d (a, b);
 }
 
-NOMIPS16 int test9 (double a, double b)
+NOCOMPRESSION int test9 (double a, double b)
 {
   return __builtin_mips_cabs_ngle_d (a, b);
 }
 
-NOMIPS16 int test10 (double a, double b)
+NOCOMPRESSION int test10 (double a, double b)
 {
   return __builtin_mips_cabs_seq_d (a, b);
 }
 
-NOMIPS16 int test11 (double a, double b)
+NOCOMPRESSION int test11 (double a, double b)
 {
   return __builtin_mips_cabs_ngl_d (a, b);
 }
 
-NOMIPS16 int test12 (double a, double b)
+NOCOMPRESSION int test12 (double a, double b)
 {
   return __builtin_mips_cabs_lt_d (a, b);
 }
 
-NOMIPS16 int test13 (double a, double b)
+NOCOMPRESSION int test13 (double a, double b)
 {
   return __builtin_mips_cabs_nge_d (a, b);
 }
 
-NOMIPS16 int test14 (double a, double b)
+NOCOMPRESSION int test14 (double a, double b)
 {
   return __builtin_mips_cabs_le_d (a, b);
 }
 
-NOMIPS16 int test15 (double a, double b)
+NOCOMPRESSION int test15 (double a, double b)
 {
   return __builtin_mips_cabs_ngt_d (a, b);
 }
Index: gcc.target/mips/r10k-cache-barrier-10.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-10.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-10.c	(working copy)
@@ -6,7 +6,7 @@
 /* Test that code after a branch-likely does not get an unnecessary
    cache barrier.  */
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (unsigned char *n)
 {
   /* n starts in $4, but will be in $2 after the call to bar.
Index: gcc.target/mips/branch-4.c
===================================================================
--- gcc.target/mips/branch-4.c	(revision 195378)
+++ gcc.target/mips/branch-4.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (volatile int *x)
 {
   if (__builtin_expect (*x == 0, 1))
Index: gcc.target/mips/mmcount-ra-address-1.c
===================================================================
--- gcc.target/mips/mmcount-ra-address-1.c	(revision 195378)
+++ gcc.target/mips/mmcount-ra-address-1.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-pg -mmcount-ra-address -mabi=64" } */
 /* { dg-final { scan-assembler "\tmove\t\\\$12,\\\$0" } } */
-NOMIPS16 int bazl(int i)
+NOCOMPRESSION int bazl(int i)
 {
   return i + 2;
 }
Index: gcc.target/mips/octeon-bbit-1.c
===================================================================
--- gcc.target/mips/octeon-bbit-1.c	(revision 195378)
+++ gcc.target/mips/octeon-bbit-1.c	(working copy)
@@ -6,37 +6,37 @@
 /* { dg-final { scan-assembler-times "\tbbit.\t" 6 } } */
 /* { dg-final { scan-assembler-not "andi\t" } } */
 
-NOMIPS16 void foo (void);
+NOCOMPRESSION void foo (void);
 
-NOMIPS16 void
+NOCOMPRESSION void
 f1 (long long i)
 {
   if (i & 0x80)
     foo ();
 }
 
-NOMIPS16 void
+NOCOMPRESSION void
 f2 (int i)
 {
   if (!(i & 0x80))
     foo ();
 }
 
-NOMIPS16 void
+NOCOMPRESSION void
 f3 (int i)
 {
   if (i % 2)
     foo ();
 }
 
-NOMIPS16 void
+NOCOMPRESSION void
 f4 (int i)
 {
   if (i & 1)
     foo ();
 }
 
-NOMIPS16 void
+NOCOMPRESSION void
 f5 (long long i)
 {
   if ((i >> 3) & 1)
@@ -45,13 +45,13 @@
 
 unsigned long long r;
 
-NOMIPS16 static inline __attribute__((always_inline)) int
+NOCOMPRESSION static inline __attribute__((always_inline)) int
 test_bit(unsigned long long nr, const unsigned long long *addr)
 {
   return 1UL & (addr[nr >> 6] >> (nr & 63ULL));
 }
 
-NOMIPS16 void
+NOCOMPRESSION void
 f6 ()
 {
   if (!test_bit(0, &r))
Index: gcc.target/mips/no-smartmips-lwxs.c
===================================================================
--- gcc.target/mips/no-smartmips-lwxs.c	(revision 195378)
+++ gcc.target/mips/no-smartmips-lwxs.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mno-smartmips" } */
 
-NOMIPS16 int scaled_indexed_word_load (int a[], int b)
+NOCOMPRESSION int scaled_indexed_word_load (int a[], int b)
 {
   return a[b];
 }
Index: gcc.target/mips/octeon-dmul-3.c
===================================================================
--- gcc.target/mips/octeon-dmul-3.c	(revision 195378)
+++ gcc.target/mips/octeon-dmul-3.c	(working copy)
@@ -5,14 +5,14 @@
 /* { dg-final { scan-assembler-not "\td?mult\t" } } */
 /* { dg-final { scan-assembler-times "\tdext\t" 2 } } */
 
-NOMIPS16 long long
+NOCOMPRESSION long long
 f (int i, int j)
 {
   i++;
   return (long long) i * j;
 }
 
-NOMIPS16 unsigned long long
+NOCOMPRESSION unsigned long long
 g (unsigned int i, unsigned int j)
 {
   i++;
Index: gcc.target/mips/octeon2-lx-3.c
===================================================================
--- gcc.target/mips/octeon2-lx-3.c	(revision 195378)
+++ gcc.target/mips/octeon2-lx-3.c	(working copy)
@@ -3,8 +3,8 @@
 /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
 
 #define TEST(N, T) \
-  T f##N (T *p, int i) { return p[i]; } \
-  unsigned T g##N (unsigned T *p, int i) { return p[i]; }
+  T NOMICROMIPS f##N (T *p, int i) { return p[i]; } \
+  unsigned T NOMICROMIPS g##N (unsigned T *p, int i) { return p[i]; }
 
 TEST (1, char)
 /* { dg-final { scan-assembler-times "\tlbu?x\t" 2 } } */
Index: gcc.target/mips/r10k-cache-barrier-3.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-3.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-3.c	(working copy)
@@ -5,7 +5,7 @@
 
 void bar (int *x);
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int v)
 {
   int x[0x100000];
Index: gcc.target/mips/octeon-exts-3.c
===================================================================
--- gcc.target/mips/octeon-exts-3.c	(revision 195378)
+++ gcc.target/mips/octeon-exts-3.c	(working copy)
@@ -10,7 +10,7 @@
   unsigned long long c:22;
 };
 
-NOMIPS16 unsigned
+NOCOMPRESSION unsigned
 f (struct foo s)
 {
   return s.b;
@@ -23,13 +23,13 @@
   unsigned long long c:1;
 };
 
-NOMIPS16 int
+NOCOMPRESSION int
 g (struct bar s)
 {
   return (int) s.b;
 }
 
-NOMIPS16 int
+NOCOMPRESSION int
 h (int i)
 {
   return (i << 4) >> 24;
Index: gcc.target/mips/mips-3d-8.c
===================================================================
--- gcc.target/mips/mips-3d-8.c	(revision 195378)
+++ gcc.target/mips/mips-3d-8.c	(working copy)
@@ -7,42 +7,42 @@
 
 typedef float v2sf __attribute__((vector_size(8)));
 
-NOMIPS16 v2sf test0 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test1 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test2 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test3 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test4 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test5 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test6 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test7 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test8 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test9 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test10 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test11 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test12 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test13 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test14 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test15 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test16 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test17 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test18 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test19 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test20 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test21 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test22 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test23 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test24 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test25 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test26 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test27 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test28 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test29 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test30 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 v2sf test31 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test0 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test1 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test2 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test3 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test4 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test5 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test6 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test7 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test8 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test9 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test10 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test11 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test12 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test13 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test14 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test15 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test16 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test17 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test18 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test19 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test20 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test21 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test22 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test23 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test24 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test25 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test26 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test27 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test28 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test29 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test30 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION v2sf test31 (v2sf a, v2sf b, v2sf c, v2sf d);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   v2sf a, b, c, d, e, f;
 
@@ -469,162 +469,162 @@
   exit (0);
 }
 
-NOMIPS16 v2sf test0 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test0 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_f_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test1 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test1 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_f_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test2 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test2 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_un_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test3 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test3 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_un_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test4 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test4 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_eq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test5 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test5 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_eq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test6 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test6 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ueq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test7 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test7 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ueq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test8 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test8 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_olt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test9 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test9 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_olt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test10 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test10 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ult_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test11 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test11 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ult_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test12 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test12 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ole_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test13 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test13 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ole_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test14 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test14 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ule_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test15 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test15 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ule_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test16 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test16 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_sf_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test17 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test17 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_sf_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test18 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test18 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ngle_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test19 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test19 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ngle_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test20 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test20 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_seq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test21 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test21 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_seq_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test22 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test22 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ngl_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test23 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test23 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ngl_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test24 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test24 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_lt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test25 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test25 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_lt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test26 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test26 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_nge_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test27 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test27 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_nge_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test28 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test28 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_le_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test29 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test29 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_le_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test30 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test30 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movt_cabs_ngt_ps (a, b, c, d);
 }
 
-NOMIPS16 v2sf test31 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION v2sf test31 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return  __builtin_mips_movf_cabs_ngt_ps (a, b, c, d);
 }
Index: gcc.target/mips/r10k-cache-barrier-11.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-11.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-11.c	(working copy)
@@ -4,7 +4,7 @@
 
 int bar (int);
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int *ptr)
 {
   *ptr = bar (*ptr);
Index: gcc.target/mips/branch-5.c
===================================================================
--- gcc.target/mips/branch-5.c	(revision 195378)
+++ gcc.target/mips/branch-5.c	(working copy)
@@ -6,7 +6,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (volatile int *x)
 {
   if (__builtin_expect (*x == 0, 1))
Index: gcc.target/mips/octeon-bbit-2.c
===================================================================
--- gcc.target/mips/octeon-bbit-2.c	(revision 195378)
+++ gcc.target/mips/octeon-bbit-2.c	(working copy)
@@ -5,7 +5,7 @@
 /* { dg-final { scan-assembler-not "\tbbit\[01\]l\t" } } */
 /* { dg-final { scan-assembler "\tbnel\t" } } */
 
-NOMIPS16 int
+NOCOMPRESSION int
 f (int *a, int *b)
 {
   do
@@ -14,7 +14,7 @@
   while (++a < b);
 }
 
-NOMIPS16 int
+NOCOMPRESSION int
 g (int *a, int *b)
 {
   do
Index: gcc.target/mips/gcc-have-sync-compare-and-swap-4.c
===================================================================
--- gcc.target/mips/gcc-have-sync-compare-and-swap-4.c	(revision 195378)
+++ gcc.target/mips/gcc-have-sync-compare-and-swap-4.c	(working copy)
@@ -1,4 +1,4 @@
-/* { dg-options "-mgp64 -mips16" } */
+/* { dg-options "-mgp64 -mips16 -mno-micromips" } */
 
 #ifndef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_1
 #error nonono
Index: gcc.target/mips/r10k-cache-barrier-4.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-4.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-4.c	(working copy)
@@ -5,7 +5,7 @@
 /* Test that out-of-range stores to the frame are protected by cache
    barriers.  */
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int v)
 {
   int x[8];
Index: gcc.target/mips/mips-3d-1.c
===================================================================
--- gcc.target/mips/mips-3d-1.c	(revision 195378)
+++ gcc.target/mips/mips-3d-1.c	(working copy)
@@ -7,7 +7,7 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   int little_endian;
   v2sf a, b, c, d;
Index: gcc.target/mips/octeon-pipe-1.c
===================================================================
--- gcc.target/mips/octeon-pipe-1.c	(revision 195378)
+++ gcc.target/mips/octeon-pipe-1.c	(working copy)
@@ -3,7 +3,7 @@
 /* { dg-options "-march=octeon -fschedule-insns2 -fdump-rtl-sched2" } */
 /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
 
-NOMIPS16 int f (int a, int b)
+NOCOMPRESSION int f (int a, int b)
 {
   return a / b;
 }
Index: gcc.target/mips/mips-3d-9.c
===================================================================
--- gcc.target/mips/mips-3d-9.c	(revision 195378)
+++ gcc.target/mips/mips-3d-9.c	(working copy)
@@ -19,9 +19,9 @@
 float f[4]; /* Result for matrix_multiply4() */
 
 void matrix_multiply1();
-NOMIPS16 void matrix_multiply2();
-NOMIPS16 void matrix_multiply3();
-NOMIPS16 void matrix_multiply4();
+NOCOMPRESSION void matrix_multiply2();
+NOCOMPRESSION void matrix_multiply3();
+NOCOMPRESSION void matrix_multiply4();
 
 int main ()
 {
@@ -65,7 +65,7 @@
    }
 }
 
-NOMIPS16 void matrix_multiply2()
+NOCOMPRESSION void matrix_multiply2()
 {
   int i, j;
   v2sf m1, m2;
@@ -91,7 +91,7 @@
    }
 }
 
-NOMIPS16 void matrix_multiply3()
+NOCOMPRESSION void matrix_multiply3()
 {
   int i;
   v2sf m1, m2, n1, n2;
@@ -114,7 +114,7 @@
    }
 }
 
-NOMIPS16 void matrix_multiply4()
+NOCOMPRESSION void matrix_multiply4()
 {
   v2sf m1, m2;
   v2sf n1, n2, n3, n4, n5, n6, n7, n8;
Index: gcc.target/mips/r10k-cache-barrier-12.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-12.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-12.c	(working copy)
@@ -4,7 +4,7 @@
 
 int bar (int);
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int *ptr)
 {
   *ptr = bar (*ptr);
Index: gcc.target/mips/near-far-1.c
===================================================================
--- gcc.target/mips/near-far-1.c	(revision 195378)
+++ gcc.target/mips/near-far-1.c	(working copy)
@@ -16,5 +16,5 @@
 
 /* { dg-final { scan-assembler-not "\tjal\tlong_call_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal\tfar_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal\tnear_func\n" } } */
+/* { dg-final { scan-assembler     "\tjals?\tnear_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal\tnormal_func\n" } } */
Index: gcc.target/mips/branch-6.c
===================================================================
--- gcc.target/mips/branch-6.c	(revision 195378)
+++ gcc.target/mips/branch-6.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (volatile int *x)
 {
   if (__builtin_expect (*x == 0, 1))
Index: gcc.target/mips/mmcount-ra-address-3.c
===================================================================
--- gcc.target/mips/mmcount-ra-address-3.c	(revision 195378)
+++ gcc.target/mips/mmcount-ra-address-3.c	(working copy)
@@ -3,7 +3,7 @@
 /* { dg-skip-if "requiring a specific frame layout makes this a code quality test" { *-*-* } { "-O0" } { "" } } */
 /* { dg-final { scan-assembler "\tdla\t\\\$12,200008\\(\\\$sp\\)" } } */
 int foo (int *);
-NOMIPS16 int bar(int i)
+NOCOMPRESSION int bar(int i)
 {
   int big[50000];
   return foo (big) + 2;
Index: gcc.target/mips/octeon-bbit-3.c
===================================================================
--- gcc.target/mips/octeon-bbit-3.c	(revision 195378)
+++ gcc.target/mips/octeon-bbit-3.c	(working copy)
@@ -33,7 +33,7 @@
 
 bitfield_t bar;
 
-NOMIPS16 void
+NOCOMPRESSION void
 f ()
 {
   foo(&bar);
Index: gcc.target/mips/octeon-seq-3.c
===================================================================
--- gcc.target/mips/octeon-seq-3.c	(revision 195378)
+++ gcc.target/mips/octeon-seq-3.c	(working copy)
@@ -7,8 +7,8 @@
 
 
 #define TEST(N, LHS, REL, RHS) \
-  NOMIPS16 long long w##N (int a, int b) {return LHS REL RHS;} \
-  NOMIPS16 int n##N (long long a, long long b) {return LHS REL RHS;} \
+  NOCOMPRESSION long long w##N (int a, int b) {return LHS REL RHS;} \
+  NOCOMPRESSION int n##N (long long a, long long b) {return LHS REL RHS;} \
 
 TEST (eq, a, ==, 10);
 TEST (ne, a, !=, 32);
Index: gcc.target/mips/r10k-cache-barrier-5.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-5.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-5.c	(working copy)
@@ -6,7 +6,7 @@
 int x[4];
 void bar (void);
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int n)
 {
   while (n--)
Index: gcc.target/mips/octeon-exts-5.c
===================================================================
--- gcc.target/mips/octeon-exts-5.c	(revision 195378)
+++ gcc.target/mips/octeon-exts-5.c	(working copy)
@@ -12,19 +12,19 @@
   unsigned long long a:1;
 };
 
-NOMIPS16 int
+NOCOMPRESSION int
 f1 (struct bar *s, int a)
 {
   return (int) s->b + a;
 }
 
-NOMIPS16 char
+NOCOMPRESSION char
 f2 (struct bar *s)
 {
   return s->d + 1;
 }
 
-NOMIPS16 int
+NOCOMPRESSION int
 f3 ()
 {
   struct bar s;
@@ -32,7 +32,7 @@
   return (int) s.b + 1;
 }
 
-NOMIPS16 long long
+NOCOMPRESSION long long
 f4 (struct bar *s)
 {
   return s->d;
Index: gcc.target/mips/mips-3d-2.c
===================================================================
--- gcc.target/mips/mips-3d-2.c	(revision 195378)
+++ gcc.target/mips/mips-3d-2.c	(working copy)
@@ -7,42 +7,42 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int test0 (v2sf a, v2sf b);
-NOMIPS16 int test1 (v2sf a, v2sf b);
-NOMIPS16 int test2 (v2sf a, v2sf b);
-NOMIPS16 int test3 (v2sf a, v2sf b);
-NOMIPS16 int test4 (v2sf a, v2sf b);
-NOMIPS16 int test5 (v2sf a, v2sf b);
-NOMIPS16 int test6 (v2sf a, v2sf b);
-NOMIPS16 int test7 (v2sf a, v2sf b);
-NOMIPS16 int test8 (v2sf a, v2sf b);
-NOMIPS16 int test9 (v2sf a, v2sf b);
-NOMIPS16 int test10 (v2sf a, v2sf b);
-NOMIPS16 int test11 (v2sf a, v2sf b);
-NOMIPS16 int test12 (v2sf a, v2sf b);
-NOMIPS16 int test13 (v2sf a, v2sf b);
-NOMIPS16 int test14 (v2sf a, v2sf b);
-NOMIPS16 int test15 (v2sf a, v2sf b);
-NOMIPS16 int test16 (v2sf a, v2sf b);
-NOMIPS16 int test17 (v2sf a, v2sf b);
-NOMIPS16 int test18 (v2sf a, v2sf b);
-NOMIPS16 int test19 (v2sf a, v2sf b);
-NOMIPS16 int test20 (v2sf a, v2sf b);
-NOMIPS16 int test21 (v2sf a, v2sf b);
-NOMIPS16 int test22 (v2sf a, v2sf b);
-NOMIPS16 int test23 (v2sf a, v2sf b);
-NOMIPS16 int test24 (v2sf a, v2sf b);
-NOMIPS16 int test25 (v2sf a, v2sf b);
-NOMIPS16 int test26 (v2sf a, v2sf b);
-NOMIPS16 int test27 (v2sf a, v2sf b);
-NOMIPS16 int test28 (v2sf a, v2sf b);
-NOMIPS16 int test29 (v2sf a, v2sf b);
-NOMIPS16 int test30 (v2sf a, v2sf b);
-NOMIPS16 int test31 (v2sf a, v2sf b);
+NOCOMPRESSION int test0 (v2sf a, v2sf b);
+NOCOMPRESSION int test1 (v2sf a, v2sf b);
+NOCOMPRESSION int test2 (v2sf a, v2sf b);
+NOCOMPRESSION int test3 (v2sf a, v2sf b);
+NOCOMPRESSION int test4 (v2sf a, v2sf b);
+NOCOMPRESSION int test5 (v2sf a, v2sf b);
+NOCOMPRESSION int test6 (v2sf a, v2sf b);
+NOCOMPRESSION int test7 (v2sf a, v2sf b);
+NOCOMPRESSION int test8 (v2sf a, v2sf b);
+NOCOMPRESSION int test9 (v2sf a, v2sf b);
+NOCOMPRESSION int test10 (v2sf a, v2sf b);
+NOCOMPRESSION int test11 (v2sf a, v2sf b);
+NOCOMPRESSION int test12 (v2sf a, v2sf b);
+NOCOMPRESSION int test13 (v2sf a, v2sf b);
+NOCOMPRESSION int test14 (v2sf a, v2sf b);
+NOCOMPRESSION int test15 (v2sf a, v2sf b);
+NOCOMPRESSION int test16 (v2sf a, v2sf b);
+NOCOMPRESSION int test17 (v2sf a, v2sf b);
+NOCOMPRESSION int test18 (v2sf a, v2sf b);
+NOCOMPRESSION int test19 (v2sf a, v2sf b);
+NOCOMPRESSION int test20 (v2sf a, v2sf b);
+NOCOMPRESSION int test21 (v2sf a, v2sf b);
+NOCOMPRESSION int test22 (v2sf a, v2sf b);
+NOCOMPRESSION int test23 (v2sf a, v2sf b);
+NOCOMPRESSION int test24 (v2sf a, v2sf b);
+NOCOMPRESSION int test25 (v2sf a, v2sf b);
+NOCOMPRESSION int test26 (v2sf a, v2sf b);
+NOCOMPRESSION int test27 (v2sf a, v2sf b);
+NOCOMPRESSION int test28 (v2sf a, v2sf b);
+NOCOMPRESSION int test29 (v2sf a, v2sf b);
+NOCOMPRESSION int test30 (v2sf a, v2sf b);
+NOCOMPRESSION int test31 (v2sf a, v2sf b);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   v2sf a, b, c, d;
   int i, j;
@@ -393,162 +393,162 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (v2sf a, v2sf b)
+NOCOMPRESSION int test0 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_f_ps (a, b);
 }
 
-NOMIPS16 int test1 (v2sf a, v2sf b)
+NOCOMPRESSION int test1 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_f_ps (a, b);
 }
 
-NOMIPS16 int test2 (v2sf a, v2sf b)
+NOCOMPRESSION int test2 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_un_ps (a, b);
 }
 
-NOMIPS16 int test3 (v2sf a, v2sf b)
+NOCOMPRESSION int test3 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_un_ps (a, b);
 }
 
-NOMIPS16 int test4 (v2sf a, v2sf b)
+NOCOMPRESSION int test4 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_eq_ps (a, b);
 }
 
-NOMIPS16 int test5 (v2sf a, v2sf b)
+NOCOMPRESSION int test5 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_eq_ps (a, b);
 }
 
-NOMIPS16 int test6 (v2sf a, v2sf b)
+NOCOMPRESSION int test6 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ueq_ps (a, b);
 }
 
-NOMIPS16 int test7 (v2sf a, v2sf b)
+NOCOMPRESSION int test7 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ueq_ps (a, b);
 }
 
-NOMIPS16 int test8 (v2sf a, v2sf b)
+NOCOMPRESSION int test8 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_olt_ps (a, b);
 }
 
-NOMIPS16 int test9 (v2sf a, v2sf b)
+NOCOMPRESSION int test9 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_olt_ps (a, b);
 }
 
-NOMIPS16 int test10 (v2sf a, v2sf b)
+NOCOMPRESSION int test10 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ult_ps (a, b);
 }
 
-NOMIPS16 int test11 (v2sf a, v2sf b)
+NOCOMPRESSION int test11 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ult_ps (a, b);
 }
 
-NOMIPS16 int test12 (v2sf a, v2sf b)
+NOCOMPRESSION int test12 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ole_ps (a, b);
 }
 
-NOMIPS16 int test13 (v2sf a, v2sf b)
+NOCOMPRESSION int test13 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ole_ps (a, b);
 }
 
-NOMIPS16 int test14 (v2sf a, v2sf b)
+NOCOMPRESSION int test14 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ule_ps (a, b);
 }
 
-NOMIPS16 int test15 (v2sf a, v2sf b)
+NOCOMPRESSION int test15 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ule_ps (a, b);
 }
 
-NOMIPS16 int test16 (v2sf a, v2sf b)
+NOCOMPRESSION int test16 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_sf_ps (a, b);
 }
 
-NOMIPS16 int test17 (v2sf a, v2sf b)
+NOCOMPRESSION int test17 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_sf_ps (a, b);
 }
 
-NOMIPS16 int test18 (v2sf a, v2sf b)
+NOCOMPRESSION int test18 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ngle_ps (a, b);
 }
 
-NOMIPS16 int test19 (v2sf a, v2sf b)
+NOCOMPRESSION int test19 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ngle_ps (a, b);
 }
 
-NOMIPS16 int test20 (v2sf a, v2sf b)
+NOCOMPRESSION int test20 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_seq_ps (a, b);
 }
 
-NOMIPS16 int test21 (v2sf a, v2sf b)
+NOCOMPRESSION int test21 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_seq_ps (a, b);
 }
 
-NOMIPS16 int test22 (v2sf a, v2sf b)
+NOCOMPRESSION int test22 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ngl_ps (a, b);
 }
 
-NOMIPS16 int test23 (v2sf a, v2sf b)
+NOCOMPRESSION int test23 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ngl_ps (a, b);
 }
 
-NOMIPS16 int test24 (v2sf a, v2sf b)
+NOCOMPRESSION int test24 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_lt_ps (a, b);
 }
 
-NOMIPS16 int test25 (v2sf a, v2sf b)
+NOCOMPRESSION int test25 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_lt_ps (a, b);
 }
 
-NOMIPS16 int test26 (v2sf a, v2sf b)
+NOCOMPRESSION int test26 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_nge_ps (a, b);
 }
 
-NOMIPS16 int test27 (v2sf a, v2sf b)
+NOCOMPRESSION int test27 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_nge_ps (a, b);
 }
 
-NOMIPS16 int test28 (v2sf a, v2sf b)
+NOCOMPRESSION int test28 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_le_ps (a, b);
 }
 
-NOMIPS16 int test29 (v2sf a, v2sf b)
+NOCOMPRESSION int test29 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_le_ps (a, b);
 }
 
-NOMIPS16 int test30 (v2sf a, v2sf b)
+NOCOMPRESSION int test30 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_c_ngt_ps (a, b);
 }
 
-NOMIPS16 int test31 (v2sf a, v2sf b)
+NOCOMPRESSION int test31 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_c_ngt_ps (a, b);
 }
Index: gcc.target/mips/r10k-cache-barrier-13.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-13.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-13.c	(working copy)
@@ -4,7 +4,7 @@
 
 int bar (int);
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (void (*fn) (void), int x)
 {
   if (x)
Index: gcc.target/mips/near-far-2.c
===================================================================
--- gcc.target/mips/near-far-2.c	(revision 195378)
+++ gcc.target/mips/near-far-2.c	(working copy)
@@ -16,5 +16,5 @@
 
 /* { dg-final { scan-assembler-not "\tjal\tlong_call_func\n" } } */
 /* { dg-final { scan-assembler-not "\tjal\tfar_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal\tnear_func\n" } } */
-/* { dg-final { scan-assembler     "\tjal\tnormal_func\n" } } */
+/* { dg-final { scan-assembler     "\tjals?\tnear_func\n" } } */
+/* { dg-final { scan-assembler     "\tjals?\tnormal_func\n" } } */
Index: gcc.target/mips/octeon-seq-4.c
===================================================================
--- gcc.target/mips/octeon-seq-4.c	(revision 195378)
+++ gcc.target/mips/octeon-seq-4.c	(working copy)
@@ -6,7 +6,7 @@
 unsigned
 m (unsigned e);
 
-NOMIPS16 void
+NOCOMPRESSION void
 f (unsigned i)
 {
   unsigned j = m (i);
Index: gcc.target/mips/octeon-cins-1.c
===================================================================
--- gcc.target/mips/octeon-cins-1.c	(revision 195378)
+++ gcc.target/mips/octeon-cins-1.c	(working copy)
@@ -6,19 +6,19 @@
 /* { dg-final { scan-assembler-times "\tcins\t" 3 } } */
 /* { dg-final { scan-assembler-not "\tandi\t|sll\t" } } */
 
-NOMIPS16 long long
+NOCOMPRESSION long long
 f (long long i)
 {
   return (i & 0xff) << 34;
 }
 
-NOMIPS16 int
+NOCOMPRESSION int
 g (int i)
 {
   return (i << 4) & 0xff0;
 }
 
-NOMIPS16 long long
+NOCOMPRESSION long long
 h (long long i)
 {
   return (i << 4) & 0xfff;
Index: gcc.target/mips/r10k-cache-barrier-6.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-6.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-6.c	(working copy)
@@ -6,7 +6,7 @@
 /* Test that out-of-range stores to static objects are protected by a
    cache barrier.  */
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int n)
 {
   while (n--)
Index: gcc.target/mips/branch-10.c
===================================================================
--- gcc.target/mips/branch-10.c	(revision 195378)
+++ gcc.target/mips/branch-10.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int (*bar) (void), int *x)
 {
   *x = bar ();
Index: gcc.target/mips/mips-3d-3.c
===================================================================
--- gcc.target/mips/mips-3d-3.c	(revision 195378)
+++ gcc.target/mips/mips-3d-3.c	(working copy)
@@ -7,74 +7,74 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int test0 (v2sf a, v2sf b);
-NOMIPS16 int test1 (v2sf a, v2sf b);
-NOMIPS16 int test2 (v2sf a, v2sf b);
-NOMIPS16 int test3 (v2sf a, v2sf b);
-NOMIPS16 int test4 (v2sf a, v2sf b);
-NOMIPS16 int test5 (v2sf a, v2sf b);
-NOMIPS16 int test6 (v2sf a, v2sf b);
-NOMIPS16 int test7 (v2sf a, v2sf b);
-NOMIPS16 int test8 (v2sf a, v2sf b);
-NOMIPS16 int test9 (v2sf a, v2sf b);
-NOMIPS16 int test10 (v2sf a, v2sf b);
-NOMIPS16 int test11 (v2sf a, v2sf b);
-NOMIPS16 int test12 (v2sf a, v2sf b);
-NOMIPS16 int test13 (v2sf a, v2sf b);
-NOMIPS16 int test14 (v2sf a, v2sf b);
-NOMIPS16 int test15 (v2sf a, v2sf b);
-NOMIPS16 int test16 (v2sf a, v2sf b);
-NOMIPS16 int test17 (v2sf a, v2sf b);
-NOMIPS16 int test18 (v2sf a, v2sf b);
-NOMIPS16 int test19 (v2sf a, v2sf b);
-NOMIPS16 int test20 (v2sf a, v2sf b);
-NOMIPS16 int test21 (v2sf a, v2sf b);
-NOMIPS16 int test22 (v2sf a, v2sf b);
-NOMIPS16 int test23 (v2sf a, v2sf b);
-NOMIPS16 int test24 (v2sf a, v2sf b);
-NOMIPS16 int test25 (v2sf a, v2sf b);
-NOMIPS16 int test26 (v2sf a, v2sf b);
-NOMIPS16 int test27 (v2sf a, v2sf b);
-NOMIPS16 int test28 (v2sf a, v2sf b);
-NOMIPS16 int test29 (v2sf a, v2sf b);
-NOMIPS16 int test30 (v2sf a, v2sf b);
-NOMIPS16 int test31 (v2sf a, v2sf b);
-NOMIPS16 int test32 (v2sf a, v2sf b);
-NOMIPS16 int test33 (v2sf a, v2sf b);
-NOMIPS16 int test34 (v2sf a, v2sf b);
-NOMIPS16 int test35 (v2sf a, v2sf b);
-NOMIPS16 int test36 (v2sf a, v2sf b);
-NOMIPS16 int test37 (v2sf a, v2sf b);
-NOMIPS16 int test38 (v2sf a, v2sf b);
-NOMIPS16 int test39 (v2sf a, v2sf b);
-NOMIPS16 int test40 (v2sf a, v2sf b);
-NOMIPS16 int test41 (v2sf a, v2sf b);
-NOMIPS16 int test42 (v2sf a, v2sf b);
-NOMIPS16 int test43 (v2sf a, v2sf b);
-NOMIPS16 int test44 (v2sf a, v2sf b);
-NOMIPS16 int test45 (v2sf a, v2sf b);
-NOMIPS16 int test46 (v2sf a, v2sf b);
-NOMIPS16 int test47 (v2sf a, v2sf b);
-NOMIPS16 int test48 (v2sf a, v2sf b);
-NOMIPS16 int test49 (v2sf a, v2sf b);
-NOMIPS16 int test50 (v2sf a, v2sf b);
-NOMIPS16 int test51 (v2sf a, v2sf b);
-NOMIPS16 int test52 (v2sf a, v2sf b);
-NOMIPS16 int test53 (v2sf a, v2sf b);
-NOMIPS16 int test54 (v2sf a, v2sf b);
-NOMIPS16 int test55 (v2sf a, v2sf b);
-NOMIPS16 int test56 (v2sf a, v2sf b);
-NOMIPS16 int test57 (v2sf a, v2sf b);
-NOMIPS16 int test58 (v2sf a, v2sf b);
-NOMIPS16 int test59 (v2sf a, v2sf b);
-NOMIPS16 int test60 (v2sf a, v2sf b);
-NOMIPS16 int test61 (v2sf a, v2sf b);
-NOMIPS16 int test62 (v2sf a, v2sf b);
-NOMIPS16 int test63 (v2sf a, v2sf b);
+NOCOMPRESSION int test0 (v2sf a, v2sf b);
+NOCOMPRESSION int test1 (v2sf a, v2sf b);
+NOCOMPRESSION int test2 (v2sf a, v2sf b);
+NOCOMPRESSION int test3 (v2sf a, v2sf b);
+NOCOMPRESSION int test4 (v2sf a, v2sf b);
+NOCOMPRESSION int test5 (v2sf a, v2sf b);
+NOCOMPRESSION int test6 (v2sf a, v2sf b);
+NOCOMPRESSION int test7 (v2sf a, v2sf b);
+NOCOMPRESSION int test8 (v2sf a, v2sf b);
+NOCOMPRESSION int test9 (v2sf a, v2sf b);
+NOCOMPRESSION int test10 (v2sf a, v2sf b);
+NOCOMPRESSION int test11 (v2sf a, v2sf b);
+NOCOMPRESSION int test12 (v2sf a, v2sf b);
+NOCOMPRESSION int test13 (v2sf a, v2sf b);
+NOCOMPRESSION int test14 (v2sf a, v2sf b);
+NOCOMPRESSION int test15 (v2sf a, v2sf b);
+NOCOMPRESSION int test16 (v2sf a, v2sf b);
+NOCOMPRESSION int test17 (v2sf a, v2sf b);
+NOCOMPRESSION int test18 (v2sf a, v2sf b);
+NOCOMPRESSION int test19 (v2sf a, v2sf b);
+NOCOMPRESSION int test20 (v2sf a, v2sf b);
+NOCOMPRESSION int test21 (v2sf a, v2sf b);
+NOCOMPRESSION int test22 (v2sf a, v2sf b);
+NOCOMPRESSION int test23 (v2sf a, v2sf b);
+NOCOMPRESSION int test24 (v2sf a, v2sf b);
+NOCOMPRESSION int test25 (v2sf a, v2sf b);
+NOCOMPRESSION int test26 (v2sf a, v2sf b);
+NOCOMPRESSION int test27 (v2sf a, v2sf b);
+NOCOMPRESSION int test28 (v2sf a, v2sf b);
+NOCOMPRESSION int test29 (v2sf a, v2sf b);
+NOCOMPRESSION int test30 (v2sf a, v2sf b);
+NOCOMPRESSION int test31 (v2sf a, v2sf b);
+NOCOMPRESSION int test32 (v2sf a, v2sf b);
+NOCOMPRESSION int test33 (v2sf a, v2sf b);
+NOCOMPRESSION int test34 (v2sf a, v2sf b);
+NOCOMPRESSION int test35 (v2sf a, v2sf b);
+NOCOMPRESSION int test36 (v2sf a, v2sf b);
+NOCOMPRESSION int test37 (v2sf a, v2sf b);
+NOCOMPRESSION int test38 (v2sf a, v2sf b);
+NOCOMPRESSION int test39 (v2sf a, v2sf b);
+NOCOMPRESSION int test40 (v2sf a, v2sf b);
+NOCOMPRESSION int test41 (v2sf a, v2sf b);
+NOCOMPRESSION int test42 (v2sf a, v2sf b);
+NOCOMPRESSION int test43 (v2sf a, v2sf b);
+NOCOMPRESSION int test44 (v2sf a, v2sf b);
+NOCOMPRESSION int test45 (v2sf a, v2sf b);
+NOCOMPRESSION int test46 (v2sf a, v2sf b);
+NOCOMPRESSION int test47 (v2sf a, v2sf b);
+NOCOMPRESSION int test48 (v2sf a, v2sf b);
+NOCOMPRESSION int test49 (v2sf a, v2sf b);
+NOCOMPRESSION int test50 (v2sf a, v2sf b);
+NOCOMPRESSION int test51 (v2sf a, v2sf b);
+NOCOMPRESSION int test52 (v2sf a, v2sf b);
+NOCOMPRESSION int test53 (v2sf a, v2sf b);
+NOCOMPRESSION int test54 (v2sf a, v2sf b);
+NOCOMPRESSION int test55 (v2sf a, v2sf b);
+NOCOMPRESSION int test56 (v2sf a, v2sf b);
+NOCOMPRESSION int test57 (v2sf a, v2sf b);
+NOCOMPRESSION int test58 (v2sf a, v2sf b);
+NOCOMPRESSION int test59 (v2sf a, v2sf b);
+NOCOMPRESSION int test60 (v2sf a, v2sf b);
+NOCOMPRESSION int test61 (v2sf a, v2sf b);
+NOCOMPRESSION int test62 (v2sf a, v2sf b);
+NOCOMPRESSION int test63 (v2sf a, v2sf b);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   int little_endian;
   v2sf a, b, c, d;
@@ -774,322 +774,322 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (v2sf a, v2sf b)
+NOCOMPRESSION int test0 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_f_ps (a, b);
 }
 
-NOMIPS16 int test1 (v2sf a, v2sf b)
+NOCOMPRESSION int test1 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_f_ps (a, b);
 }
 
-NOMIPS16 int test2 (v2sf a, v2sf b)
+NOCOMPRESSION int test2 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_f_ps (a, b);
 }
 
-NOMIPS16 int test3 (v2sf a, v2sf b)
+NOCOMPRESSION int test3 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_f_ps (a, b);
 }
 
-NOMIPS16 int test4 (v2sf a, v2sf b)
+NOCOMPRESSION int test4 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_un_ps (a, b);
 }
 
-NOMIPS16 int test5 (v2sf a, v2sf b)
+NOCOMPRESSION int test5 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_un_ps (a, b);
 }
 
-NOMIPS16 int test6 (v2sf a, v2sf b)
+NOCOMPRESSION int test6 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_un_ps (a, b);
 }
 
-NOMIPS16 int test7 (v2sf a, v2sf b)
+NOCOMPRESSION int test7 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_un_ps (a, b);
 }
 
-NOMIPS16 int test8 (v2sf a, v2sf b)
+NOCOMPRESSION int test8 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_eq_ps (a, b);
 }
 
-NOMIPS16 int test9 (v2sf a, v2sf b)
+NOCOMPRESSION int test9 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_eq_ps (a, b);
 }
 
-NOMIPS16 int test10 (v2sf a, v2sf b)
+NOCOMPRESSION int test10 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_eq_ps (a, b);
 }
 
-NOMIPS16 int test11 (v2sf a, v2sf b)
+NOCOMPRESSION int test11 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_eq_ps (a, b);
 }
 
-NOMIPS16 int test12 (v2sf a, v2sf b)
+NOCOMPRESSION int test12 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ueq_ps (a, b);
 }
 
-NOMIPS16 int test13 (v2sf a, v2sf b)
+NOCOMPRESSION int test13 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ueq_ps (a, b);
 }
 
-NOMIPS16 int test14 (v2sf a, v2sf b)
+NOCOMPRESSION int test14 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ueq_ps (a, b);
 }
 
-NOMIPS16 int test15 (v2sf a, v2sf b)
+NOCOMPRESSION int test15 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ueq_ps (a, b);
 }
 
-NOMIPS16 int test16 (v2sf a, v2sf b)
+NOCOMPRESSION int test16 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_olt_ps (a, b);
 }
 
-NOMIPS16 int test17 (v2sf a, v2sf b)
+NOCOMPRESSION int test17 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_olt_ps (a, b);
 }
 
-NOMIPS16 int test18 (v2sf a, v2sf b)
+NOCOMPRESSION int test18 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_olt_ps (a, b);
 }
 
-NOMIPS16 int test19 (v2sf a, v2sf b)
+NOCOMPRESSION int test19 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_olt_ps (a, b);
 }
 
-NOMIPS16 int test20 (v2sf a, v2sf b)
+NOCOMPRESSION int test20 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ult_ps (a, b);
 }
 
-NOMIPS16 int test21 (v2sf a, v2sf b)
+NOCOMPRESSION int test21 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ult_ps (a, b);
 }
 
-NOMIPS16 int test22 (v2sf a, v2sf b)
+NOCOMPRESSION int test22 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ult_ps (a, b);
 }
 
-NOMIPS16 int test23 (v2sf a, v2sf b)
+NOCOMPRESSION int test23 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ult_ps (a, b);
 }
 
-NOMIPS16 int test24 (v2sf a, v2sf b)
+NOCOMPRESSION int test24 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ole_ps (a, b);
 }
 
-NOMIPS16 int test25 (v2sf a, v2sf b)
+NOCOMPRESSION int test25 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ole_ps (a, b);
 }
 
-NOMIPS16 int test26 (v2sf a, v2sf b)
+NOCOMPRESSION int test26 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ole_ps (a, b);
 }
 
-NOMIPS16 int test27 (v2sf a, v2sf b)
+NOCOMPRESSION int test27 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ole_ps (a, b);
 }
 
-NOMIPS16 int test28 (v2sf a, v2sf b)
+NOCOMPRESSION int test28 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ule_ps (a, b);
 }
 
-NOMIPS16 int test29 (v2sf a, v2sf b)
+NOCOMPRESSION int test29 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ule_ps (a, b);
 }
 
-NOMIPS16 int test30 (v2sf a, v2sf b)
+NOCOMPRESSION int test30 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ule_ps (a, b);
 }
 
-NOMIPS16 int test31 (v2sf a, v2sf b)
+NOCOMPRESSION int test31 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ule_ps (a, b);
 }
 
-NOMIPS16 int test32 (v2sf a, v2sf b)
+NOCOMPRESSION int test32 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_sf_ps (a, b);
 }
 
-NOMIPS16 int test33 (v2sf a, v2sf b)
+NOCOMPRESSION int test33 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_sf_ps (a, b);
 }
 
-NOMIPS16 int test34 (v2sf a, v2sf b)
+NOCOMPRESSION int test34 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_sf_ps (a, b);
 }
 
-NOMIPS16 int test35 (v2sf a, v2sf b)
+NOCOMPRESSION int test35 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_sf_ps (a, b);
 }
 
-NOMIPS16 int test36 (v2sf a, v2sf b)
+NOCOMPRESSION int test36 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ngle_ps (a, b);
 }
 
-NOMIPS16 int test37 (v2sf a, v2sf b)
+NOCOMPRESSION int test37 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ngle_ps (a, b);
 }
 
-NOMIPS16 int test38 (v2sf a, v2sf b)
+NOCOMPRESSION int test38 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ngle_ps (a, b);
 }
 
-NOMIPS16 int test39 (v2sf a, v2sf b)
+NOCOMPRESSION int test39 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ngle_ps (a, b);
 }
 
-NOMIPS16 int test40 (v2sf a, v2sf b)
+NOCOMPRESSION int test40 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_seq_ps (a, b);
 }
 
-NOMIPS16 int test41 (v2sf a, v2sf b)
+NOCOMPRESSION int test41 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_seq_ps (a, b);
 }
 
-NOMIPS16 int test42 (v2sf a, v2sf b)
+NOCOMPRESSION int test42 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_seq_ps (a, b);
 }
 
-NOMIPS16 int test43 (v2sf a, v2sf b)
+NOCOMPRESSION int test43 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_seq_ps (a, b);
 }
 
-NOMIPS16 int test44 (v2sf a, v2sf b)
+NOCOMPRESSION int test44 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ngl_ps (a, b);
 }
 
-NOMIPS16 int test45 (v2sf a, v2sf b)
+NOCOMPRESSION int test45 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ngl_ps (a, b);
 }
 
-NOMIPS16 int test46 (v2sf a, v2sf b)
+NOCOMPRESSION int test46 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ngl_ps (a, b);
 }
 
-NOMIPS16 int test47 (v2sf a, v2sf b)
+NOCOMPRESSION int test47 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ngl_ps (a, b);
 }
 
-NOMIPS16 int test48 (v2sf a, v2sf b)
+NOCOMPRESSION int test48 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_lt_ps (a, b);
 }
 
-NOMIPS16 int test49 (v2sf a, v2sf b)
+NOCOMPRESSION int test49 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_lt_ps (a, b);
 }
 
-NOMIPS16 int test50 (v2sf a, v2sf b)
+NOCOMPRESSION int test50 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_lt_ps (a, b);
 }
 
-NOMIPS16 int test51 (v2sf a, v2sf b)
+NOCOMPRESSION int test51 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_lt_ps (a, b);
 }
 
-NOMIPS16 int test52 (v2sf a, v2sf b)
+NOCOMPRESSION int test52 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_nge_ps (a, b);
 }
 
-NOMIPS16 int test53 (v2sf a, v2sf b)
+NOCOMPRESSION int test53 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_nge_ps (a, b);
 }
 
-NOMIPS16 int test54 (v2sf a, v2sf b)
+NOCOMPRESSION int test54 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_nge_ps (a, b);
 }
 
-NOMIPS16 int test55 (v2sf a, v2sf b)
+NOCOMPRESSION int test55 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_nge_ps (a, b);
 }
 
-NOMIPS16 int test56 (v2sf a, v2sf b)
+NOCOMPRESSION int test56 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_le_ps (a, b);
 }
 
-NOMIPS16 int test57 (v2sf a, v2sf b)
+NOCOMPRESSION int test57 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_le_ps (a, b);
 }
 
-NOMIPS16 int test58 (v2sf a, v2sf b)
+NOCOMPRESSION int test58 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_le_ps (a, b);
 }
 
-NOMIPS16 int test59 (v2sf a, v2sf b)
+NOCOMPRESSION int test59 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_le_ps (a, b);
 }
 
-NOMIPS16 int test60 (v2sf a, v2sf b)
+NOCOMPRESSION int test60 (v2sf a, v2sf b)
 {
   return __builtin_mips_any_cabs_ngt_ps (a, b);
 }
 
-NOMIPS16 int test61 (v2sf a, v2sf b)
+NOCOMPRESSION int test61 (v2sf a, v2sf b)
 {
   return __builtin_mips_upper_cabs_ngt_ps (a, b);
 }
 
-NOMIPS16 int test62 (v2sf a, v2sf b)
+NOCOMPRESSION int test62 (v2sf a, v2sf b)
 {
   return __builtin_mips_lower_cabs_ngt_ps (a, b);
 }
 
-NOMIPS16 int test63 (v2sf a, v2sf b)
+NOCOMPRESSION int test63 (v2sf a, v2sf b)
 {
   return __builtin_mips_all_cabs_ngt_ps (a, b);
 }
Index: gcc.target/mips/long-calls-pg.c
===================================================================
--- gcc.target/mips/long-calls-pg.c	(revision 195378)
+++ gcc.target/mips/long-calls-pg.c	(working copy)
@@ -1,7 +1,7 @@
 /* { dg-do compile } */
 /* { dg-options "-mabi=32 -pg -mno-abicalls -mlong-calls" } */
 /* { dg-final { scan-assembler-not "\tjal\t_mcount" } } */
-NOMIPS16 void
+NOCOMPRESSION void
 foo (void)
 {
 }
Index: gcc.target/mips/branch-8.c
===================================================================
--- gcc.target/mips/branch-8.c	(revision 195378)
+++ gcc.target/mips/branch-8.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int (*bar) (void), int *x)
 {
   *x = bar ();
Index: gcc.target/mips/octeon-baddu-1.c
===================================================================
--- gcc.target/mips/octeon-baddu-1.c	(revision 195378)
+++ gcc.target/mips/octeon-baddu-1.c	(working copy)
@@ -4,27 +4,27 @@
 /* { dg-final { scan-assembler-times "\tbaddu\t" 4 } } */
 /* { dg-final { scan-assembler-not "\tandi\t" } } */
 
-NOMIPS16 unsigned char
+NOCOMPRESSION unsigned char
 g (long long a, long long b)
 {
   return a + b;
 }
 
-NOMIPS16 unsigned long long
+NOCOMPRESSION unsigned long long
 h (unsigned long long a, unsigned long long b)
 {
   unsigned char c = a + b;
   return c;
 }
 
-NOMIPS16 long long
+NOCOMPRESSION long long
 ff (long long a, long long b)
 {
   unsigned char c = a + b;
   return c;
 }
 
-NOMIPS16 int
+NOCOMPRESSION int
 gg (int a, int b)
 {
   return (a + b) & 0xff;
Index: gcc.target/mips/octeon-cins-2.c
===================================================================
--- gcc.target/mips/octeon-cins-2.c	(revision 195378)
+++ gcc.target/mips/octeon-cins-2.c	(working copy)
@@ -3,13 +3,13 @@
 /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
 /* { dg-final { scan-assembler-not "\tcins\t" } } */
 
-NOMIPS16 unsigned
+NOCOMPRESSION unsigned
 f (unsigned i)
 {
   return (i & 0xff) << 24;
 }
 
-NOMIPS16 unsigned long long
+NOCOMPRESSION unsigned long long
 g (unsigned long long i)
 {
   return (i & 0x1ffffffffULL) << 4;
Index: gcc.target/mips/lazy-binding-1.c
===================================================================
--- gcc.target/mips/lazy-binding-1.c	(revision 195378)
+++ gcc.target/mips/lazy-binding-1.c	(working copy)
@@ -6,7 +6,7 @@
 
 void bar (void);
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int n)
 {
   while (n--)
Index: gcc.target/mips/r10k-cache-barrier-7.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-7.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-7.c	(working copy)
@@ -4,7 +4,7 @@
 void bar2 (void);
 void bar3 (void);
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int *x, int sel, int n)
 {
   if (sel)
Index: gcc.target/mips/call-saved-1.c
===================================================================
--- gcc.target/mips/call-saved-1.c	(revision 195378)
+++ gcc.target/mips/call-saved-1.c	(working copy)
@@ -4,7 +4,7 @@
 
 void bar (void);
 
-MIPS16 void
+MIPS16 NOMICROMIPS void
 foo (int x)
 {
   __builtin_unwind_init ();
Index: gcc.target/mips/octeon-exts-7.c
===================================================================
--- gcc.target/mips/octeon-exts-7.c	(revision 195378)
+++ gcc.target/mips/octeon-exts-7.c	(working copy)
@@ -12,7 +12,7 @@
   long long c:22;
 };
 
-NOMIPS16 int
+NOCOMPRESSION int
 f1 (struct bar *s)
 {
   return s->b;
Index: gcc.target/mips/mips-3d-4.c
===================================================================
--- gcc.target/mips/mips-3d-4.c	(revision 195378)
+++ gcc.target/mips/mips-3d-4.c	(working copy)
@@ -7,42 +7,42 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int test0 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test1 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test2 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test3 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test4 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test5 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test6 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test7 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test8 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test9 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test10 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test11 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test12 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test13 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test14 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test15 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test16 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test17 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test18 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test19 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test20 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test21 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test22 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test23 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test24 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test25 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test26 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test27 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test28 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test29 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test30 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test31 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test0 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test1 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test2 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test3 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test4 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test5 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test6 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test7 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test8 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test9 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test10 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test11 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test12 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test13 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test14 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test15 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test16 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test17 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test18 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test19 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test20 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test21 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test22 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test23 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test24 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test25 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test26 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test27 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test28 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test29 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test30 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test31 (v2sf a, v2sf b, v2sf c, v2sf d);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   v2sf a, b, c, d;
   int i, j;
@@ -429,162 +429,162 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test0 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_f_4s (a, b, c, d);
 }
 
-NOMIPS16 int test1 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test1 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_f_4s (a, b, c, d);
 }
 
-NOMIPS16 int test2 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test2 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_un_4s (a, b, c, d);
 }
 
-NOMIPS16 int test3 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test3 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_un_4s (a, b, c, d);
 }
 
-NOMIPS16 int test4 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test4 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_eq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test5 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test5 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_eq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test6 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test6 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ueq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test7 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test7 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ueq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test8 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test8 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_olt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test9 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test9 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_olt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test10 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test10 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ult_4s (a, b, c, d);
 }
 
-NOMIPS16 int test11 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test11 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ult_4s (a, b, c, d);
 }
 
-NOMIPS16 int test12 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test12 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ole_4s (a, b, c, d);
 }
 
-NOMIPS16 int test13 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test13 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ole_4s (a, b, c, d);
 }
 
-NOMIPS16 int test14 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test14 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ule_4s (a, b, c, d);
 }
 
-NOMIPS16 int test15 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test15 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ule_4s (a, b, c, d);
 }
 
-NOMIPS16 int test16 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test16 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_sf_4s (a, b, c, d);
 }
 
-NOMIPS16 int test17 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test17 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_sf_4s (a, b, c, d);
 }
 
-NOMIPS16 int test18 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test18 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ngle_4s (a, b, c, d);
 }
 
-NOMIPS16 int test19 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test19 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ngle_4s (a, b, c, d);
 }
 
-NOMIPS16 int test20 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test20 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_seq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test21 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test21 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_seq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test22 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test22 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ngl_4s (a, b, c, d);
 }
 
-NOMIPS16 int test23 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test23 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ngl_4s (a, b, c, d);
 }
 
-NOMIPS16 int test24 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test24 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_lt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test25 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test25 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_lt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test26 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test26 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_nge_4s (a, b, c, d);
 }
 
-NOMIPS16 int test27 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test27 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_nge_4s (a, b, c, d);
 }
 
-NOMIPS16 int test28 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test28 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_le_4s (a, b, c, d);
 }
 
-NOMIPS16 int test29 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test29 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_le_4s (a, b, c, d);
 }
 
-NOMIPS16 int test30 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test30 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_c_ngt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test31 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test31 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_c_ngt_4s (a, b, c, d);
 }
Index: gcc.target/mips/loongson-shift-count-truncated-1.c
===================================================================
--- gcc.target/mips/loongson-shift-count-truncated-1.c	(revision 195378)
+++ gcc.target/mips/loongson-shift-count-truncated-1.c	(working copy)
@@ -13,7 +13,7 @@
 
 typedef union { int32x2_t v; int32_t a[2]; } int32x2_encap_t;
 
-void
+void NOMICROMIPS
 main1 (int shift)
 {
   int32x2_encap_t s;
@@ -29,7 +29,7 @@
   assert (r.a[1] == 0xffffffff);
 }
 
-int
+int NOMICROMIPS
 main (void)
 {
   main1 (0x40);
Index: gcc.target/mips/micromips-lwp-swp-volatile.c
===================================================================
--- gcc.target/mips/micromips-lwp-swp-volatile.c	(revision 0)
+++ gcc.target/mips/micromips-lwp-swp-volatile.c	(revision 0)
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+/* This test ensures that we do not generate microMIPS SWP or LWP
+   instructions when any component of the accessed memory is volatile; 
+   they are unsafe for such since they might cause replay of partial 
+   accesses if interrupted by an exception.  */
+
+static void set_csr (volatile void *p, int v)
+{
+  *(volatile int *) (p) = v;
+}
+
+static int get_csr (volatile void *p)
+{
+  return *(volatile int *) (p);
+}
+
+int main ()
+{
+  int i, q = 0, p = 0, r = 0;
+
+  for (i = 0; i < 20; i++)
+    {
+      set_csr ((volatile void *) 0xbf0100a8, 0xffff0002);
+      set_csr ((volatile void *) 0xbf0100a4, 0x80000008);
+    }
+
+  for (i = 0; i < 20; i++)
+    {
+      register int k, j;
+      k = get_csr ((volatile void *) 0xbf0100b8);
+      p += k;
+      j = get_csr ((volatile void *) 0xbf0100b4);
+      r += j;
+      q = j + k;
+    }
+  return q + r + p;
+}
+
+/* { dg-final { scan-assembler-not "\tswp\t\\\$" } } */
+/* { dg-final { scan-assembler-not "\tlwp\t\\\$" } } */
Index: gcc.target/mips/r10k-cache-barrier-8.c
===================================================================
--- gcc.target/mips/r10k-cache-barrier-8.c	(revision 195378)
+++ gcc.target/mips/r10k-cache-barrier-8.c	(working copy)
@@ -5,7 +5,7 @@
 
 struct { struct { char i[4]; } a; struct { char j[4]; } b; } s;
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int sel)
 {
   s.a.i[0] = 1;
Index: gcc.target/mips/call-saved-2.c
===================================================================
--- gcc.target/mips/call-saved-2.c	(revision 195378)
+++ gcc.target/mips/call-saved-2.c	(working copy)
@@ -2,7 +2,7 @@
 /* { dg-options "(-mips16) isa_rev=0" } */
 /* { dg-skip-if "naming registers makes this a code quality test" { *-*-* } { "-O0" } { "" } } */
 
-MIPS16 void
+MIPS16 NOMICROMIPS void
 foo (void)
 {
   asm volatile ("" ::: "$19", "$23", "$24", "$30");
Index: gcc.target/mips/branch-12.c
===================================================================
--- gcc.target/mips/branch-12.c	(revision 195378)
+++ gcc.target/mips/branch-12.c	(working copy)
@@ -4,7 +4,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (int (*bar) (void), int *x)
 {
   *x = bar ();
Index: gcc.target/mips/mips-3d-5.c
===================================================================
--- gcc.target/mips/mips-3d-5.c	(revision 195378)
+++ gcc.target/mips/mips-3d-5.c	(working copy)
@@ -7,42 +7,42 @@
 
 typedef float v2sf __attribute__ ((vector_size(8)));
 
-NOMIPS16 int test0 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test1 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test2 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test3 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test4 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test5 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test6 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test7 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test8 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test9 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test10 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test11 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test12 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test13 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test14 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test15 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test16 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test17 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test18 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test19 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test20 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test21 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test22 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test23 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test24 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test25 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test26 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test27 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test28 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test29 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test30 (v2sf a, v2sf b, v2sf c, v2sf d);
-NOMIPS16 int test31 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test0 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test1 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test2 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test3 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test4 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test5 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test6 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test7 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test8 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test9 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test10 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test11 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test12 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test13 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test14 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test15 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test16 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test17 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test18 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test19 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test20 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test21 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test22 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test23 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test24 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test25 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test26 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test27 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test28 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test29 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test30 (v2sf a, v2sf b, v2sf c, v2sf d);
+NOCOMPRESSION int test31 (v2sf a, v2sf b, v2sf c, v2sf d);
 
 float qnan = 1.0f/0.0f - 1.0f/0.0f;
 
-NOMIPS16 int main ()
+NOCOMPRESSION int main ()
 {
   v2sf a, b, c, d;
   int i, j;
@@ -429,162 +429,162 @@
   exit (0);
 }
 
-NOMIPS16 int test0 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test0 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_f_4s (a, b, c, d);
 }
 
-NOMIPS16 int test1 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test1 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_f_4s (a, b, c, d);
 }
 
-NOMIPS16 int test2 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test2 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_un_4s (a, b, c, d);
 }
 
-NOMIPS16 int test3 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test3 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_un_4s (a, b, c, d);
 }
 
-NOMIPS16 int test4 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test4 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_eq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test5 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test5 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_eq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test6 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test6 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ueq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test7 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test7 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ueq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test8 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test8 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_olt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test9 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test9 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_olt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test10 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test10 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ult_4s (a, b, c, d);
 }
 
-NOMIPS16 int test11 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test11 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ult_4s (a, b, c, d);
 }
 
-NOMIPS16 int test12 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test12 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ole_4s (a, b, c, d);
 }
 
-NOMIPS16 int test13 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test13 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ole_4s (a, b, c, d);
 }
 
-NOMIPS16 int test14 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test14 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ule_4s (a, b, c, d);
 }
 
-NOMIPS16 int test15 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test15 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ule_4s (a, b, c, d);
 }
 
-NOMIPS16 int test16 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test16 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_sf_4s (a, b, c, d);
 }
 
-NOMIPS16 int test17 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test17 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_sf_4s (a, b, c, d);
 }
 
-NOMIPS16 int test18 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test18 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ngle_4s (a, b, c, d);
 }
 
-NOMIPS16 int test19 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test19 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ngle_4s (a, b, c, d);
 }
 
-NOMIPS16 int test20 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test20 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_seq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test21 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test21 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_seq_4s (a, b, c, d);
 }
 
-NOMIPS16 int test22 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test22 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ngl_4s (a, b, c, d);
 }
 
-NOMIPS16 int test23 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test23 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ngl_4s (a, b, c, d);
 }
 
-NOMIPS16 int test24 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test24 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_lt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test25 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test25 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_lt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test26 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test26 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_nge_4s (a, b, c, d);
 }
 
-NOMIPS16 int test27 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test27 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_nge_4s (a, b, c, d);
 }
 
-NOMIPS16 int test28 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test28 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_le_4s (a, b, c, d);
 }
 
-NOMIPS16 int test29 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test29 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_le_4s (a, b, c, d);
 }
 
-NOMIPS16 int test30 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test30 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_any_cabs_ngt_4s (a, b, c, d);
 }
 
-NOMIPS16 int test31 (v2sf a, v2sf b, v2sf c, v2sf d)
+NOCOMPRESSION int test31 (v2sf a, v2sf b, v2sf c, v2sf d)
 {
   return __builtin_mips_all_cabs_ngt_4s (a, b, c, d);
 }
Index: gcc.target/mips/loongson-muldiv-1.c
===================================================================
--- gcc.target/mips/loongson-muldiv-1.c	(revision 195378)
+++ gcc.target/mips/loongson-muldiv-1.c	(working copy)
@@ -3,11 +3,11 @@
 typedef int st;
 typedef unsigned int ut;
 
-NOMIPS16 st smul (st x, st y) { return x * y; }
-NOMIPS16 st sdiv (st x, st y) { return x / y + x % y; }
+NOCOMPRESSION st smul (st x, st y) { return x * y; }
+NOCOMPRESSION st sdiv (st x, st y) { return x / y + x % y; }
 
-NOMIPS16 ut umul (ut x, ut y) { return x * y; }
-NOMIPS16 ut udiv (ut x, ut y) { return x / y + x % y; }
+NOCOMPRESSION ut umul (ut x, ut y) { return x * y; }
+NOCOMPRESSION ut udiv (ut x, ut y) { return x / y + x % y; }
 
 /* { dg-final { scan-assembler-times "\tmultu.g\t" 2 } } */
 /* { dg-final { scan-assembler-times "\tdivu.g\t" 1 } } */
Index: gcc.target/mips/branch-2.c
===================================================================
--- gcc.target/mips/branch-2.c	(revision 195378)
+++ gcc.target/mips/branch-2.c	(working copy)
@@ -5,7 +5,7 @@
 
 #include "branch-helper.h"
 
-NOMIPS16 void
+NOCOMPRESSION void
 foo (volatile int *x)
 {
   if (__builtin_expect (*x == 0, 1))
Index: gcc.c-torture/execute/ieee/ieee.exp
===================================================================
--- gcc.c-torture/execute/ieee/ieee.exp	(revision 195378)
+++ gcc.c-torture/execute/ieee/ieee.exp	(working copy)
@@ -54,6 +54,9 @@
      || [istarget "sh*-*-*"] } then {
   lappend additional_flags "-mieee"
 }
+if [istarget "mips*-sde-*"] then {
+  lappend additional_flags "-Wl,--defsym=__cs3_mips_float_type=2" "-lcs3-mips-cp1" "-lcs3-mips-fpemu"
+}
 
 # load support procs
 load_lib c-torture.exp
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 195378)
+++ ChangeLog	(working copy)
@@ -1,3 +1,80 @@
+2013-01-22  Catherine Moore  <clm@codesourcery.com>
+
+	* gcc.target/mips/branch-2.c: Change NOMIPS16 to NOCOMPRESSION.
+	* gcc.target/mips/branch-4.c: Likewise.
+	* gcc.target/mips/branch-5.c: Likewise.
+	* gcc.target/mips/branch-6.c: Likewise.
+	* gcc.target/mips/branch-8.c: Likewise.
+	* gcc.target/mips/branch-10.c: Likewise.
+	* gcc.target/mips/branch-12.c: Likewise.
+	* gcc.target/mips/branch-13.c: Likewise.
+	* gcc.target/mips/call-1.c: Change NOMIPS16 to NOCOMPRESSION.
+	* gcc.target/mips/call-saved-1.c: Add attribute NOMICROMIPS.
+	* gcc.target/mips/call-saved-2.c: Likewise.
+	* gcc.target/mips/call-saved-3.c: Likewise.
+	* gcc.target/mips/gcc-have-sync-compare-and-swap-4.c: Compile with -mno-micromips.
+	* gcc.target/mips/lazy-binding-1.c: Change NOMIPS16 to NOCOMPRESSION.
+	* gcc.target/mips/long-calls-pg.c: Likewise.
+	* gcc.target/mips/loongson-muldiv-1.c: Likewise.
+	* gcc.target/mips/loongson-muldiv-2.c: Likewise.
+	* gcc.target/mips/loongson3a-muldiv-1.c: Likewise.
+	* gcc.target/mips/loongson3a-muldiv-2.c: Likewise.
+	* gcc.target/mips/loongson-shift-count-truncated-1.c: Add NOMICROMIPS attribute.
+	* gcc.target/mips/loongson-simd.c: Compile with -mno-compression.
+	* gcc.target/mips/micromips-lwp-swp-volatile.c: New test.
+	* gcc.target/mips/mips-3d-1.c: Change NOMIPS16 to NOCOMPRESSION.
+	* gcc.target/mips/mips-3d-2.c: Likewise.
+	* gcc.target/mips/mips-3d-3.c: Likewise.
+	* gcc.target/mips/mips-3d-4.c: Likewise.
+	* gcc.target/mips/mips-3d-5.c: Likewise.
+	* gcc.target/mips/mips-3d-6.c: Likewise.
+	* gcc.target/mips/mips-3d-9.c: Likewise.
+	* gcc.target/mips/mips-3d-7.c: Likewise.
+	* gcc.target/mips/mips-3d-8.c: Likewise.
+	* gcc.target/mips/mmcount-ra-address-1.c: Likewise.
+	* gcc.target/mips/mmcount-ra-address-3.c: Likewise.
+	* gcc.target/mips/near-far-1.c
+	* gcc.target/mips/near-far-2.c
+	* gcc.target/mips/no-smartmips-lwxs.c: Likewise.
+	* gcc.target/mips/octeon-baddu-1.c: Change NOMIPS16 to NOCOMPRESSION.
+	* gcc.target/mips/octeon-bbit-1.c: Likewise.
+	* gcc.target/mips/octeon-bbit-2.c: Likewise.
+	* gcc.target/mips/octeon-bbit-3.c: Likewise.
+	* gcc.target/mips/octeon-cins-1.c: Likewise.
+	* gcc.target/mips/octeon-cins-2.c: Likewise.
+	* gcc.target/mips/octeon-dmul-1.c: Likewise.
+	* gcc.target/mips/octeon-dmul-2.c: Likewise.
+	* gcc.target/mips/octeon-dmul-3.c: Likewise.
+	* gcc.target/mips/octeon-exts-1.c: Likewise.
+	* gcc.target/mips/octeon-exts-2.c: Likewise.
+	* gcc.target/mips/octeon-exts-3.c: Likewise.
+	* gcc.target/mips/octeon-exts-5.c: Likewise.
+	* gcc.target/mips/octeon-exts-7.c: Likewise.
+	* gcc.target/mips/octeon-pipe-1.c: Likewise.
+	* gcc.target/mips/octeon-pop-1.c: Likewise.
+	* gcc.target/mips/octeon-pop-2.c: Likewise.
+	* gcc.target/mips/octeon-seq-3.c: Likewise.
+	* gcc.target/mips/octeon-seq-4.c: Likewise.
+	* gcc.target/mips/octeon2-lx-2.c: Use attribute NOMICROMIPS.
+	* gcc.target/mips/octeon2-lx-3.c: Likewise.
+	* gcc.target/mips/octeon2-pipe-1.c: Change NOMIPS16 to NOCOMPRESSION.
+	* gcc.target/mips/r10k-cache-barrier-1.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-2.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-3.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-4.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-5.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-6.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-7.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-8.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-9.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-10.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-11.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-12.c: Likewise.
+	* gcc.target/mips/r10k-cache-barrier-13.c: Likewise.
+	* gcc.target/mips/mips.exp (mips_option_groups): Add -mmicromips
+	and -mno-micromips. Pass nomicromips and nocompression attributes
+	to all tests.
+	
 2013-01-22  Dodji Seketeli  <dodji@redhat.com>
 
 	PR c++/53609

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-01-22 20:27       ` Moore, Catherine
@ 2013-01-23 20:05         ` Richard Sandiford
  2013-01-26  3:52           ` Maciej W. Rozycki
  2013-02-12 19:00           ` Moore, Catherine
  0 siblings, 2 replies; 41+ messages in thread
From: Richard Sandiford @ 2013-01-23 20:05 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

Hi Catherine,

Thanks for the update.  Despite the length of this reply, there isn't
anything major.

Please don't change all NOMIPS16 to NOCOMPRESSION in the testsuite.
Most NOMIPSs are there because of the drastically reduced MIPS16
instruction set.  I would have expected most of them to pass with
microMIPS.

Instead, please add NOCOMPRESSION as an alternative to NOMIPS16,
and only change NOMIPS16 to NOCOMPRESSION in tests that also fail for
microMIPS.  I think that should be a separate patch and isn't really
a prerequisite for the core patch going in, although obviously it would
better if the testsuite results were clean.  Please explain why each
NOMIPS16 to NOCOMPRESSION change is needed; even if it's obvious to you,
it probably won't be to me.

There need to be more test casees.  We should at least test:

* LWM and SWM (see gcc.target/mips/save-restore-* for possible templates)
* MOVEP
* positive LWP and SWP tests (rather than just the volatile "not used" one)
* the new asm constraints

(Unlike the NOCOMPRESSION bits, these should be part of the core patch.)


As a general comment, I think it would be good to have:

/* The ISA compression flags that are currently in effect.  */
#define TARGET_COMPRESSION (target_flags & (MASK_MIPS16 | MASK_MICROMIPS))

I've used this in some of the comments below.

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> Index: config/mips/linux-unwind.h
> ===================================================================
> --- config/mips/linux-unwind.h	(revision 195304)
> +++ config/mips/linux-unwind.h	(working copy)
> @@ -52,6 +52,11 @@
>    _Unwind_Ptr new_cfa, reg_offset;
>    int i;
>  
> +  /* microMIPS frame; the kernel does not have microMIPS signal
> +     frames.  */
> +  if ((_Unwind_Ptr) pc & 3)
> +    return _URC_END_OF_STACK;

Should mention MIPS16 too.  E.g.:

  /* A MIPS16 or microMIPS frame.  Signal frames always use the standard
     ISA encoding.  */

> @@ -15991,18 +15995,33 @@ Generate MIPS16 code on alternating functions.  Th
>  for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
>  not intended for ordinary use in compiling user code.
>  
> +@item -minterlink-compressed
> +@item -mno-interlink-compressed
> +@opindex minterlink-compressed
> +@opindex mno-interlink-compressed
> +Require (do not require) that code using the standard (uncompressed) MIPS ISA
> +be link-compatible with MIPS16 and microMIPS code.
> +
> +For example, non-MIPS16 code cannot jump directly to MIPS16 code; it must
> +either use a call or an indirect jump.  The same applies to non-microMIPS
> +jumps to microMIPS code.  @option{-minterlink-compressed} therefore disables
> +direct jumps unless GCC knows that the target of the jump is not compressed.

I think I'm reediting a previous suggestion, sorry, but:

  For example, code using the standard ISA encoding cannot jump directly
  to MIPS16 or microMIPS code; it must either use a call or an indirect jump.
  @option{-minterlink-compressed} therefore disables direct jumps unless GCC
  knows that the target of the jump is not compressed.

> +@item -minterlink-uncompressed
> +@item -mno-interlink-uncompressed
> +@opindex minterlink-compressed
> +@opindex mno-interlink-compressed
> +Require (do not require) that code using microMIPS instructions be
> +link-compatible with the standard (uncompressed) MIPS ISA.

The distinction between this and -minterlink-compressed seems confusing
to me, and it wasn't handled consistently in the patch (see the sibcall
and gnu-user.h comments below).  I think it would be better to fold the
functionality into -minterlink-compressed, with the documentation
changed to:

  Require (do not require) that code using the standard (uncompressed) MIPS ISA
  be link-compatible with MIPS16 and microMIPS code, and vice versa.

> Index: config/mips/gnu-user.h
> ===================================================================
> --- config/mips/gnu-user.h	(revision 195351)
> +++ config/mips/gnu-user.h	(working copy)
> @@ -137,3 +137,12 @@ extern const char *host_detect_local_cpu (int argc
>  #define ENDFILE_SPEC \
>    GNU_USER_TARGET_MATHFILE_SPEC " " \
>    GNU_USER_TARGET_ENDFILE_SPEC
> +
> +#undef SUBTARGET_OVERRIDE_OPTIONS
> +#define SUBTARGET_OVERRIDE_OPTIONS                              \
> +do {                                                            \
> +  /* microMIPS PLT entries are non-microMIPS.  */               \
> +  TARGET_INTERLINK_COMPRESSED = 1;                              \
> +} while (0)
> +
> +

Hmm, that sounds like a reason to set TARGET_INTERLINK_UNCOMPRESSED
rather than TARGET_INTERLINK_COMPRESSED.  I.e. we need to avoid direct
branches from microMIPS code to standard PLTs.

But that means that microMIPS code can't even jump directly to functions
that have a micromips attribute when the call might go via a PLT.
TARGET_INTERLINK_(UN)COMPRESSED doesn't cover that case.  I think instead
we need to handle it directly in mips_function_ok_for_sibcall,
keyed off TARGET_ABICALLS_PIC0.  Specific suggestion below.

> +(define_insn "*lwp"
> +  [(parallel [(set (match_operand:SI 0 "d_operand")
> +		   (match_operand:SI 1 "non_volatile_mem_operand"))
> +	      (set (match_operand:SI 2 "d_operand")
> +		   (match_operand:SI 3 "non_volatile_mem_operand"))])]
> +
> +  "TARGET_MICROMIPS
> +   && umips_load_store_pair_p (true, operands)"
> +  {
> +    umips_output_load_store_pair (true, operands);
> +    return "";
> +  }

Very minor, sorry, but other MIPS patterns put multiline { ... } blocks
in column 0.  Same for *swp, but *movep<MOVEP1:mode><MOVEP2:mode>
is already OK.

> +  [(set_attr "type" "load")
> +   (set_attr "mode" "SI")
> +   (set_attr "can_delay" "no")])

Please add a comment saying why LWP can't go in a delay slot.
Same for SWP and MOVEP.

> +(define_insn "mips_jraddiusp"
> +  [(parallel [(return)
> +              (use (reg:SI 31))
> +	      (set (reg:SI 29)
> +		   (plus:SI (reg:SI 29)
> +			    (match_operand 0 "const_int_operand")))])]
> +  "TARGET_MICROMIPS"
> +  "jraddiusp\t%0"
> +  [(set_attr "type" "trap")
> +   (set_attr "mode" "SI")
> +   (set_attr "can_delay" "no")])

Is this pattern used?  If not, please leave it out for now.
If it is used, please add a testcase.

> +; For movep
> +(define_peephole2
> +  [(set (match_operand:MOVEP1 0 "register_operand" "")
> +        (match_operand:MOVEP1 1 "movep_operand" ""))
> +   (set (match_operand:MOVEP2 2 "register_operand" "")
> +        (match_operand:MOVEP2 3 "movep_operand" ""))]
> +  "TARGET_MICROMIPS
> +   && umips_movep_target_p (operands[0], operands[2])"
> +  [(parallel [(set (match_dup 0) (match_dup 1))
> +              (set (match_dup 2) (match_dup 3))])]
> +)

Probably not worth having movep_operand, because all the checking
is done by umips_movep_target_p.  reg_or_0_operand should be OK.

> Index: config/mips/constraints.md
> ===================================================================
> --- config/mips/constraints.md	(revision 195351)
> +++ config/mips/constraints.md	(working copy)
> @@ -232,6 +232,26 @@
>     "@internal"
>     (match_operand 0 "low_bitmask_operand"))
>  
> +(define_memory_constraint "ZC"
> +  "When compiling microMIPS code, this constraing matches a memory operand
> +   whose address is formed from a base register and a 12-bit offset.  These
> +   operands can be used for microMIPS instructions such as @code{ll} and
> +   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
> +   equivalent to @code{R}."
> +  (and (match_code "mem")
> +       (ior (and (match_test "TARGET_MICROMIPS")
> +		 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)"))
> +	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))

The last line should be:

   (match_test "mips_address_insns (XEXP (op, 0), mode, false) == 1")

to match "R".  The documentation makes it sound like an if-then-else,
but the implementation isn't.  Should it be:

  (and (match_code "mem")
       (if_then_else
	 (match_test "TARGET_MICROMIPS")
	 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)"))
	 (match_test "mips_address_insns (XEXP (op, 0), mode, false) == 1"))))

instead?

> +(define_address_constraint "ZD"
> +  "When compiling microMIPS code, this constraint matches an address operand
> +   that is formed from a base register and a 12-bit offset.  These operands
> +   can be used for microMIPS instructions such as @code{prefetch}.  When
> +   not compiling for microMIPS code, @code{YC} is equivalent to @code{p}."
> +   (ior (and (match_test "TARGET_MICROMIPS")
> +	     (match_test "umips_12bit_offset_address_p (op, mode)"))
> +	(match_test "mips_address_insns (op, mode, false)")))

Same comments here.

> +;; Return 1 if the operand is in non-volatile memory.  Note that during the
> +;; RTL generation phase, memory_operand does not return TRUE for volatile
> +;; memory references.  So this function allows us to recognize volatile
> +;; references where it's safe.
> +(define_predicate "non_volatile_mem_operand"
> +  (and (match_operand 0 "memory_operand")
> +       (not (match_test "MEM_VOLATILE_P (op)"))))

I don't understand the comment.  We're trying to avoid all volatile references.

> +minterlink-uncompressed
> +Target Report Var(TARGET_INTERLINK_UNCOMPRESSED) Init(1)
> +Generated code that is link-compatible with the standard (uncompressed)
> +MIPS ISA.

Do multi-line documentation strings work?  Please check the --target-help
output to make sure.

> Index: config/mips/mips.c
> ===================================================================
> --- config/mips/mips.c	(revision 195351)
> +++ config/mips/mips.c	(working copy)
> @@ -77,6 +77,9 @@ along with GCC; see the file COPYING3.  If not see
>     preserve the maximum stack alignment.  We therefore use a value
>     of 0x7ff0 in this case.
>  
> +   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
> +   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
> +
>     MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
>     up to 0x7f8 bytes and can usually save or restore all the registers
>     that we need to save or restore.  (Note that we can only use these
> @@ -87,7 +90,8 @@ along with GCC; see the file COPYING3.  If not see
>     to save and restore registers, and to allocate and deallocate the top
>     part of the frame.  */
>  #define MIPS_MAX_FIRST_STACK_STEP					\
> -  (!TARGET_MIPS16 ? 0x7ff0						\
> +  ((!TARGET_MIPS16 && !TARGET_MICROMIPS) ? 0x7ff0			\
> +   : TARGET_MICROMIPS ? 0x7f0						\
>     : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8				\
>     : TARGET_64BIT ? 0x100 : 0x400)

I'd prefer:

  (TARGET_MICROMIPS ? 0x7f0						\
   : !TARGET_MIPS16 ? 0x7ff0						\
   : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8				\
   : TARGET_64BIT ? 0x100 : 0x400)

The comment doesn't really explain the reason for 0x7f0 rather than 0x7f8.
Is this in anticipation of future n32 and n64 support, where the stack
must be 16-byte aligned?  If so, that's OK, but worth mentioning.

> @@ -1167,10 +1174,11 @@ mflip_mips16_use_mips16_p (tree decl)
>    const char *name;
>    hashval_t hash;
>    void **slot;
> +  bool base_is_mips16 = mips_base_compression_flags & MASK_MIPS16;

Please make this:

  bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) != 0;

> @@ -1257,12 +1252,57 @@ mips_use_debug_exception_return_p (tree type)
>  			   TYPE_ATTRIBUTES (type)) != NULL;
>  }
>  
> -/* Return true if function DECL is a MIPS16 function.  Return the ambient
> -   setting if DECL is null.  */
> +/* Return the set of compression modes that are explicitly required
> +   by DECL.  */
>  
> -static bool
> -mips_use_mips16_mode_p (tree decl)
> +static unsigned int
> +mips_get_compress_on_flags (tree decl)
>  {
> +  unsigned int flags = 0;
> +
> +  if (!decl || !DECL_P (decl))
> +    return flags;

Is this check necessary?  Same for mips_get_compress_off_flags.

> @@ -1297,29 +1337,47 @@ static void
>  mips_insert_attributes (tree decl, tree *attributes)
>  {
>    const char *name;
> -  bool mips16_p, nomips16_p;
> +  unsigned int compression_p, nocompression_p;

No _p, since these aren't booleans now.  _flags would be better.

>    /* Check for "mips16" and "nomips16" attributes.  */
> -  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
> -  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
> +  compression_p = mips_get_compress_on_flags (decl);
> +  nocompression_p = mips_get_compress_off_flags (decl);
> +
>    if (TREE_CODE (decl) != FUNCTION_DECL)
>      {
> -      if (mips16_p)
> +      if (compression_p & MASK_MIPS16)
>  	error ("%qs attribute only applies to functions", "mips16");
> -      if (nomips16_p)
> +      if (nocompression_p & MASK_MIPS16)
>  	error ("%qs attribute only applies to functions", "nomips16");
> +
> +      if (nocompression_p & MASK_MICROMIPS
> +	  && nocompression_p & MASK_MIPS16)
> +	error ("%qs attribute only applies to functions", "nocompression");

This case needs to come first, otherwise nomips16 will be reported instead.
Although...

> +      else
> +	{
> +	  if (compression_p & MASK_MICROMIPS)
> +	    error ("%qs attribute only applies to functions", "micromips");
> +	  if (nocompression_p & MASK_MICROMIPS)
> +	    error ("%qs attribute only applies to functions", "nomicromips");
> +	}

...I think it would be easier to have:

/* Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
   flags FLAGS.  */

static const char *
mips_get_compress_on_name (unsigned int flags)
{
  if (flags == MASK_MIPS16)
    return "mips16";
  return "micromips";
}

/* Return the attribute that forbids MASK_MIPS16 and MASK_MICROMIPS
   flags FLAGS.  */

static const char *
mips_get_compress_off_name (unsigned int flags)
{
  if (flags == MASK_MIPS16)
    return "nomips16";
  if (flags == MASK_MICROMIPS)
    return "nomicromips";
  return "nocompression";
}

Then:

      if (nocompression_flags)
        error ("%qs attribute only applies to functions",
               mips_get_compress_off_name (nocompression_flags));
      if (compression_flags)
        error ("%qs attribute only applies to functions",
               mips_get_compress_on_name (compression_flags));

>      }
>    else
>      {
> -      mips16_p |= mips_mips16_decl_p (decl);
> -      nomips16_p |= mips_nomips16_decl_p (decl);
> -      if (mips16_p || nomips16_p)
> +      if (compression_p & MASK_MIPS16
> +           && nocompression_p & (MASK_MIPS16 | MASK_MICROMIPS))
>  	{
> +	  /* DECL cannot be simultaneously "mips16" and "nocompression".  */
> +	  error ("%qE cannot have both %<mips16%> and "
> +		 "%<nocompression%> attributes",
> +		 DECL_NAME (decl));
> +	}
> +      else if (compression_p & MASK_MIPS16
> +		&& nocompression_p & MASK_MIPS16)
> +	{
>  	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
> -	  if (mips16_p && nomips16_p)
> -	    error ("%qE cannot have both %<mips16%> and "
> -		   "%<nomips16%> attributes",
> -		   DECL_NAME (decl));
> +	  error ("%qE cannot have both %<mips16%> and "
> +		 "%<nomips16%> attributes",
> +		 DECL_NAME (decl));
>  	}
>        else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
>  	{
> @@ -1329,6 +1387,39 @@ mips_insert_attributes (tree decl, tree *attribute
>  	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
>  	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
>  	}
> +
> +      if (compression_p & MASK_MICROMIPS
> +           && nocompression_p & (MASK_MIPS16 | MASK_MICROMIPS))
> +	{
> +	  /* DECL cannot be simultaneously "micromips" and "nocompression".  */
> +	  error ("%qE cannot have both %<micromips%> and "
> +		 "%<nocompression%> attributes",
> +		 DECL_NAME (decl));
> +	}
> +      else if (compression_p & MASK_MICROMIPS
> +		&& nocompression_p & MASK_MICROMIPS)
> +	{
> +	  /* DECL cannot be simultaneously "micromips" and "nomicromips".  */
> +	  error ("%qs cannot have both %<micromips%> and "
> +		 "%<nomicromips%> attributes",
> +		 IDENTIFIER_POINTER (DECL_NAME (decl)));
> +	}

All the above then becomes:

      if (compression_flags && nocompression_flags)
	error ("%qE cannot have both %qs and %qs attributes",
	       DECL_NAME (decl), mips_get_compress_on_name (compression_flags),
	       mips_get_compress_off_name (nocompression_flags));

> +
> +      if (compression_p & MASK_MIPS16
> +          && compression_p & MASK_MICROMIPS)
> +	error ("%qs cannot have both %<mips16%> and %<micromips%> attributes",
> +	       IDENTIFIER_POINTER (DECL_NAME (decl)));

%qE and no IDENTIFIER_POINTER.  Please use the %qs form here too,
with "mips16" and "micromips" as error() arguments, so that one
translation covers both this case and the previous one.

> +      /* If DECL is "nocompression" set the "nomips16" and 
> +	 "nomicromips" attributes.  */
> +      if (nocompression_p & MASK_MIPS16
> +          && nocompression_p & MASK_MICROMIPS)
> +	{
> +	  name = "nomips16";
> +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> +	  name = "nomicromips";
> +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> +	}

Hmm, why is this necessary?  Anything that cares should be using
mips_get_compress_off_flags.

> @@ -1338,12 +1429,9 @@ static tree
>  mips_merge_decl_attributes (tree olddecl, tree newdecl)
>  {
>    /* The decls' "mips16" and "nomips16" attributes must match exactly.  */
> -  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
> +  if (mips_get_compress_mode (olddecl) != mips_get_compress_mode (newdecl))
>      error ("%qE redeclared with conflicting %qs attributes",
> -	   DECL_NAME (newdecl), "mips16");
> -  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
> -    error ("%qE redeclared with conflicting %qs attributes",
> -	   DECL_NAME (newdecl), "nomips16");
> +	   DECL_NAME (newdecl), "compression");

This should be:

  unsigned int diff;

  diff = (mips_get_compress_on_flags (olddecl)
          ^ mips_get_compress_on_flags (newdecl));
  if (diff)
    error ("%qE redeclared with conflicting %qs attributes",
           DECL_NAME (newdecl), mips_get_compress_on_name (diff));

  diff = (mips_get_compress_off_flags (olddecl)
          ^ mips_get_compress_off_flags (newdecl));
  if (diff)
    error ("%qE redeclared with conflicting %qs attributes",
           DECL_NAME (newdecl), mips_get_compress_off_name (diff));

> @@ -2300,6 +2388,20 @@ mips_address_insns (rtx x, enum machine_mode mode,
>    return 0;
>  }
>  
> +/* Return true if X is a legitimate address with a 12-bit offset.
> +   MODE is the mode of the value being accessed.  */
> +
> +bool
> +umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
> +{
> +  struct mips_address_info addr;
> +
> +  return (mips_classify_address(&addr, x, mode, false)

Space before '('

> +	  && addr.type == ADDRESS_REG
> +	  && CONST_INT_P (addr.offset)
> +	  && UMIPS_12BIT_OFFSET_P (addr.offset));

Isn't there a missing INTVAL here?  Please check the patch to make sure
there are no compiler warnings.

> @@ -6908,6 +7017,8 @@ mips_split_call (rtx insn, rtx call_pattern)
>  static bool
>  mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
>  {
> +  unsigned int compression_mode = mips_get_compress_mode (decl);
> +

Might as well move this down to where it's needed, especially now that
we're C++.

>    if (!TARGET_SIBCALLS)
>      return false;
>  
> @@ -6916,22 +7027,45 @@ mips_function_ok_for_sibcall (tree decl, tree exp
>    if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
>      return false;
>  
> +  if (TARGET_MICROMIPS)
> +    {
> +      /* We can't do a sibcall if the called function is a MIPS32 function.  */

s/is a MIPS32 function/isn't microMIPS/, to avoid confusion with
the MIPS32 ISA.

> +      if (decl
> +	  && (compression_mode & MASK_MICROMIPS) == 0
> +	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
> +	return false;
> +
> +      /* When -minterlink-compressed is in effect, assume that non-locally-binding
> +	 functions could be MIPS32 ones unless an attribute explicitly tells
> +	 us otherwise.  */
> +      if (TARGET_INTERLINK_COMPRESSED
> +	  && decl
> +	  && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
> +	  && (compression_mode & MASK_MICROMIPS) == 0
> +	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
> +	return false;

We're dealing here with branches from microMIPS to non-microMIPS,
so shouldn't this be TARGET_INTERLINK_UNCOMPRESSED?

We need to use mips_get_compress_on_flags rather than mips_get_compress_mode
for the second condition, because we can only assume that external functions
are micromips if they have been explicitly tagged.

> +
> +      /* Otherwise OK.  */
> +      return true;
> +    }
> +

There's too much cut-&-paste of the MIPS16 code here, so that it
becomes difficult to see what the logic actually is.  With the
suggested change to fold -minterlink-nocompressed into
-minterlink-compressed, the block above and:

>    /* We can't do a sibcall if the called function is a MIPS16 function
>       because there is no direct "jx" instruction equivalent to "jalx" to
>       switch the ISA mode.  We only care about cases where the sibling
>       and normal calls would both be direct.  */
>    if (decl
> -      && mips_use_mips16_mode_p (decl)
> +      && ((compression_mode & (MASK_MIPS16 | MASK_MICROMIPS)) != 0)
>        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
>      return false;
>  
> -  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
> -     functions could be MIPS16 ones unless an attribute explicitly tells
> +  /* When -minterlink-compressed is in effect, assume that non-locally-binding
> +     functions could be MIPS16 or microMIPS unless an attribute explicitly tells
>       us otherwise.  */
> -  if (TARGET_INTERLINK_MIPS16
> +  if (TARGET_INTERLINK_COMPRESSED
>        && decl
>        && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
> -      && !mips_nomips16_decl_p (decl)
> +      && (compression_mode & MASK_MICROMIPS) == 0
> +      && (compression_mode & MASK_MIPS16) == 0
>        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
>      return false;

should be something like:

  /* Direct Js are only possible to functions that use the same ISA encoding.
     There is no JX counterpart of JALX.  */
  if (decl
      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
      && mips_call_may_need_jalx_p (decl))
    return false;

with:

/* Return true if a call to DECL may need to use JALX.  */

static bool
mips_call_may_need_jalx_p (decl)
{
  /* If the current translation unit would use a different mode for DECL,
     assume that the call needs JALX.  */
  if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
    return true;

  /* mips_get_compress_mode is always accurate for locally-binding
     functions in the current translation unit.  */
  if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
    return false;

  /* PLTs use the standard encoding, so calls that might go via PLTs
     must use JALX.  */
  if (TARGET_COMPRESSED
      && TARGET_ABICALLS_PIC0
      && DECL_EXTERNAL (decl)
      && !targetm.binds_local_p (decl))
    return true;

  /* When -minterlink-compressed is in effect, assume that functions
     could use a different encoding mode unless an attribute explicitly
     tells us otherwise.  */
  if (TARGET_INTERLINK_COMPRESSED)
    {
      if (!TARGET_COMPRESSION && mips_get_compress_off_flags (decl) == 0)
        return true;
      if (TARGET_COMPRESSION && mips_get_compress_on_flags (decl) == 0)
        return true;
    }

  return false;
}

The TARGET_ABICALLS_PIC0 case should deal with the gnu-user.h comment above.

> @@ -7881,6 +8018,20 @@ mips_print_operand_punctuation (FILE *file, int ch
>        fputs (reg_names[STACK_POINTER_REGNUM], file);
>        break;
>  
> +    case ':':
> +      /* When reorder or noreorder with final_squence 0, the delay slot will
> +	 be a nop, so we just use the compact version for microMIPS.  */
> +      if (final_sequence == 0)
> +	putc ('c', file);
> +      break;
> +
> +    case '!':
> +      /* When reorder or noreorder with final_squence 0, the delay slot will
> +	 be a nop, so we just use the compact version for microMIPS.  */
> +      if (final_sequence == 0)
> +	putc ('s', file);
> +      break;
> +

Pasto: the second "the compact version" should be "16-bit delay slots".

> @@ -10198,7 +10349,7 @@ typedef void (*mips_save_restore_fn) (rtx, rtx);
>     stack pointer.  */
>  
>  static void
> -mips_save_restore_reg (enum machine_mode mode, int regno,
> +mips_save_restore_single_reg (enum machine_mode mode, int regno,
>  		       HOST_WIDE_INT offset, mips_save_restore_fn fn)
>  {
>    rtx mem;

Please reindent the second line, although I'd prefer not to have this change;
more below.

> @@ -10208,6 +10359,23 @@ static void
>    fn (gen_rtx_REG (mode, regno), mem);
>  }
>  
> +static void
> +mips_save_restore_registers (int start_reg, int end_reg, HOST_WIDE_INT *offset,
> +			     mips_save_restore_fn fn, HOST_WIDE_INT sp_offset)
> +{
> +  int regno;
> +
> +  for (regno = start_reg; regno > end_reg; regno--)
> +    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> +      {
> +        /* Record the ra offset for use by mips_function_profiler.  */
> +        if (regno == RETURN_ADDR_REGNUM)
> +          cfun->machine->frame.ra_fp_offset = *offset + sp_offset;
> +	mips_save_restore_single_reg (word_mode, regno, *offset, fn);
> +	*offset -= UNITS_PER_WORD;
> +      }
> +}
> +

Function lacks a comment, although I'm not sure it's needed; see below.

> +static const unsigned int type[19] = { 0x00010000, 0x00030000, 0x00070000,
> +				       0x000f0000, 0x001f0000, 0x003f0000,
> +				       0x007f0000, 0x00ff0000, 0x40ff0000,
> +				       0x80000000, 0x80010000, 0x80030000,
> +				       0x80070000, 0x800f0000, 0x801f0000,
> +				       0x803f0000, 0x807f0000, 0x80ff0000,
> +				       0xc0ff0000 };
> +
> +static const unsigned int encode[19] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17,
> +					 18, 19, 20, 21, 22, 23, 24, 25};

Please give these longer names, since they have file scope.  E.g.:

/* The masks of GPRs that can be saved by a microMIPS SWM and restored
   by an LWM.  */
static const unsigned int umips_swm_mask[19] = {
  0x00010000, 0x00030000, 0x00070000, 0x000f0000,
  0x001f0000, 0x003f0000, 0x007f0000, 0x00ff0000, 0x40ff0000,
  0x80000000, 0x80010000, 0x80030000, 0x80070000, 0x800f0000,
  0x801f0000, 0x803f0000, 0x807f0000, 0x80ff0000, 0xc0ff0000
};

/* umips_swm_encoding[I] is the instruction encoding used to represent mask
   umips_swm_mask[I].  */
static const unsigned int umips_swm_encoding[19] = {
  1, 2, 3, 4,
  5, 6, 7, 8, 9,
  16, 17, 18, 19, 20,
  21, 22, 23, 24, 25
};

> +/* Build microMIPS save or restore.  FN is save or restore function.
> +   OFFSET is the current stack offset.
> +   Return true if we succeed creating save or restore.  */
> +
> +static bool
> +umips_build_save_restore (mips_save_restore_fn fn,
> +			  HOST_WIDE_INT offset, HOST_WIDE_INT sp_offset)

The comment doesn't say what SP_OFFSET is, although with the comments below
I think the prototype should be:

/* Try to use a microMIPS LWM or SWM instruction to save or restore
   as many GPRs in *MASK as possible.  *OFFSET is the offset from the
   stack pointer of the topmost save slot.

   Remove from *MASK all registers that were handled using LWM and SWM.
   Update *OFFSET so that it points to the first unused save slot.  */

static void
umips_build_save_restore (mips_save_restore_fn fn, unsigned *mask
			  HOST_WIDE_INT *offset)

> +{
> +  int i, num_of_reg;
> +  unsigned int j;
> +  rtx pattern, set, reg, mem;
> +  HOST_WIDE_INT this_offset;
> +  rtx this_base;
> +
> +  /* LWM/SWM can only support offsets from -2048 to 2047.  */
> +  if (!UMIPS_12BIT_OFFSET_P (offset))
> +    return false;

At this point OFFSET is still the offset of the top of the save area,
whereas the instruction operand is the address of the first saved register.
I think you need to check this later, after:

  offset -= (UNITS_PER_WORD * (num_of_reg - 1));

> +  if (i < 8 && (cfun->machine->frame.mask & 0xff000000))
> +    mips_save_restore_registers (GP_REG_LAST, GP_REG_LAST - 8,
> +				 &offset, fn, sp_offset);

Any reason for handling this differently from the MIPS16 code?  I prefer
passing back a mask of the unhandled registers, like it does.  It would
make this function a bit simpler and would also allow the function to
be used in future with masks that don't exactly match.  E.g. if we need
to save and restore registers $16-$20 + $23, we could use LWM for $16-$20
and LW for $23.  The prototype suggested above was for this.

> +  /* Adjust offset for output.  */
> +  num_of_reg = (encode[i] & 0xf) + (encode[i] >> 4);
> +  offset -= (UNITS_PER_WORD * (num_of_reg - 1));

Very minor, sorry, but s/num_of_reg/nregs/;

> +  /* Create the final PARALLEL.  */
> +  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_of_reg));
> +
> +  this_base = stack_pointer_rtx;
> +  this_offset = offset;
> +
> +  /* For $16-$23, $30.  */
> +  for (j = 0; j < (encode[i] & 0xf); j++)
> +    {
> +      unsigned int regno;
> +      long long offset = this_offset + j * UNITS_PER_WORD;

s/long long/HOST_WIDE_INT/.

> +  pattern = emit_insn (pattern);
> +  if (fn == mips_save_reg)
> +    RTX_FRAME_RELATED_P(pattern) = 1;  

Missing space before "(".

> @@ -10253,16 +10555,13 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
>       need a nop in the epilogue if at least one register is reloaded in
>       addition to return address.  */
>    offset = cfun->machine->frame.gp_sp_offset - sp_offset;
> -  for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
> -    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> -      {
> -	/* Record the ra offset for use by mips_function_profiler.  */
> -	if (regno == RETURN_ADDR_REGNUM)
> -	  cfun->machine->frame.ra_fp_offset = offset + sp_offset;
> -	mips_save_restore_reg (word_mode, regno, offset, fn);
> -	offset -= UNITS_PER_WORD;
> -      }
>  
> +  if (!TARGET_MICROMIPS
> +      || (TARGET_MICROMIPS
> +          && !umips_build_save_restore (fn, offset, sp_offset)))
> +    mips_save_restore_registers (GP_REG_LAST, GP_REG_FIRST,
> +				 &offset, fn, sp_offset);
> +

With the pass-back suggestion above, I think this should be:

  offset = cfun->machine->frame.gp_sp_offset - sp_offset;
  mask = cfun->machine->frame.mask
  if (TARET_MICROMIPS16)
    umips_build_save_restore (fn, &mask, &offset);
  for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
    if (BITSET_P (mask, regno - GP_REG_FIRST))
      {
	/* Record the ra offset for use by mips_function_profiler.  */
	if (regno == RETURN_ADDR_REGNUM)
	  cfun->machine->frame.ra_fp_offset = offset + sp_offset;
	mips_save_restore_reg (word_mode, regno, offset, fn);
	offset -= UNITS_PER_WORD;
      }

> @@ -11078,6 +11357,7 @@ mips_deallocate_stack (rtx base, rtx offset, HOST_
>      return;
>  
>    mips_frame_barrier ();
> +
>    if (offset == const0_rtx)
>      {
>        emit_move_insn (stack_pointer_rtx, base);
> @@ -11196,9 +11476,9 @@ mips_expand_epilogue (bool sibcall_p)
>   	if (BITSET_P (mask, regno - GP_REG_FIRST))
>   	  {
>   	    offset -= UNITS_PER_WORD;
> - 	    mips_save_restore_reg (word_mode, regno, offset, mips_restore_reg);
> + 	    mips_save_restore_single_reg (word_mode, regno,
> +                                          offset, mips_restore_reg);
>   	  }
> -
>        /* Restore the remaining registers and deallocate the final bit
>  	 of the frame.  */
>        mips_frame_barrier ();
> @@ -11211,7 +11491,6 @@ mips_expand_epilogue (bool sibcall_p)
>        mips_for_each_saved_acc (frame->total_size - step2, mips_restore_reg);
>        mips_for_each_saved_gpr_and_fpr (frame->total_size - step2,
>  				       mips_restore_reg);
> -
>        if (cfun->machine->interrupt_handler_p)
>  	{
>  	  HOST_WIDE_INT offset;

Please leave out these whitespace changes.  I'd also prefer not to add
the _single_reg suffix to mips_save_restore_reg.

> @@ -11254,7 +11533,6 @@ mips_expand_epilogue (bool sibcall_p)
>  	/* Deallocate the final bit of the frame.  */
>  	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
>      }
> -  gcc_assert (!mips_epilogue.cfa_restores);
>  
>    /* Add in the __builtin_eh_return stack adjustment.  We need to

Please don't remove the assert.  AIUI this was for epilogues that use
JRADDIUSP, which isn't part of the initial patch.

> @@ -16211,17 +16489,19 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndec
>    reload_completed = 0;
>  }
>  \f
> -/* The last argument passed to mips_set_mips16_mode, or negative if the
> -   function hasn't been called yet.  */
> +/* The last argument passed to mips_set_mips16_micromips_mode,
> +   or negative if the function hasn't been called yet.  */
>  static int was_mips16_p = -1;
> +static int was_micromips_p = -1;
>  
>  /* Set up the target-dependent global state so that it matches the
>     current function's ISA mode.  */
>  
>  static void
> -mips_set_mips16_mode (int mips16_p)
> +mips_set_mips16_micromips_mode (int mips16_p, int micromips_p)
>  {
> -  if (mips16_p == was_mips16_p)
> +  if (mips16_p == was_mips16_p
> +      && micromips_p == was_micromips_p)
>      return;
>  
>    /* Restore base settings of various flags.  */

Now that we represent the mode using masks of MASK_MIPS16 and MASK_MICROMIPS,
I think it would be better to have a mask rather than two booleans here too.
I.e.:

/* The last argument passed to mips_set_mips16_micromips_mode,
   or negative if the function hasn't been called yet.  */
static unsigned int old_compression_mode = -1;

/* Set up the target-dependent global state for ISA mode COMPRESSION_MODE,
   which is either MASK_MIPS16 or MASK_MICROMIPS.  */

static void
mips_set_compression_mode (unsigned int compression_mode)

> @@ -16290,6 +16570,18 @@ static void
>        /* Switch to normal (non-MIPS16) mode.  */
>        target_flags &= ~MASK_MIPS16;
>  
> +      if (micromips_p)
> +	{
> +	  /* Switch to microMIPS mode.  */
> +	  target_flags |= MASK_MICROMIPS;
> +
> +	  /* Avoid branch likely.  */
> +	  target_flags &= ~MASK_BRANCHLIKELY;
> +	}
> +      else
> +	/* Switch to normal (non-microMIPS) mode.  */
> +	target_flags &= ~MASK_MICROMIPS;
> +

With the change above, I think we should have:

  target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
  target_flags |= compression_mode;

outside of the "if" statement, with the code above becoming:

    /* There are no microMIPS branch-likely instructions.  */
    if (TARGET_MICROMIPS)
      target_flags &= ~MASK_BRANCHLIKELY;

> +  /* Save the base compression state and process flags as though we
> +     are generating uncompressed code.  */
> +  if (TARGET_MIPS16)
> +    mips_base_compression_flags |= MASK_MIPS16;
> +  if (TARGET_MICROMIPS)
> +    mips_base_compression_flags |= MASK_MICROMIPS;
> +
> +  target_flags &= ~MASK_MIPS16;
> +  target_flags &= ~MASK_MICROMIPS;

Would prefer:

  mips_base_compression_flags = TARGET_COMPRESSION;
  target_flags &= ~TARGET_COMPRESSION;

> @@ -17088,6 +17397,316 @@ mips_mulsidi3_gen_fn (enum rtx_code ext_code)
>        return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
>      }
>  }
> +
> +
> +/* Return true if PATTERN matches the kind of instruction generated by
> +   micromips_build_save_restore.  SAVE_P is true for store.  */

umips_build_save_restore

> +
> +bool
> +umips_save_restore_pattern_p (bool save_p, rtx pattern)
> +{
> +  int n;
> +  HOST_WIDE_INT first_offset = 0;
> +  rtx first_base = 0;
> +  unsigned int first_regno = 0;
> +
> +  for (n = 0; n < XVECLEN (pattern, 0); n++)
> +    {
> +      rtx set, reg, mem, this_base;
> +      HOST_WIDE_INT this_offset;
> +      unsigned int this_regno;
> +
> +      /* Check that we have a SET.  */
> +      set = XVECEXP (pattern, 0, n);
> +      if (GET_CODE (set) != SET)
> +	return false;
> +
> +      /* Check that the SET is a load (if restoring) or a store
> +	 (if saving).  */
> +      mem = save_p ? SET_DEST (set) : SET_SRC (set);
> +      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
> +	return false;
> +
> +      /* Check that the address is the sum of base and a possibly-zero
> +	 constant offset.  Determine if the offset is in range.  */
> +      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
> +      if (!REG_P (this_base)
> +	  && UMIPS_12BIT_OFFSET_P (this_offset))
> +	return false;
> +
> +      if (n == 0)
> +	{
> +	  first_base = this_base;
> +	  first_offset = this_offset;
> +	}

The UMIPS_12BIT_OFFSET_P check should be in the "n == 0" arm.

> +      else
> +	{
> +	  /* Check if this_base is the same as first_base.  */
> +	  if (REGNO (this_base) != REGNO (first_base))
> +	    return false;
> +
> +	  /* Check if this_offset is first_offset + UNITS_PER_WORD * n.  */
> +	  if (this_offset != first_offset + UNITS_PER_WORD * n)
> +	    return false;

      /* Check that the save slots are consecutive.  */
      if (REGNO (this_base) != REGNO (first_base)
	  || this_offset != first_offset + UNITS_PER_WORD * n)

> +      /* Make sure the order of regno is "$16-$23, $30, $31", "$16-$23, $30",
> +	 or "$31".  */
> +      this_regno = REGNO (reg);
> +      if (n == 0)
> +	{
> +	  if (this_regno != 16 && this_regno != 31)
> +	    return false;
> +	  first_regno = this_regno;
> +	}
> +      else if (n == 8) /* For s8.  */
> +	{
> +	  if (n == XVECLEN (pattern, 0) - 1)
> +	    {
> +	      if (this_regno != 30 && this_regno != 31)
> +		return false;
> +	    }
> +	  else
> +	    {
> +	      if (this_regno != 30)
> +		return false;
> +	    }
> +	}
> +      else if (n != XVECLEN (pattern, 0) - 1)
> +	{
> +	  if (this_regno != first_regno + n)
> +	    return false;
> +	}
> +      else /* The last item.  */
> +	{
> +	  if ((this_regno != first_regno + n) && this_regno != 31)
> +	    return false;
> +	}
> +    }

Please instead check that the registers are in ascending order,
build a mask, and then check that mask against umips_swm_mask at the end.

> +}
> +/* Return true if MEM1 and MEM2 use the same base register, and the

Missing space between functions.

> +   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
> +   register into (from) which the contents of MEM1 will be loaded
> +   (stored), depending on the value of LOAD_P.
> +   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
> +
> +static bool
> +umips_load_store_pair_p_1 (bool load_p, bool swap_p, rtx first_reg,
> +			   rtx mem1, rtx mem2)
> +{
> +  rtx base1, base2;
> +  HOST_WIDE_INT offset1, offset2;
> +
> +  if (!MEM_P (mem1) || !MEM_P (mem2))
> +    return false;
> +
> +  /* Make sure memory is base plus offset.  */
> +  if (GET_CODE (XEXP (mem1, 0)) != PLUS
> +      || GET_CODE (XEXP (mem2, 0)) != PLUS
> +      || GET_CODE (XEXP (XEXP (mem1, 0), 1)) != CONST_INT
> +      || GET_CODE (XEXP (XEXP (mem2, 0), 1)) != CONST_INT)
> +    return false;
> +
> +  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
> +  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);

Please remove the:

  /* Make sure memory is base plus offset.  */
  if (GET_CODE (XEXP (mem1, 0)) != PLUS
      || GET_CODE (XEXP (mem2, 0)) != PLUS
      || GET_CODE (XEXP (XEXP (mem1, 0), 1)) != CONST_INT
      || GET_CODE (XEXP (XEXP (mem2, 0), 1)) != CONST_INT)
    return false;

part.  The point of using mips_split_plus is that we want to handle
(reg) paired with (plus (reg) (const_int 4)) and (plus (reg) (const_int -4))
paired with (reg).

> +  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
> +    return false;
> +
> +  /* Avoid invalid load pair instructions.  */
> +  if (load_p && REGNO (first_reg) == REGNO (base1))
> +    return false;
> +
> +  /* We must avoid this case for anti-dependence.
> +     Ex:  lw $3, 4($3)
> +          lw $2, 0($3)
> +     first_reg is $2, but the base is $3.  */
> +  if (load_p && swap_p && (REGNO (first_reg) + 1) == REGNO (base1))
> +    return false;

Redundant brackets around "REGNO (first_reg) + 1".

> +
> +  if (swap_p
> +      && offset2 + 4 != offset1)
> +    return false;
> +
> +  if (offset1 + 4 != offset2)
> +    return false;

This always returns false for swap_p.  Please add tests for both cases
to make sure that the code is triggering.  E.g. you could have an inline
asm that takes two asm register variables, one in $2 and one in $3.

> +bool
> +umips_load_store_pair_p (bool load_p, rtx *operands)

Function needs a comment.

> +{
> +  rtx reg1, reg2, mem1, mem2;
> +
> +  if (load_p)
> +    {
> +      reg1 = operands[0];
> +      reg2 = operands[2];
> +      mem1 = operands[1];
> +      mem2 = operands[3];
> +    }
> +  else
> +    {
> +      reg1 = operands[1];
> +      reg2 = operands[3];
> +      mem1 = operands[0];
> +      mem2 = operands[2];
> +    }
> +
> +  if (REGNO (reg2) == REGNO (reg1) + 1)
> +      return umips_load_store_pair_p_1 (load_p, false, reg1, mem1, mem2);
> +
> +  else if (REGNO (reg1) == REGNO (reg2) + 1)
> +      return umips_load_store_pair_p_1 (load_p, true, reg2, mem1, mem2);
> +
> +  return false;

Excess indentation.  Probably better without the "else", since this is
really early-exit style.

> +/* Return the assembly instruction for microMIPS lwp or swp.
> +   LOAD_P is true for load.  */
> +
> +static void
> +umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
> +{
> +  HOST_WIDE_INT offset;
> +  rtx base, local_ops[3];
> +
> +  gcc_assert (REG_P (reg) && MEM_P (mem));
> +
> +  mips_split_plus (XEXP (mem, 0), &base, &offset);
> +  gcc_assert (REG_P (base));
> +
> +  local_ops[0] = reg;
> +  local_ops[1] = gen_rtx_CONST_INT (Pmode, offset);
> +  local_ops[2] = base;
> +  if (load_p)
> +    output_asm_insn ("lwp %0,%1(%2)", local_ops);
> +  else
> +    output_asm_insn ("swp %0,%1(%2)", local_ops);
> +}

This ought to be equivalent to:

  rtx ops[] = { reg, mem };

  if (load_p)
    output_asm_insn ("lwp %0,%1", ops);
  else
    output_asm_insn ("swp %0,%1", ops);

> +/* Return true if reg1 and reg2 can be target of movep.  */
> +
> +bool
> +umips_movep_target_p (rtx reg1, rtx reg2)
> +{
> +  int regno1, regno2, pair;
> +  unsigned int i;
> +  static const int match[8] = {0x00000060,	/* 5, 6 */
> +			       0x000000a0,	/* 5, 7 */
> +			       0x000000c0,	/* 6, 7 */
> +			       0x00200010,	/* 4, 21 */
> +			       0x00400010,	/* 4, 22 */
> +			       0x00000030,	/* 4, 5 */
> +			       0x00000050,	/* 4, 6 */
> +			       0x00000090};	/* 4, 7 */

Should be formatted as:

  static const int match[8] = {
    0x00000060,	/* 5, 6 */
    ...
  };

> +  for (i = 0; i < ARRAY_SIZE (match); i++)
> +    {
> +      if (pair == match[i])
> +	return true;
> +    }

Redundant { ... }.

> @@ -2452,18 +2459,48 @@ typedef struct mips_args {
>     all calls should use assembly macros.  Otherwise, all indirect
>     calls should use "jr" or "jalr"; we will arrange to restore $gp
>     afterwards if necessary.  Finally, we can only generate direct
> -   calls for -mabicalls by temporarily switching to non-PIC mode.  */
> +   calls for -mabicalls by temporarily switching to non-PIC mode.
> +
> +   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
> +   instruction is in the delay slot of jal(r).  */
>  #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
> +  (TARGET_MICROMIPS						\
> +   ? (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
> +      ? (TARGET_INTERLINK_UNCOMPRESSED				\
> +	 ? "%*" INSN "%!\t%" #TARGET_OPNO "%/"			\
> +	 : "%*" INSN "\t%" #TARGET_OPNO "%/")			\

Is this special case really necessary?  Normally when using assembly
macros we should leave the choice up to the assembler.  On the one
hand we gain by having knowledge that the target is microMIPS,
while on the other we lose because the assembler can't fill the
delay slot with a 32-bit instruction from a preceding assembly macro.

Hopefully no-one really uses -mno-explicit-relocs these days anyway,
so I think this case should be handled in the same way for all modes.

I.e.:

  TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
  ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
  : REG_P (OPERANDS[TARGET_OPNO])				\
  ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)		\
     ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
        "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
     : TARGET_MICROMIPS && TARGET_INTERLINK_UNCOMPRESSED        \
     ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"			\
     : "%*" INSN "r\t%" #TARGET_OPNO "%/")			\
  : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/")))

if that works.

> +\f
> +/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
> +   "jrc" when nop is in the delay slot of "jr".  */
> +#define MICROMIPS_J(OPERANDS, OPNO)				\
>    (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
> -   ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
> -   : (REG_P (OPERANDS[TARGET_OPNO])				\
> -      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
> -   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
> -      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
> -   : REG_P (OPERANDS[TARGET_OPNO])				\
> -   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"				\
> -   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
> -\f
> +   ? "%*j\t%" #OPNO "%/"					\
> +   : REG_P (OPERANDS[OPNO])					\
> +   ? "%*jr%:\t%" #OPNO						\
> +   : TARGET_ABICALLS && flag_pic				\
> +   ? (".option\tpic0\n\t"					\
> +      "%*j\t%" #OPNO "%/\n\t"					\
> +      ".option\tpic2")						\
> +   : "%*j\t%" #OPNO "%/")

Looks like the last bit could/should use MIPS_ABSOLUTE_JUMP.

> @@ -2923,3 +2960,5 @@ extern GTY(()) struct target_globals *mips16_globa
>     with arguments ARGS.  */
>  #define PMODE_INSN(NAME, ARGS) \
>    (Pmode == SImode ? NAME ## _si ARGS : NAME ## _di ARGS)
> +
> +#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))

Please put this after #define LUI_INT, to keep the range checks together.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-01-23 20:05         ` Richard Sandiford
@ 2013-01-26  3:52           ` Maciej W. Rozycki
  2013-01-26 10:17             ` Richard Sandiford
  2013-02-12 19:00           ` Moore, Catherine
  1 sibling, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2013-01-26  3:52 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Moore, Catherine, gcc-patches

On Wed, 23 Jan 2013, Richard Sandiford wrote:

> > Index: config/mips/gnu-user.h
> > ===================================================================
> > --- config/mips/gnu-user.h	(revision 195351)
> > +++ config/mips/gnu-user.h	(working copy)
> > @@ -137,3 +137,12 @@ extern const char *host_detect_local_cpu (int argc
> >  #define ENDFILE_SPEC \
> >    GNU_USER_TARGET_MATHFILE_SPEC " " \
> >    GNU_USER_TARGET_ENDFILE_SPEC
> > +
> > +#undef SUBTARGET_OVERRIDE_OPTIONS
> > +#define SUBTARGET_OVERRIDE_OPTIONS                              \
> > +do {                                                            \
> > +  /* microMIPS PLT entries are non-microMIPS.  */               \
> > +  TARGET_INTERLINK_COMPRESSED = 1;                              \
> > +} while (0)
> > +
> > +
> 
> Hmm, that sounds like a reason to set TARGET_INTERLINK_UNCOMPRESSED
> rather than TARGET_INTERLINK_COMPRESSED.  I.e. we need to avoid direct
> branches from microMIPS code to standard PLTs.
> 
> But that means that microMIPS code can't even jump directly to functions
> that have a micromips attribute when the call might go via a PLT.
> TARGET_INTERLINK_(UN)COMPRESSED doesn't cover that case.  I think instead
> we need to handle it directly in mips_function_ok_for_sibcall,
> keyed off TARGET_ABICALLS_PIC0.  Specific suggestion below.
[...]
> >    /* We can't do a sibcall if the called function is a MIPS16 function
> >       because there is no direct "jx" instruction equivalent to "jalx" to
> >       switch the ISA mode.  We only care about cases where the sibling
> >       and normal calls would both be direct.  */
> >    if (decl
> > -      && mips_use_mips16_mode_p (decl)
> > +      && ((compression_mode & (MASK_MIPS16 | MASK_MICROMIPS)) != 0)
> >        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
> >      return false;
> >  
> > -  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
> > -     functions could be MIPS16 ones unless an attribute explicitly tells
> > +  /* When -minterlink-compressed is in effect, assume that non-locally-binding
> > +     functions could be MIPS16 or microMIPS unless an attribute explicitly tells
> >       us otherwise.  */
> > -  if (TARGET_INTERLINK_MIPS16
> > +  if (TARGET_INTERLINK_COMPRESSED
> >        && decl
> >        && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
> > -      && !mips_nomips16_decl_p (decl)
> > +      && (compression_mode & MASK_MICROMIPS) == 0
> > +      && (compression_mode & MASK_MIPS16) == 0
> >        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
> >      return false;
> 
> should be something like:
> 
>   /* Direct Js are only possible to functions that use the same ISA encoding.
>      There is no JX counterpart of JALX.  */
>   if (decl
>       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
>       && mips_call_may_need_jalx_p (decl))
>     return false;
> 
> with:
> 
> /* Return true if a call to DECL may need to use JALX.  */
> 
> static bool
> mips_call_may_need_jalx_p (decl)
> {
>   /* If the current translation unit would use a different mode for DECL,
>      assume that the call needs JALX.  */
>   if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
>     return true;
> 
>   /* mips_get_compress_mode is always accurate for locally-binding
>      functions in the current translation unit.  */
>   if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
>     return false;
> 
>   /* PLTs use the standard encoding, so calls that might go via PLTs
>      must use JALX.  */
>   if (TARGET_COMPRESSED
>       && TARGET_ABICALLS_PIC0
>       && DECL_EXTERNAL (decl)
>       && !targetm.binds_local_p (decl))
>     return true;
> 
>   /* When -minterlink-compressed is in effect, assume that functions
>      could use a different encoding mode unless an attribute explicitly
>      tells us otherwise.  */
>   if (TARGET_INTERLINK_COMPRESSED)
>     {
>       if (!TARGET_COMPRESSION && mips_get_compress_off_flags (decl) == 0)
>         return true;
>       if (TARGET_COMPRESSION && mips_get_compress_on_flags (decl) == 0)
>         return true;
>     }
> 
>   return false;
> }
> 
> The TARGET_ABICALLS_PIC0 case should deal with the gnu-user.h comment above.

 How about instead of complicating this we simply add support for 
microMIPS encoding in the PLT?  I think I should be able to squeeze out 
some time next week to dust off and retest the binutils patch I've had 
pending far too long now.  This way we won't have to maintain separate 
cases where tail calls may or may not be made via the PLT.

 Note that we need that support sooner or later anyway due to the prospect 
of pure-microMIPS processors.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-01-26  3:52           ` Maciej W. Rozycki
@ 2013-01-26 10:17             ` Richard Sandiford
  2013-01-27 13:58               ` Maciej W. Rozycki
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-01-26 10:17 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Moore, Catherine, gcc-patches

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> On Wed, 23 Jan 2013, Richard Sandiford wrote:
>> > Index: config/mips/gnu-user.h
>> > ===================================================================
>> > --- config/mips/gnu-user.h	(revision 195351)
>> > +++ config/mips/gnu-user.h	(working copy)
>> > @@ -137,3 +137,12 @@ extern const char *host_detect_local_cpu (int argc
>> >  #define ENDFILE_SPEC \
>> >    GNU_USER_TARGET_MATHFILE_SPEC " " \
>> >    GNU_USER_TARGET_ENDFILE_SPEC
>> > +
>> > +#undef SUBTARGET_OVERRIDE_OPTIONS
>> > +#define SUBTARGET_OVERRIDE_OPTIONS                              \
>> > +do {                                                            \
>> > +  /* microMIPS PLT entries are non-microMIPS.  */               \
>> > +  TARGET_INTERLINK_COMPRESSED = 1;                              \
>> > +} while (0)
>> > +
>> > +
>> 
>> Hmm, that sounds like a reason to set TARGET_INTERLINK_UNCOMPRESSED
>> rather than TARGET_INTERLINK_COMPRESSED.  I.e. we need to avoid direct
>> branches from microMIPS code to standard PLTs.
>> 
>> But that means that microMIPS code can't even jump directly to functions
>> that have a micromips attribute when the call might go via a PLT.
>> TARGET_INTERLINK_(UN)COMPRESSED doesn't cover that case.  I think instead
>> we need to handle it directly in mips_function_ok_for_sibcall,
>> keyed off TARGET_ABICALLS_PIC0.  Specific suggestion below.
> [...]
>> >    /* We can't do a sibcall if the called function is a MIPS16 function
>> >       because there is no direct "jx" instruction equivalent to "jalx" to
>> >       switch the ISA mode.  We only care about cases where the sibling
>> >       and normal calls would both be direct.  */
>> >    if (decl
>> > -      && mips_use_mips16_mode_p (decl)
>> > +      && ((compression_mode & (MASK_MIPS16 | MASK_MICROMIPS)) != 0)
>> >        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
>> >      return false;
>> >  
>> > -  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
>> > -     functions could be MIPS16 ones unless an attribute explicitly tells
>> > +  /* When -minterlink-compressed is in effect, assume that non-locally-binding
>> > +     functions could be MIPS16 or microMIPS unless an attribute explicitly tells
>> >       us otherwise.  */
>> > -  if (TARGET_INTERLINK_MIPS16
>> > +  if (TARGET_INTERLINK_COMPRESSED
>> >        && decl
>> >        && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
>> > -      && !mips_nomips16_decl_p (decl)
>> > +      && (compression_mode & MASK_MICROMIPS) == 0
>> > +      && (compression_mode & MASK_MIPS16) == 0
>> >        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
>> >      return false;
>> 
>> should be something like:
>> 
>>   /* Direct Js are only possible to functions that use the same ISA encoding.
>>      There is no JX counterpart of JALX.  */
>>   if (decl
>>       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
>>       && mips_call_may_need_jalx_p (decl))
>>     return false;
>> 
>> with:
>> 
>> /* Return true if a call to DECL may need to use JALX.  */
>> 
>> static bool
>> mips_call_may_need_jalx_p (decl)
>> {
>>   /* If the current translation unit would use a different mode for DECL,
>>      assume that the call needs JALX.  */
>>   if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
>>     return true;
>> 
>>   /* mips_get_compress_mode is always accurate for locally-binding
>>      functions in the current translation unit.  */
>>   if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
>>     return false;
>> 
>>   /* PLTs use the standard encoding, so calls that might go via PLTs
>>      must use JALX.  */
>>   if (TARGET_COMPRESSED
>>       && TARGET_ABICALLS_PIC0
>>       && DECL_EXTERNAL (decl)
>>       && !targetm.binds_local_p (decl))
>>     return true;
>> 
>>   /* When -minterlink-compressed is in effect, assume that functions
>>      could use a different encoding mode unless an attribute explicitly
>>      tells us otherwise.  */
>>   if (TARGET_INTERLINK_COMPRESSED)
>>     {
>>       if (!TARGET_COMPRESSION && mips_get_compress_off_flags (decl) == 0)
>>         return true;
>>       if (TARGET_COMPRESSION && mips_get_compress_on_flags (decl) == 0)
>>         return true;
>>     }
>> 
>>   return false;
>> }
>> 
>> The TARGET_ABICALLS_PIC0 case should deal with the gnu-user.h comment above.
>
>  How about instead of complicating this we simply add support for 
> microMIPS encoding in the PLT?  I think I should be able to squeeze out 
> some time next week to dust off and retest the binutils patch I've had 
> pending far too long now.  This way we won't have to maintain separate 
> cases where tail calls may or may not be made via the PLT.
>
>  Note that we need that support sooner or later anyway due to the prospect 
> of pure-microMIPS processors.

Just so I know: what does the PLT patch do for external functions
that are jumped to by both microMIPS and non-microMIPS code?

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-01-26 10:17             ` Richard Sandiford
@ 2013-01-27 13:58               ` Maciej W. Rozycki
  2013-01-28 10:14                 ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2013-01-27 13:58 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Moore, Catherine, gcc-patches

On Sat, 26 Jan 2013, Richard Sandiford wrote:

> >  How about instead of complicating this we simply add support for 
> > microMIPS encoding in the PLT?  I think I should be able to squeeze out 
> > some time next week to dust off and retest the binutils patch I've had 
> > pending far too long now.  This way we won't have to maintain separate 
> > cases where tail calls may or may not be made via the PLT.
> >
> >  Note that we need that support sooner or later anyway due to the prospect 
> > of pure-microMIPS processors.
> 
> Just so I know: what does the PLT patch do for external functions
> that are jumped to by both microMIPS and non-microMIPS code?

 Two PLT entries are produced in that case.

 PLT entries are created based on the relocation type referring: R_MIPS_26 
relocations trigger a standard MIPS PLT entry, R_MICROMIPS_26_S1 
relocations trigger a microMIPS PLT entry.  Other relocations reuse a PLT 
entry already produced for one of the jump relocations, or if none 
present, then they make an own PLT entry according to ELF file header 
flags: if EF_MIPS_ARCH_ASE_MICROMIPS is set, then a microMIPS entry is 
produced, otherwise a standard MIPS one.  Therefore depending on 
relocations seen up to two entries can be produced, encoded differently so 
that there is no need to switch modes with direct jumps.

 If all the individual PLT entries ultimately produced are microMIPS code, 
then the PLT header is built as microMIPS code as well, otherwise it's 
standard MIPS code.  This guarantees no standard MIPS code is produced in 
the PLT if there's none already in the executable (and vice versa).

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-01-27 13:58               ` Maciej W. Rozycki
@ 2013-01-28 10:14                 ` Richard Sandiford
  0 siblings, 0 replies; 41+ messages in thread
From: Richard Sandiford @ 2013-01-28 10:14 UTC (permalink / raw)
  To: Maciej W. Rozycki; +Cc: Moore, Catherine, gcc-patches

"Maciej W. Rozycki" <macro@codesourcery.com> writes:
> On Sat, 26 Jan 2013, Richard Sandiford wrote:
>
>> >  How about instead of complicating this we simply add support for 
>> > microMIPS encoding in the PLT?  I think I should be able to squeeze out 
>> > some time next week to dust off and retest the binutils patch I've had 
>> > pending far too long now.  This way we won't have to maintain separate 
>> > cases where tail calls may or may not be made via the PLT.
>> >
>> >  Note that we need that support sooner or later anyway due to the prospect 
>> > of pure-microMIPS processors.
>> 
>> Just so I know: what does the PLT patch do for external functions
>> that are jumped to by both microMIPS and non-microMIPS code?
>
>  Two PLT entries are produced in that case.
>
>  PLT entries are created based on the relocation type referring: R_MIPS_26 
> relocations trigger a standard MIPS PLT entry, R_MICROMIPS_26_S1 
> relocations trigger a microMIPS PLT entry.  Other relocations reuse a PLT 
> entry already produced for one of the jump relocations, or if none 
> present, then they make an own PLT entry according to ELF file header 
> flags: if EF_MIPS_ARCH_ASE_MICROMIPS is set, then a microMIPS entry is 
> produced, otherwise a standard MIPS one.  Therefore depending on 
> relocations seen up to two entries can be produced, encoded differently so 
> that there is no need to switch modes with direct jumps.
>
>  If all the individual PLT entries ultimately produced are microMIPS code, 
> then the PLT header is built as microMIPS code as well, otherwise it's 
> standard MIPS code.  This guarantees no standard MIPS code is produced in 
> the PLT if there's none already in the executable (and vice versa).

Thanks, sounds good!  In that case, yeah, let's leave the TARGET_ABICALLS_PIC0
part out (but keep the rest of mips_call_may_need_jalx_p).

For avoidance of doubt: I don't think there's any need to wait for the
linker patches before sending the updated GCC patch.  The GCC patch can
only go in 4.9 anyway, and the new PLT code won't be avaiable until 2.24,
so there's plenty of time on both sides.  Testing the GCC patch against
Mentor's linker is fine with me.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-01-23 20:05         ` Richard Sandiford
  2013-01-26  3:52           ` Maciej W. Rozycki
@ 2013-02-12 19:00           ` Moore, Catherine
  2013-02-13 11:43             ` Richard Sandiford
  1 sibling, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-02-12 19:00 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 51113 bytes --]

Hi Richard,

A new patch that incorporates your latest suggestions is attached.  I hope that we are converging on an implementation.

I have at least three follow-on patches to submit (short delay slot identification, jraddiusp, and testsuite cleanup). 

You had requested that the -mno-jals option be changed to -mno-interlink-uncompress.  I'd like to support -mno-jals (as an alias for -mno-interlink-uncompress) to accommodate folks who are already using that option.  If you don't have objections, I will submit that as a follow-on patch as well.

As usual, thanks for the thorough review.
Catherine

> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Wednesday, January 23, 2013 3:05 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> Hi Catherine,
> 
> Thanks for the update.  Despite the length of this reply, there isn't anything
> major.
> 
> Please don't change all NOMIPS16 to NOCOMPRESSION in the testsuite.
> Most NOMIPSs are there because of the drastically reduced MIPS16
> instruction set.  I would have expected most of them to pass with
> microMIPS.
> 
> Instead, please add NOCOMPRESSION as an alternative to NOMIPS16, and
> only change NOMIPS16 to NOCOMPRESSION in tests that also fail for
> microMIPS.  I think that should be a separate patch and isn't really a
> prerequisite for the core patch going in, although obviously it would better if
> the testsuite results were clean.  Please explain why each
> NOMIPS16 to NOCOMPRESSION change is needed; even if it's obvious to
> you, it probably won't be to me.
> 
> There need to be more test casees.  We should at least test:
> 
> * LWM and SWM (see gcc.target/mips/save-restore-* for possible
> templates)
> * MOVEP
> * positive LWP and SWP tests (rather than just the volatile "not used" one)
> * the new asm constraints
> 
> (Unlike the NOCOMPRESSION bits, these should be part of the core patch.)
> 
> 
> As a general comment, I think it would be good to have:
> 
> /* The ISA compression flags that are currently in effect.  */ #define
> TARGET_COMPRESSION (target_flags & (MASK_MIPS16 |
> MASK_MICROMIPS))
> 
> I've used this in some of the comments below.
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> > Index: config/mips/linux-unwind.h
> >
> ==========================================================
> =========
> > --- config/mips/linux-unwind.h	(revision 195304)
> > +++ config/mips/linux-unwind.h	(working copy)
> > @@ -52,6 +52,11 @@
> >    _Unwind_Ptr new_cfa, reg_offset;
> >    int i;
> >
> > +  /* microMIPS frame; the kernel does not have microMIPS signal
> > +     frames.  */
> > +  if ((_Unwind_Ptr) pc & 3)
> > +    return _URC_END_OF_STACK;
> 
> Should mention MIPS16 too.  E.g.:
> 
>   /* A MIPS16 or microMIPS frame.  Signal frames always use the standard
>      ISA encoding.  */
> 
> > @@ -15991,18 +15995,33 @@ Generate MIPS16 code on alternating
> > functions.  Th  for regression testing of mixed MIPS16/non-MIPS16 code
> > generation, and is  not intended for ordinary use in compiling user code.
> >
> > +@item -minterlink-compressed
> > +@item -mno-interlink-compressed
> > +@opindex minterlink-compressed
> > +@opindex mno-interlink-compressed
> > +Require (do not require) that code using the standard (uncompressed)
> > +MIPS ISA be link-compatible with MIPS16 and microMIPS code.
> > +
> > +For example, non-MIPS16 code cannot jump directly to MIPS16 code; it
> > +must either use a call or an indirect jump.  The same applies to
> > +non-microMIPS jumps to microMIPS code.
> > +@option{-minterlink-compressed} therefore disables direct jumps unless
> GCC knows that the target of the jump is not compressed.
> 
> I think I'm reediting a previous suggestion, sorry, but:
> 
>   For example, code using the standard ISA encoding cannot jump directly
>   to MIPS16 or microMIPS code; it must either use a call or an indirect jump.
>   @option{-minterlink-compressed} therefore disables direct jumps unless
> GCC
>   knows that the target of the jump is not compressed.
> 
> > +@item -minterlink-uncompressed
> > +@item -mno-interlink-uncompressed
> > +@opindex minterlink-compressed
> > +@opindex mno-interlink-compressed
> > +Require (do not require) that code using microMIPS instructions be
> > +link-compatible with the standard (uncompressed) MIPS ISA.
> 
> The distinction between this and -minterlink-compressed seems confusing to
> me, and it wasn't handled consistently in the patch (see the sibcall and gnu-
> user.h comments below).  I think it would be better to fold the functionality
> into -minterlink-compressed, with the documentation changed to:
> 
>   Require (do not require) that code using the standard (uncompressed)
> MIPS ISA
>   be link-compatible with MIPS16 and microMIPS code, and vice versa.
> 
> > Index: config/mips/gnu-user.h
> >
> ==========================================================
> =========
> > --- config/mips/gnu-user.h	(revision 195351)
> > +++ config/mips/gnu-user.h	(working copy)
> > @@ -137,3 +137,12 @@ extern const char *host_detect_local_cpu (int
> > argc  #define ENDFILE_SPEC \
> >    GNU_USER_TARGET_MATHFILE_SPEC " " \
> >    GNU_USER_TARGET_ENDFILE_SPEC
> > +
> > +#undef SUBTARGET_OVERRIDE_OPTIONS
> > +#define SUBTARGET_OVERRIDE_OPTIONS                              \
> > +do {                                                            \
> > +  /* microMIPS PLT entries are non-microMIPS.  */               \
> > +  TARGET_INTERLINK_COMPRESSED = 1;                              \
> > +} while (0)
> > +
> > +
> 
> Hmm, that sounds like a reason to set TARGET_INTERLINK_UNCOMPRESSED
> rather than TARGET_INTERLINK_COMPRESSED.  I.e. we need to avoid direct
> branches from microMIPS code to standard PLTs.
> 
> But that means that microMIPS code can't even jump directly to functions
> that have a micromips attribute when the call might go via a PLT.
> TARGET_INTERLINK_(UN)COMPRESSED doesn't cover that case.  I think
> instead we need to handle it directly in mips_function_ok_for_sibcall, keyed
> off TARGET_ABICALLS_PIC0.  Specific suggestion below.
> 
> > +(define_insn "*lwp"
> > +  [(parallel [(set (match_operand:SI 0 "d_operand")
> > +		   (match_operand:SI 1 "non_volatile_mem_operand"))
> > +	      (set (match_operand:SI 2 "d_operand")
> > +		   (match_operand:SI 3 "non_volatile_mem_operand"))])]
> > +
> > +  "TARGET_MICROMIPS
> > +   && umips_load_store_pair_p (true, operands)"
> > +  {
> > +    umips_output_load_store_pair (true, operands);
> > +    return "";
> > +  }
> 
> Very minor, sorry, but other MIPS patterns put multiline { ... } blocks in
> column 0.  Same for *swp, but *movep<MOVEP1:mode><MOVEP2:mode> is
> already OK.
> 
> > +  [(set_attr "type" "load")
> > +   (set_attr "mode" "SI")
> > +   (set_attr "can_delay" "no")])
> 
> Please add a comment saying why LWP can't go in a delay slot.
> Same for SWP and MOVEP.
> 
> > +(define_insn "mips_jraddiusp"
> > +  [(parallel [(return)
> > +              (use (reg:SI 31))
> > +	      (set (reg:SI 29)
> > +		   (plus:SI (reg:SI 29)
> > +			    (match_operand 0 "const_int_operand")))])]
> > +  "TARGET_MICROMIPS"
> > +  "jraddiusp\t%0"
> > +  [(set_attr "type" "trap")
> > +   (set_attr "mode" "SI")
> > +   (set_attr "can_delay" "no")])
> 
> Is this pattern used?  If not, please leave it out for now.
> If it is used, please add a testcase.
> 

> > +; For movep
> > +(define_peephole2
> > +  [(set (match_operand:MOVEP1 0 "register_operand" "")
> > +        (match_operand:MOVEP1 1 "movep_operand" ""))
> > +   (set (match_operand:MOVEP2 2 "register_operand" "")
> > +        (match_operand:MOVEP2 3 "movep_operand" ""))]
> > +  "TARGET_MICROMIPS
> > +   && umips_movep_target_p (operands[0], operands[2])"
> > +  [(parallel [(set (match_dup 0) (match_dup 1))
> > +              (set (match_dup 2) (match_dup 3))])]
> > +)
> 
> Probably not worth having movep_operand, because all the checking is done
> by umips_movep_target_p.  reg_or_0_operand should be OK.      

The source and target register criteria are not identical.  I've now renamed the movep_operand predicate to movep_src_operand. 
> 
> > Index: config/mips/constraints.md
> >
> ==========================================================
> =========
> > --- config/mips/constraints.md	(revision 195351)
> > +++ config/mips/constraints.md	(working copy)
> > @@ -232,6 +232,26 @@
> >     "@internal"
> >     (match_operand 0 "low_bitmask_operand"))
> >
> > +(define_memory_constraint "ZC"
> > +  "When compiling microMIPS code, this constraing matches a memory
> operand
> > +   whose address is formed from a base register and a 12-bit offset.  These
> > +   operands can be used for microMIPS instructions such as @code{ll} and
> > +   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
> > +   equivalent to @code{R}."
> > +  (and (match_code "mem")
> > +       (ior (and (match_test "TARGET_MICROMIPS")
> > +		 (match_test "umips_12bit_offset_address_p (XEXP (op, 0),
> mode)"))
> > +	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
> 
> The last line should be:
> 
>    (match_test "mips_address_insns (XEXP (op, 0), mode, false) == 1")
> 
> to match "R".  The documentation makes it sound like an if-then-else, but
> the implementation isn't.  Should it be:
> 
>   (and (match_code "mem")
>        (if_then_else
> 	 (match_test "TARGET_MICROMIPS")
> 	 (match_test "umips_12bit_offset_address_p (XEXP (op, 0),
> mode)"))
> 	 (match_test "mips_address_insns (XEXP (op, 0), mode, false) ==
> 1"))))
> 
> instead?
> 
> > +(define_address_constraint "ZD"
> > +  "When compiling microMIPS code, this constraint matches an address
> operand
> > +   that is formed from a base register and a 12-bit offset.  These operands
> > +   can be used for microMIPS instructions such as @code{prefetch}.  When
> > +   not compiling for microMIPS code, @code{YC} is equivalent to
> @code{p}."
> > +   (ior (and (match_test "TARGET_MICROMIPS")
> > +	     (match_test "umips_12bit_offset_address_p (op, mode)"))
> > +	(match_test "mips_address_insns (op, mode, false)")))
> 
> Same comments here.
> 
> > +;; Return 1 if the operand is in non-volatile memory.  Note that
> > +during the ;; RTL generation phase, memory_operand does not return
> > +TRUE for volatile ;; memory references.  So this function allows us
> > +to recognize volatile ;; references where it's safe.
> > +(define_predicate "non_volatile_mem_operand"
> > +  (and (match_operand 0 "memory_operand")
> > +       (not (match_test "MEM_VOLATILE_P (op)"))))
> 
> I don't understand the comment.  We're trying to avoid all volatile
> references.
> 
> > +minterlink-uncompressed
> > +Target Report Var(TARGET_INTERLINK_UNCOMPRESSED) Init(1)
> Generated
> > +code that is link-compatible with the standard (uncompressed) MIPS
> > +ISA.
> 
> Do multi-line documentation strings work?  Please check the --target-help
> output to make sure.
> 
Yes, this does work.

> > Index: config/mips/mips.c
> >
> ==========================================================
> =========
> > --- config/mips/mips.c	(revision 195351)
> > +++ config/mips/mips.c	(working copy)
> > @@ -77,6 +77,9 @@ along with GCC; see the file COPYING3.  If not see
> >     preserve the maximum stack alignment.  We therefore use a value
> >     of 0x7ff0 in this case.
> >
> > +   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
> > +   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
> > +
> >     MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
> >     up to 0x7f8 bytes and can usually save or restore all the registers
> >     that we need to save or restore.  (Note that we can only use these
> > @@ -87,7 +90,8 @@ along with GCC; see the file COPYING3.  If not see
> >     to save and restore registers, and to allocate and deallocate the top
> >     part of the frame.  */
> >  #define MIPS_MAX_FIRST_STACK_STEP
> 	\
> > -  (!TARGET_MIPS16 ? 0x7ff0						\
> > +  ((!TARGET_MIPS16 && !TARGET_MICROMIPS) ? 0x7ff0
> 	\
> > +   : TARGET_MICROMIPS ? 0x7f0
> 	\
> >     : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8
> 	\
> >     : TARGET_64BIT ? 0x100 : 0x400)
> 
> I'd prefer:
> 
>   (TARGET_MICROMIPS ? 0x7f0						\
>    : !TARGET_MIPS16 ? 0x7ff0						\
>    : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8
> 	\
>    : TARGET_64BIT ? 0x100 : 0x400)
> 
> The comment doesn't really explain the reason for 0x7f0 rather than 0x7f8.
> Is this in anticipation of future n32 and n64 support, where the stack must be
> 16-byte aligned?  If so, that's OK, but worth mentioning.
> 
> > @@ -1167,10 +1174,11 @@ mflip_mips16_use_mips16_p (tree decl)
> >    const char *name;
> >    hashval_t hash;
> >    void **slot;
> > +  bool base_is_mips16 = mips_base_compression_flags & MASK_MIPS16;
> 
> Please make this:
> 
>   bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) !=
> 0;
> 
> > @@ -1257,12 +1252,57 @@ mips_use_debug_exception_return_p (tree
> type)
> >  			   TYPE_ATTRIBUTES (type)) != NULL;  }
> >
> > -/* Return true if function DECL is a MIPS16 function.  Return the ambient
> > -   setting if DECL is null.  */
> > +/* Return the set of compression modes that are explicitly required
> > +   by DECL.  */
> >
> > -static bool
> > -mips_use_mips16_mode_p (tree decl)
> > +static unsigned int
> > +mips_get_compress_on_flags (tree decl)
> >  {
> > +  unsigned int flags = 0;
> > +
> > +  if (!decl || !DECL_P (decl))
> > +    return flags;
> 
> Is this check necessary?  Same for mips_get_compress_off_flags.
> 
> > @@ -1297,29 +1337,47 @@ static void
> >  mips_insert_attributes (tree decl, tree *attributes)  {
> >    const char *name;
> > -  bool mips16_p, nomips16_p;
> > +  unsigned int compression_p, nocompression_p;
> 
> No _p, since these aren't booleans now.  _flags would be better.
> 
> >    /* Check for "mips16" and "nomips16" attributes.  */
> > -  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
> > -  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
> > +  compression_p = mips_get_compress_on_flags (decl);
> nocompression_p
> > + = mips_get_compress_off_flags (decl);
> > +
> >    if (TREE_CODE (decl) != FUNCTION_DECL)
> >      {
> > -      if (mips16_p)
> > +      if (compression_p & MASK_MIPS16)
> >  	error ("%qs attribute only applies to functions", "mips16");
> > -      if (nomips16_p)
> > +      if (nocompression_p & MASK_MIPS16)
> >  	error ("%qs attribute only applies to functions", "nomips16");
> > +
> > +      if (nocompression_p & MASK_MICROMIPS
> > +	  && nocompression_p & MASK_MIPS16)
> > +	error ("%qs attribute only applies to functions", "nocompression");
> 
> This case needs to come first, otherwise nomips16 will be reported instead.
> Although...
> 
> > +      else
> > +	{
> > +	  if (compression_p & MASK_MICROMIPS)
> > +	    error ("%qs attribute only applies to functions", "micromips");
> > +	  if (nocompression_p & MASK_MICROMIPS)
> > +	    error ("%qs attribute only applies to functions", "nomicromips");
> > +	}
> 
> ...I think it would be easier to have:
> 
> /* Return the attribute name associated with MASK_MIPS16 and
> MASK_MICROMIPS
>    flags FLAGS.  */
> 
> static const char *
> mips_get_compress_on_name (unsigned int flags) {
>   if (flags == MASK_MIPS16)
>     return "mips16";
>   return "micromips";
> }
> 
> /* Return the attribute that forbids MASK_MIPS16 and MASK_MICROMIPS
>    flags FLAGS.  */
> 
> static const char *
> mips_get_compress_off_name (unsigned int flags) {
>   if (flags == MASK_MIPS16)
>     return "nomips16";
>   if (flags == MASK_MICROMIPS)
>     return "nomicromips";
>   return "nocompression";
> }
> 
> Then:
> 
>       if (nocompression_flags)
>         error ("%qs attribute only applies to functions",
>                mips_get_compress_off_name (nocompression_flags));
>       if (compression_flags)
>         error ("%qs attribute only applies to functions",
>                mips_get_compress_on_name (compression_flags));
> 
> >      }
> >    else
> >      {
> > -      mips16_p |= mips_mips16_decl_p (decl);
> > -      nomips16_p |= mips_nomips16_decl_p (decl);
> > -      if (mips16_p || nomips16_p)
> > +      if (compression_p & MASK_MIPS16
> > +           && nocompression_p & (MASK_MIPS16 | MASK_MICROMIPS))
> >  	{
> > +	  /* DECL cannot be simultaneously "mips16" and "nocompression".
> */
> > +	  error ("%qE cannot have both %<mips16%> and "
> > +		 "%<nocompression%> attributes",
> > +		 DECL_NAME (decl));
> > +	}
> > +      else if (compression_p & MASK_MIPS16
> > +		&& nocompression_p & MASK_MIPS16)
> > +	{
> >  	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
> > -	  if (mips16_p && nomips16_p)
> > -	    error ("%qE cannot have both %<mips16%> and "
> > -		   "%<nomips16%> attributes",
> > -		   DECL_NAME (decl));
> > +	  error ("%qE cannot have both %<mips16%> and "
> > +		 "%<nomips16%> attributes",
> > +		 DECL_NAME (decl));
> >  	}
> >        else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
> >  	{
> > @@ -1329,6 +1387,39 @@ mips_insert_attributes (tree decl, tree
> *attribute
> >  	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" :
> "nomips16";
> >  	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> >  	}
> > +
> > +      if (compression_p & MASK_MICROMIPS
> > +           && nocompression_p & (MASK_MIPS16 | MASK_MICROMIPS))
> > +	{
> > +	  /* DECL cannot be simultaneously "micromips" and
> "nocompression".  */
> > +	  error ("%qE cannot have both %<micromips%> and "
> > +		 "%<nocompression%> attributes",
> > +		 DECL_NAME (decl));
> > +	}
> > +      else if (compression_p & MASK_MICROMIPS
> > +		&& nocompression_p & MASK_MICROMIPS)
> > +	{
> > +	  /* DECL cannot be simultaneously "micromips" and "nomicromips".
> */
> > +	  error ("%qs cannot have both %<micromips%> and "
> > +		 "%<nomicromips%> attributes",
> > +		 IDENTIFIER_POINTER (DECL_NAME (decl)));
> > +	}
> 
> All the above then becomes:
> 
>       if (compression_flags && nocompression_flags)
> 	error ("%qE cannot have both %qs and %qs attributes",
> 	       DECL_NAME (decl), mips_get_compress_on_name
> (compression_flags),
> 	       mips_get_compress_off_name (nocompression_flags));
> 
> > +
> > +      if (compression_p & MASK_MIPS16
> > +          && compression_p & MASK_MICROMIPS)
> > +	error ("%qs cannot have both %<mips16%> and %<micromips%>
> attributes",
> > +	       IDENTIFIER_POINTER (DECL_NAME (decl)));
> 
> %qE and no IDENTIFIER_POINTER.  Please use the %qs form here too, with
> "mips16" and "micromips" as error() arguments, so that one translation
> covers both this case and the previous one.
> 
> > +      /* If DECL is "nocompression" set the "nomips16" and
> > +	 "nomicromips" attributes.  */
> > +      if (nocompression_p & MASK_MIPS16
> > +          && nocompression_p & MASK_MICROMIPS)
> > +	{
> > +	  name = "nomips16";
> > +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> > +	  name = "nomicromips";
> > +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> > +	}
> 
> Hmm, why is this necessary?  Anything that cares should be using
> mips_get_compress_off_flags.
> 
> > @@ -1338,12 +1429,9 @@ static tree
> >  mips_merge_decl_attributes (tree olddecl, tree newdecl)  {
> >    /* The decls' "mips16" and "nomips16" attributes must match
> > exactly.  */
> > -  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
> > +  if (mips_get_compress_mode (olddecl) != mips_get_compress_mode
> > + (newdecl))
> >      error ("%qE redeclared with conflicting %qs attributes",
> > -	   DECL_NAME (newdecl), "mips16");
> > -  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p
> (newdecl))
> > -    error ("%qE redeclared with conflicting %qs attributes",
> > -	   DECL_NAME (newdecl), "nomips16");
> > +	   DECL_NAME (newdecl), "compression");
> 
> This should be:
> 
>   unsigned int diff;
> 
>   diff = (mips_get_compress_on_flags (olddecl)
>           ^ mips_get_compress_on_flags (newdecl));
>   if (diff)
>     error ("%qE redeclared with conflicting %qs attributes",
>            DECL_NAME (newdecl), mips_get_compress_on_name (diff));
> 
>   diff = (mips_get_compress_off_flags (olddecl)
>           ^ mips_get_compress_off_flags (newdecl));
>   if (diff)
>     error ("%qE redeclared with conflicting %qs attributes",
>            DECL_NAME (newdecl), mips_get_compress_off_name (diff));
> 
> > @@ -2300,6 +2388,20 @@ mips_address_insns (rtx x, enum
> machine_mode mode,
> >    return 0;
> >  }
> >
> > +/* Return true if X is a legitimate address with a 12-bit offset.
> > +   MODE is the mode of the value being accessed.  */
> > +
> > +bool
> > +umips_12bit_offset_address_p (rtx x, enum machine_mode mode) {
> > +  struct mips_address_info addr;
> > +
> > +  return (mips_classify_address(&addr, x, mode, false)
> 
> Space before '('
> 
> > +	  && addr.type == ADDRESS_REG
> > +	  && CONST_INT_P (addr.offset)
> > +	  && UMIPS_12BIT_OFFSET_P (addr.offset));
> 
> Isn't there a missing INTVAL here?  Please check the patch to make sure
> there are no compiler warnings.
> 
> > @@ -6908,6 +7017,8 @@ mips_split_call (rtx insn, rtx call_pattern)
> > static bool  mips_function_ok_for_sibcall (tree decl, tree exp
> > ATTRIBUTE_UNUSED)  {
> > +  unsigned int compression_mode = mips_get_compress_mode (decl);
> > +
> 
> Might as well move this down to where it's needed, especially now that
> we're C++.
> 
> >    if (!TARGET_SIBCALLS)
> >      return false;
> >
> > @@ -6916,22 +7027,45 @@ mips_function_ok_for_sibcall (tree decl, tree
> exp
> >    if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
> >      return false;
> >
> > +  if (TARGET_MICROMIPS)
> > +    {
> > +      /* We can't do a sibcall if the called function is a MIPS32
> > + function.  */
> 
> s/is a MIPS32 function/isn't microMIPS/, to avoid confusion with the MIPS32
> ISA.
> 
> > +      if (decl
> > +	  && (compression_mode & MASK_MICROMIPS) == 0
> > +	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0),
> VOIDmode))
> > +	return false;
> > +
> > +      /* When -minterlink-compressed is in effect, assume that non-locally-
> binding
> > +	 functions could be MIPS32 ones unless an attribute explicitly tells
> > +	 us otherwise.  */
> > +      if (TARGET_INTERLINK_COMPRESSED
> > +	  && decl
> > +	  && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
> > +	  && (compression_mode & MASK_MICROMIPS) == 0
> > +	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0),
> VOIDmode))
> > +	return false;
> 
> We're dealing here with branches from microMIPS to non-microMIPS, so
> shouldn't this be TARGET_INTERLINK_UNCOMPRESSED?
> 
> We need to use mips_get_compress_on_flags rather than
> mips_get_compress_mode for the second condition, because we can only
> assume that external functions are micromips if they have been explicitly
> tagged.
> 
> > +
> > +      /* Otherwise OK.  */
> > +      return true;
> > +    }
> > +
> 
> There's too much cut-&-paste of the MIPS16 code here, so that it becomes
> difficult to see what the logic actually is.  With the suggested change to fold -
> minterlink-nocompressed into -minterlink-compressed, the block above and:
> 
> >    /* We can't do a sibcall if the called function is a MIPS16 function
> >       because there is no direct "jx" instruction equivalent to "jalx" to
> >       switch the ISA mode.  We only care about cases where the sibling
> >       and normal calls would both be direct.  */
> >    if (decl
> > -      && mips_use_mips16_mode_p (decl)
> > +      && ((compression_mode & (MASK_MIPS16 | MASK_MICROMIPS)) !=
> 0)
> >        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
> >      return false;
> >
> > -  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
> > -     functions could be MIPS16 ones unless an attribute explicitly tells
> > +  /* When -minterlink-compressed is in effect, assume that non-locally-
> binding
> > +     functions could be MIPS16 or microMIPS unless an attribute
> > + explicitly tells
> >       us otherwise.  */
> > -  if (TARGET_INTERLINK_MIPS16
> > +  if (TARGET_INTERLINK_COMPRESSED
> >        && decl
> >        && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
> > -      && !mips_nomips16_decl_p (decl)
> > +      && (compression_mode & MASK_MICROMIPS) == 0
> > +      && (compression_mode & MASK_MIPS16) == 0
> >        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
> >      return false;
> 
> should be something like:
> 
>   /* Direct Js are only possible to functions that use the same ISA encoding.
>      There is no JX counterpart of JALX.  */
>   if (decl
>       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
>       && mips_call_may_need_jalx_p (decl))
>     return false;
> 
> with:
> 
> /* Return true if a call to DECL may need to use JALX.  */
> 
> static bool
> mips_call_may_need_jalx_p (decl)
> {
>   /* If the current translation unit would use a different mode for DECL,
>      assume that the call needs JALX.  */
>   if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
>     return true;
> 
>   /* mips_get_compress_mode is always accurate for locally-binding
>      functions in the current translation unit.  */
>   if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
>     return false;
> 
>   /* PLTs use the standard encoding, so calls that might go via PLTs
>      must use JALX.  */
>   if (TARGET_COMPRESSED
>       && TARGET_ABICALLS_PIC0
>       && DECL_EXTERNAL (decl)
>       && !targetm.binds_local_p (decl))
>     return true;
> 
>   /* When -minterlink-compressed is in effect, assume that functions
>      could use a different encoding mode unless an attribute explicitly
>      tells us otherwise.  */
>   if (TARGET_INTERLINK_COMPRESSED)
>     {
>       if (!TARGET_COMPRESSION && mips_get_compress_off_flags (decl) ==
> 0)
>         return true;
>       if (TARGET_COMPRESSION && mips_get_compress_on_flags (decl) == 0)
>         return true;
>     }
> 
>   return false;
> }
> 
> The TARGET_ABICALLS_PIC0 case should deal with the gnu-user.h comment
> above.
> 
> > @@ -7881,6 +8018,20 @@ mips_print_operand_punctuation (FILE *file, int
> ch
> >        fputs (reg_names[STACK_POINTER_REGNUM], file);
> >        break;
> >
> > +    case ':':
> > +      /* When reorder or noreorder with final_squence 0, the delay slot will
> > +	 be a nop, so we just use the compact version for microMIPS.  */
> > +      if (final_sequence == 0)
> > +	putc ('c', file);
> > +      break;
> > +
> > +    case '!':
> > +      /* When reorder or noreorder with final_squence 0, the delay slot will
> > +	 be a nop, so we just use the compact version for microMIPS.  */
> > +      if (final_sequence == 0)
> > +	putc ('s', file);
> > +      break;
> > +
> 
> Pasto: the second "the compact version" should be "16-bit delay slots".
> 
> > @@ -10198,7 +10349,7 @@ typedef void (*mips_save_restore_fn) (rtx,
> rtx);
> >     stack pointer.  */
> >
> >  static void
> > -mips_save_restore_reg (enum machine_mode mode, int regno,
> > +mips_save_restore_single_reg (enum machine_mode mode, int regno,
> >  		       HOST_WIDE_INT offset, mips_save_restore_fn fn)  {
> >    rtx mem;
> 
> Please reindent the second line, although I'd prefer not to have this change;
> more below.
> 
> > @@ -10208,6 +10359,23 @@ static void
> >    fn (gen_rtx_REG (mode, regno), mem);  }
> >
> > +static void
> > +mips_save_restore_registers (int start_reg, int end_reg, HOST_WIDE_INT
> *offset,
> > +			     mips_save_restore_fn fn, HOST_WIDE_INT
> sp_offset) {
> > +  int regno;
> > +
> > +  for (regno = start_reg; regno > end_reg; regno--)
> > +    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> > +      {
> > +        /* Record the ra offset for use by mips_function_profiler.  */
> > +        if (regno == RETURN_ADDR_REGNUM)
> > +          cfun->machine->frame.ra_fp_offset = *offset + sp_offset;
> > +	mips_save_restore_single_reg (word_mode, regno, *offset, fn);
> > +	*offset -= UNITS_PER_WORD;
> > +      }
> > +}
> > +
> 
> Function lacks a comment, although I'm not sure it's needed; see below.
> 
> > +static const unsigned int type[19] = { 0x00010000, 0x00030000, 0x00070000,
> > +				       0x000f0000, 0x001f0000, 0x003f0000,
> > +				       0x007f0000, 0x00ff0000, 0x40ff0000,
> > +				       0x80000000, 0x80010000, 0x80030000,
> > +				       0x80070000, 0x800f0000, 0x801f0000,
> > +				       0x803f0000, 0x807f0000, 0x80ff0000,
> > +				       0xc0ff0000 };
> > +
> > +static const unsigned int encode[19] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 16, 17,
> > +					 18, 19, 20, 21, 22, 23, 24, 25};
> 
> Please give these longer names, since they have file scope.  E.g.:
> 
> /* The masks of GPRs that can be saved by a microMIPS SWM and restored
>    by an LWM.  */
> static const unsigned int umips_swm_mask[19] = {
>   0x00010000, 0x00030000, 0x00070000, 0x000f0000,
>   0x001f0000, 0x003f0000, 0x007f0000, 0x00ff0000, 0x40ff0000,
>   0x80000000, 0x80010000, 0x80030000, 0x80070000, 0x800f0000,
>   0x801f0000, 0x803f0000, 0x807f0000, 0x80ff0000, 0xc0ff0000 };
> 
> /* umips_swm_encoding[I] is the instruction encoding used to represent
> mask
>    umips_swm_mask[I].  */
> static const unsigned int umips_swm_encoding[19] = {
>   1, 2, 3, 4,
>   5, 6, 7, 8, 9,
>   16, 17, 18, 19, 20,
>   21, 22, 23, 24, 25
> };
> 
> > +/* Build microMIPS save or restore.  FN is save or restore function.
> > +   OFFSET is the current stack offset.
> > +   Return true if we succeed creating save or restore.  */
> > +
> > +static bool
> > +umips_build_save_restore (mips_save_restore_fn fn,
> > +			  HOST_WIDE_INT offset, HOST_WIDE_INT sp_offset)
> 
> The comment doesn't say what SP_OFFSET is, although with the comments
> below I think the prototype should be:
> 
> /* Try to use a microMIPS LWM or SWM instruction to save or restore
>    as many GPRs in *MASK as possible.  *OFFSET is the offset from the
>    stack pointer of the topmost save slot.
> 
>    Remove from *MASK all registers that were handled using LWM and SWM.
>    Update *OFFSET so that it points to the first unused save slot.  */
> 
> static void
> umips_build_save_restore (mips_save_restore_fn fn, unsigned *mask
> 			  HOST_WIDE_INT *offset)
> 
> > +{
> > +  int i, num_of_reg;
> > +  unsigned int j;
> > +  rtx pattern, set, reg, mem;
> > +  HOST_WIDE_INT this_offset;
> > +  rtx this_base;
> > +
> > +  /* LWM/SWM can only support offsets from -2048 to 2047.  */  if
> > + (!UMIPS_12BIT_OFFSET_P (offset))
> > +    return false;
> 
> At this point OFFSET is still the offset of the top of the save area, whereas the
> instruction operand is the address of the first saved register.
> I think you need to check this later, after:
> 
>   offset -= (UNITS_PER_WORD * (num_of_reg - 1));
> 
> > +  if (i < 8 && (cfun->machine->frame.mask & 0xff000000))
> > +    mips_save_restore_registers (GP_REG_LAST, GP_REG_LAST - 8,
> > +				 &offset, fn, sp_offset);
> 
> Any reason for handling this differently from the MIPS16 code?  I prefer
> passing back a mask of the unhandled registers, like it does.  It would make
> this function a bit simpler and would also allow the function to be used in
> future with masks that don't exactly match.  E.g. if we need to save and
> restore registers $16-$20 + $23, we could use LWM for $16-$20 and LW for
> $23.  The prototype suggested above was for this.
> 
> > +  /* Adjust offset for output.  */
> > +  num_of_reg = (encode[i] & 0xf) + (encode[i] >> 4);  offset -=
> > + (UNITS_PER_WORD * (num_of_reg - 1));
> 
> Very minor, sorry, but s/num_of_reg/nregs/;
> 
> > +  /* Create the final PARALLEL.  */
> > +  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (num_of_reg));
> > +
> > +  this_base = stack_pointer_rtx;
> > +  this_offset = offset;
> > +
> > +  /* For $16-$23, $30.  */
> > +  for (j = 0; j < (encode[i] & 0xf); j++)
> > +    {
> > +      unsigned int regno;
> > +      long long offset = this_offset + j * UNITS_PER_WORD;
> 
> s/long long/HOST_WIDE_INT/.
> 
> > +  pattern = emit_insn (pattern);
> > +  if (fn == mips_save_reg)
> > +    RTX_FRAME_RELATED_P(pattern) = 1;
> 
> Missing space before "(".
> 
> > @@ -10253,16 +10555,13 @@ mips_for_each_saved_gpr_and_fpr
> (HOST_WIDE_INT sp_
> >       need a nop in the epilogue if at least one register is reloaded in
> >       addition to return address.  */
> >    offset = cfun->machine->frame.gp_sp_offset - sp_offset;
> > -  for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
> > -    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
> > -      {
> > -	/* Record the ra offset for use by mips_function_profiler.  */
> > -	if (regno == RETURN_ADDR_REGNUM)
> > -	  cfun->machine->frame.ra_fp_offset = offset + sp_offset;
> > -	mips_save_restore_reg (word_mode, regno, offset, fn);
> > -	offset -= UNITS_PER_WORD;
> > -      }
> >
> > +  if (!TARGET_MICROMIPS
> > +      || (TARGET_MICROMIPS
> > +          && !umips_build_save_restore (fn, offset, sp_offset)))
> > +    mips_save_restore_registers (GP_REG_LAST, GP_REG_FIRST,
> > +				 &offset, fn, sp_offset);
> > +
> 
> With the pass-back suggestion above, I think this should be:
> 
>   offset = cfun->machine->frame.gp_sp_offset - sp_offset;
>   mask = cfun->machine->frame.mask
>   if (TARET_MICROMIPS16)
>     umips_build_save_restore (fn, &mask, &offset);
>   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
>     if (BITSET_P (mask, regno - GP_REG_FIRST))
>       {
> 	/* Record the ra offset for use by mips_function_profiler.  */
> 	if (regno == RETURN_ADDR_REGNUM)
> 	  cfun->machine->frame.ra_fp_offset = offset + sp_offset;
> 	mips_save_restore_reg (word_mode, regno, offset, fn);
> 	offset -= UNITS_PER_WORD;
>       }
> 
> > @@ -11078,6 +11357,7 @@ mips_deallocate_stack (rtx base, rtx offset,
> HOST_
> >      return;
> >
> >    mips_frame_barrier ();
> > +
> >    if (offset == const0_rtx)
> >      {
> >        emit_move_insn (stack_pointer_rtx, base); @@ -11196,9 +11476,9
> > @@ mips_expand_epilogue (bool sibcall_p)
> >   	if (BITSET_P (mask, regno - GP_REG_FIRST))
> >   	  {
> >   	    offset -= UNITS_PER_WORD;
> > - 	    mips_save_restore_reg (word_mode, regno, offset,
> mips_restore_reg);
> > + 	    mips_save_restore_single_reg (word_mode, regno,
> > +                                          offset, mips_restore_reg);
> >   	  }
> > -
> >        /* Restore the remaining registers and deallocate the final bit
> >  	 of the frame.  */
> >        mips_frame_barrier ();
> > @@ -11211,7 +11491,6 @@ mips_expand_epilogue (bool sibcall_p)
> >        mips_for_each_saved_acc (frame->total_size - step2,
> mips_restore_reg);
> >        mips_for_each_saved_gpr_and_fpr (frame->total_size - step2,
> >  				       mips_restore_reg);
> > -
> >        if (cfun->machine->interrupt_handler_p)
> >  	{
> >  	  HOST_WIDE_INT offset;
> 
> Please leave out these whitespace changes.  I'd also prefer not to add the
> _single_reg suffix to mips_save_restore_reg.
> 
> > @@ -11254,7 +11533,6 @@ mips_expand_epilogue (bool sibcall_p)
> >  	/* Deallocate the final bit of the frame.  */
> >  	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
> >      }
> > -  gcc_assert (!mips_epilogue.cfa_restores);
> >
> >    /* Add in the __builtin_eh_return stack adjustment.  We need to
> 
> Please don't remove the assert.  AIUI this was for epilogues that use
> JRADDIUSP, which isn't part of the initial patch.
> 
> > @@ -16211,17 +16489,19 @@ mips_output_mi_thunk (FILE *file, tree
> thunk_fndec
> >    reload_completed = 0;
> >  }
> >  

> > -/* The last argument passed to mips_set_mips16_mode, or negative if the
> > -   function hasn't been called yet.  */
> > +/* The last argument passed to mips_set_mips16_micromips_mode,
> > +   or negative if the function hasn't been called yet.  */
> >  static int was_mips16_p = -1;
> > +static int was_micromips_p = -1;
> >
> >  /* Set up the target-dependent global state so that it matches the
> >     current function's ISA mode.  */
> >
> >  static void
> > -mips_set_mips16_mode (int mips16_p)
> > +mips_set_mips16_micromips_mode (int mips16_p, int micromips_p)
> >  {
> > -  if (mips16_p == was_mips16_p)
> > +  if (mips16_p == was_mips16_p
> > +      && micromips_p == was_micromips_p)
> >      return;
> >
> >    /* Restore base settings of various flags.  */
> 
> Now that we represent the mode using masks of MASK_MIPS16 and
> MASK_MICROMIPS, I think it would be better to have a mask rather than
> two booleans here too.
> I.e.:
> 
> /* The last argument passed to mips_set_mips16_micromips_mode,
>    or negative if the function hasn't been called yet.  */ static unsigned int
> old_compression_mode = -1;
> 
> /* Set up the target-dependent global state for ISA mode
> COMPRESSION_MODE,
>    which is either MASK_MIPS16 or MASK_MICROMIPS.  */
> 
> static void
> mips_set_compression_mode (unsigned int compression_mode)
> 
> > @@ -16290,6 +16570,18 @@ static void
> >        /* Switch to normal (non-MIPS16) mode.  */
> >        target_flags &= ~MASK_MIPS16;
> >
> > +      if (micromips_p)
> > +	{
> > +	  /* Switch to microMIPS mode.  */
> > +	  target_flags |= MASK_MICROMIPS;
> > +
> > +	  /* Avoid branch likely.  */
> > +	  target_flags &= ~MASK_BRANCHLIKELY;
> > +	}
> > +      else
> > +	/* Switch to normal (non-microMIPS) mode.  */
> > +	target_flags &= ~MASK_MICROMIPS;
> > +
> 
> With the change above, I think we should have:
> 
>   target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
>   target_flags |= compression_mode;
> 
> outside of the "if" statement, with the code above becoming:
> 
>     /* There are no microMIPS branch-likely instructions.  */
>     if (TARGET_MICROMIPS)
>       target_flags &= ~MASK_BRANCHLIKELY;
> 
> > +  /* Save the base compression state and process flags as though we
> > +     are generating uncompressed code.  */  if (TARGET_MIPS16)
> > +    mips_base_compression_flags |= MASK_MIPS16;  if
> > + (TARGET_MICROMIPS)
> > +    mips_base_compression_flags |= MASK_MICROMIPS;
> > +
> > +  target_flags &= ~MASK_MIPS16;
> > +  target_flags &= ~MASK_MICROMIPS;
> 
> Would prefer:
> 
>   mips_base_compression_flags = TARGET_COMPRESSION;
>   target_flags &= ~TARGET_COMPRESSION;
> 
> > @@ -17088,6 +17397,316 @@ mips_mulsidi3_gen_fn (enum rtx_code
> ext_code)
> >        return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
> >      }
> >  }
> > +
> > +
> > +/* Return true if PATTERN matches the kind of instruction generated by
> > +   micromips_build_save_restore.  SAVE_P is true for store.  */
> 
> umips_build_save_restore
> 
> > +
> > +bool
> > +umips_save_restore_pattern_p (bool save_p, rtx pattern) {
> > +  int n;
> > +  HOST_WIDE_INT first_offset = 0;
> > +  rtx first_base = 0;
> > +  unsigned int first_regno = 0;
> > +
> > +  for (n = 0; n < XVECLEN (pattern, 0); n++)
> > +    {
> > +      rtx set, reg, mem, this_base;
> > +      HOST_WIDE_INT this_offset;
> > +      unsigned int this_regno;
> > +
> > +      /* Check that we have a SET.  */
> > +      set = XVECEXP (pattern, 0, n);
> > +      if (GET_CODE (set) != SET)
> > +	return false;
> > +
> > +      /* Check that the SET is a load (if restoring) or a store
> > +	 (if saving).  */
> > +      mem = save_p ? SET_DEST (set) : SET_SRC (set);
> > +      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
> > +	return false;
> > +
> > +      /* Check that the address is the sum of base and a possibly-zero
> > +	 constant offset.  Determine if the offset is in range.  */
> > +      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
> > +      if (!REG_P (this_base)
> > +	  && UMIPS_12BIT_OFFSET_P (this_offset))
> > +	return false;
> > +
> > +      if (n == 0)
> > +	{
> > +	  first_base = this_base;
> > +	  first_offset = this_offset;
> > +	}
> 
> The UMIPS_12BIT_OFFSET_P check should be in the "n == 0" arm.
> 
> > +      else
> > +	{
> > +	  /* Check if this_base is the same as first_base.  */
> > +	  if (REGNO (this_base) != REGNO (first_base))
> > +	    return false;
> > +
> > +	  /* Check if this_offset is first_offset + UNITS_PER_WORD * n.  */
> > +	  if (this_offset != first_offset + UNITS_PER_WORD * n)
> > +	    return false;
> 
>       /* Check that the save slots are consecutive.  */
>       if (REGNO (this_base) != REGNO (first_base)
> 	  || this_offset != first_offset + UNITS_PER_WORD * n)
> 
> > +      /* Make sure the order of regno is "$16-$23, $30, $31", "$16-$23, $30",
> > +	 or "$31".  */
> > +      this_regno = REGNO (reg);
> > +      if (n == 0)
> > +	{
> > +	  if (this_regno != 16 && this_regno != 31)
> > +	    return false;
> > +	  first_regno = this_regno;
> > +	}
> > +      else if (n == 8) /* For s8.  */
> > +	{
> > +	  if (n == XVECLEN (pattern, 0) - 1)
> > +	    {
> > +	      if (this_regno != 30 && this_regno != 31)
> > +		return false;
> > +	    }
> > +	  else
> > +	    {
> > +	      if (this_regno != 30)
> > +		return false;
> > +	    }
> > +	}
> > +      else if (n != XVECLEN (pattern, 0) - 1)
> > +	{
> > +	  if (this_regno != first_regno + n)
> > +	    return false;
> > +	}
> > +      else /* The last item.  */
> > +	{
> > +	  if ((this_regno != first_regno + n) && this_regno != 31)
> > +	    return false;
> > +	}
> > +    }
> 
> Please instead check that the registers are in ascending order, build a mask,
> and then check that mask against umips_swm_mask at the end.
> 
> > +}
> > +/* Return true if MEM1 and MEM2 use the same base register, and the
> 
> Missing space between functions.
> 
> > +   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
> > +   register into (from) which the contents of MEM1 will be loaded
> > +   (stored), depending on the value of LOAD_P.
> > +   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
> > +
> > +static bool
> > +umips_load_store_pair_p_1 (bool load_p, bool swap_p, rtx first_reg,
> > +			   rtx mem1, rtx mem2)
> > +{
> > +  rtx base1, base2;
> > +  HOST_WIDE_INT offset1, offset2;
> > +
> > +  if (!MEM_P (mem1) || !MEM_P (mem2))
> > +    return false;
> > +
> > +  /* Make sure memory is base plus offset.  */  if (GET_CODE (XEXP
> > + (mem1, 0)) != PLUS
> > +      || GET_CODE (XEXP (mem2, 0)) != PLUS
> > +      || GET_CODE (XEXP (XEXP (mem1, 0), 1)) != CONST_INT
> > +      || GET_CODE (XEXP (XEXP (mem2, 0), 1)) != CONST_INT)
> > +    return false;
> > +
> > +  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
> > + mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
> 
> Please remove the:
> 
>   /* Make sure memory is base plus offset.  */
>   if (GET_CODE (XEXP (mem1, 0)) != PLUS
>       || GET_CODE (XEXP (mem2, 0)) != PLUS
>       || GET_CODE (XEXP (XEXP (mem1, 0), 1)) != CONST_INT
>       || GET_CODE (XEXP (XEXP (mem2, 0), 1)) != CONST_INT)
>     return false;
> 
> part.  The point of using mips_split_plus is that we want to handle
> (reg) paired with (plus (reg) (const_int 4)) and (plus (reg) (const_int -4))
> paired with (reg).
> 
> > +  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
> > +    return false;
> > +
> > +  /* Avoid invalid load pair instructions.  */  if (load_p && REGNO
> > + (first_reg) == REGNO (base1))
> > +    return false;
> > +
> > +  /* We must avoid this case for anti-dependence.
> > +     Ex:  lw $3, 4($3)
> > +          lw $2, 0($3)
> > +     first_reg is $2, but the base is $3.  */  if (load_p && swap_p
> > + && (REGNO (first_reg) + 1) == REGNO (base1))
> > +    return false;
> 
> Redundant brackets around "REGNO (first_reg) + 1".
> 
> > +
> > +  if (swap_p
> > +      && offset2 + 4 != offset1)
> > +    return false;
> > +
> > +  if (offset1 + 4 != offset2)
> > +    return false;
> 
> This always returns false for swap_p.  Please add tests for both cases to
> make sure that the code is triggering.  E.g. you could have an inline asm that
> takes two asm register variables, one in $2 and one in $3.
> 
> > +bool
> > +umips_load_store_pair_p (bool load_p, rtx *operands)
> 
> Function needs a comment.
> 
> > +{
> > +  rtx reg1, reg2, mem1, mem2;
> > +
> > +  if (load_p)
> > +    {
> > +      reg1 = operands[0];
> > +      reg2 = operands[2];
> > +      mem1 = operands[1];
> > +      mem2 = operands[3];
> > +    }
> > +  else
> > +    {
> > +      reg1 = operands[1];
> > +      reg2 = operands[3];
> > +      mem1 = operands[0];
> > +      mem2 = operands[2];
> > +    }
> > +
> > +  if (REGNO (reg2) == REGNO (reg1) + 1)
> > +      return umips_load_store_pair_p_1 (load_p, false, reg1, mem1,
> > + mem2);
> > +
> > +  else if (REGNO (reg1) == REGNO (reg2) + 1)
> > +      return umips_load_store_pair_p_1 (load_p, true, reg2, mem1,
> > + mem2);
> > +
> > +  return false;
> 
> Excess indentation.  Probably better without the "else", since this is really
> early-exit style.
> 
> > +/* Return the assembly instruction for microMIPS lwp or swp.
> > +   LOAD_P is true for load.  */
> > +
> > +static void
> > +umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem) {
> > +  HOST_WIDE_INT offset;
> > +  rtx base, local_ops[3];
> > +
> > +  gcc_assert (REG_P (reg) && MEM_P (mem));
> > +
> > +  mips_split_plus (XEXP (mem, 0), &base, &offset);  gcc_assert (REG_P
> > + (base));
> > +
> > +  local_ops[0] = reg;
> > +  local_ops[1] = gen_rtx_CONST_INT (Pmode, offset);
> > +  local_ops[2] = base;
> > +  if (load_p)
> > +    output_asm_insn ("lwp %0,%1(%2)", local_ops);
> > +  else
> > +    output_asm_insn ("swp %0,%1(%2)", local_ops); }
> 
> This ought to be equivalent to:
> 
>   rtx ops[] = { reg, mem };
> 
>   if (load_p)
>     output_asm_insn ("lwp %0,%1", ops);
>   else
>     output_asm_insn ("swp %0,%1", ops);
> 
> > +/* Return true if reg1 and reg2 can be target of movep.  */
> > +
> > +bool
> > +umips_movep_target_p (rtx reg1, rtx reg2) {
> > +  int regno1, regno2, pair;
> > +  unsigned int i;
> > +  static const int match[8] = {0x00000060,	/* 5, 6 */
> > +			       0x000000a0,	/* 5, 7 */
> > +			       0x000000c0,	/* 6, 7 */
> > +			       0x00200010,	/* 4, 21 */
> > +			       0x00400010,	/* 4, 22 */
> > +			       0x00000030,	/* 4, 5 */
> > +			       0x00000050,	/* 4, 6 */
> > +			       0x00000090};	/* 4, 7 */
> 
> Should be formatted as:
> 
>   static const int match[8] = {
>     0x00000060,	/* 5, 6 */
>     ...
>   };
> 
> > +  for (i = 0; i < ARRAY_SIZE (match); i++)
> > +    {
> > +      if (pair == match[i])
> > +	return true;
> > +    }
> 
> Redundant { ... }.
> 
> > @@ -2452,18 +2459,48 @@ typedef struct mips_args {
> >     all calls should use assembly macros.  Otherwise, all indirect
> >     calls should use "jr" or "jalr"; we will arrange to restore $gp
> >     afterwards if necessary.  Finally, we can only generate direct
> > -   calls for -mabicalls by temporarily switching to non-PIC mode.  */
> > +   calls for -mabicalls by temporarily switching to non-PIC mode.
> > +
> > +   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
> > +   instruction is in the delay slot of jal(r).  */
> >  #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
> > +  (TARGET_MICROMIPS						\
> > +   ? (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS
> 	\
> > +      ? (TARGET_INTERLINK_UNCOMPRESSED				\
> > +	 ? "%*" INSN "%!\t%" #TARGET_OPNO "%/"			\
> > +	 : "%*" INSN "\t%" #TARGET_OPNO "%/")			\
> 
> Is this special case really necessary?  Normally when using assembly macros
> we should leave the choice up to the assembler.  On the one hand we gain
> by having knowledge that the target is microMIPS, while on the other we
> lose because the assembler can't fill the delay slot with a 32-bit instruction
> from a preceding assembly macro.
> 
> Hopefully no-one really uses -mno-explicit-relocs these days anyway, so I
> think this case should be handled in the same way for all modes.
> 
> I.e.:
> 
>   TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
>   ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
>   : REG_P (OPERANDS[TARGET_OPNO])				\
>   ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)		\
>      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
>         "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
>      : TARGET_MICROMIPS && TARGET_INTERLINK_UNCOMPRESSED        \
>      ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"			\
>      : "%*" INSN "r\t%" #TARGET_OPNO "%/")			\
>   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/")))
> 
> if that works.
> 
> > +

> > +/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
> > +   "jrc" when nop is in the delay slot of "jr".  */
> > +#define MICROMIPS_J(OPERANDS, OPNO)				\
> >    (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
> > -   ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
> > -   : (REG_P (OPERANDS[TARGET_OPNO])				\
> > -      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
> > -   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
> > -      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
> > -   : REG_P (OPERANDS[TARGET_OPNO])				\
> > -   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"				\
> > -   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
> > -

> > +   ? "%*j\t%" #OPNO "%/"					\
> > +   : REG_P (OPERANDS[OPNO])					\
> > +   ? "%*jr%:\t%" #OPNO						\
> > +   : TARGET_ABICALLS && flag_pic				\
> > +   ? (".option\tpic0\n\t"					\
> > +      "%*j\t%" #OPNO "%/\n\t"					\
> > +      ".option\tpic2")						\
> > +   : "%*j\t%" #OPNO "%/")
> 
> Looks like the last bit could/should use MIPS_ABSOLUTE_JUMP.
> 
> > @@ -2923,3 +2960,5 @@ extern GTY(()) struct target_globals
> *mips16_globa
> >     with arguments ARGS.  */
> >  #define PMODE_INSN(NAME, ARGS) \
> >    (Pmode == SImode ? NAME ## _si ARGS : NAME ## _di ARGS)
> > +
> > +#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048,
> 2047))
> 
> Please put this after #define LUI_INT, to keep the range checks together.
> 
> Thanks,
> Richard

[-- Attachment #2: gcc.cl --]
[-- Type: application/octet-stream, Size: 5712 bytes --]

2013-02-12  Catherine Moore  <clm@codesourcery.com>
	    Maciej W. Rozycki  <macro@codesourcery.com>
	    Tom de Vries  <tom@codesourcery.com>
	    Nathan Sidwell <nathan@codesourcery.com>
	    Iain Sandoe  <iain@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>
	    Chao-ying Fu <fu@mips.com>

	* doc/extend.texi: (micromips, nomicromips, nocompression):
	Document new function attributes. 
	* doc/invoke.texi (minterlink-compressed, mmicromips,
	minterlink-uncompressed, m14k, m14ke, m14kec): Document new
	options.
	(minterlink-mips16): Update documentation.
	* doc/md.texi (ZC, ZD): Document new constraints.
	* configure.ac (gcc_cv_as_micromis): Check if linker
	supports the .set micromips directive.
	* configure: Regenerate.
	* config.in: Regenerate.
	* config/mips/mips-tables.opt: Regenerate.
	* config/mips/gnu-user.h (SUBTARGET_OVERRIDE_OPTIONS): Set
	TARGET_INTERLINK_COMPRESSED.
	* config/mips/micromips.md: New file.
	* constraints.md (ZC, AD): New constraints.
	* config/mips/predicates.md (movep_src_register): New predicate.
	(movep_src_operand): New predicate.
	(non_volatile_mem_operand): New predicate.
	* config/mips/mips.md (multimem): New type.
	(length): Differentiate between 17-bit and 18-bit branch offsets.
	(MOVEP1, MOVEP2): New mode iterator.
 	(mov_<load>l): Use ZC constraint.
	(mov_<load>r): Likewise.
	(mov_<store>l): Likewise.
	(mov_<store>r): Likewise.
	(*branch_equality<mode>_micromips): New insn.
	(*branch_equality<mode>_inverted_micromips): New insn.
	(*branch_equality<mode>_inverted): Disable for microMIPS.
	(*branch_equality<mode>): Likewise.
	(*jump_absolute): microMIPS variant.
	(indirect_jump_<mode>): Likewise.
	(tablejump_<mode>): Likewise.
	(<optab>_internal): Likewise.
	(sibcall_internal): Likewise.
	(sibcall_value_internal): Likewise.
	(prefetch): Use constraint ZD.
	* config/mips/mips.opt (minterlink-compressed): New option.
	(minterlink-uncompressed): New option.
	(minterlink-mips16): Now an alias for minterlink-compressed.
	(mmicromips): New option.
	* config/mips/sync.md (sync_compare_and_swap<mode>): Use ZR constraint.
	(compare_and_swap_12): Likewise.
	(sync_add<mode>): Likewise.
	(sync_<optab>_12): Likewise.
	(sync_old_<optab>_12): Likewise.
	(sync_new_<optab>_12): Likewise.
	(sync_nand_12): Likewise.
	(sync_old_nand_12): Likewise.
	(sync_new_nand_12): Likewise.
	(sync_sub<mode>): Likewise.
	(sync_old_add<mode>): Likewise.
	(sync_old_sub<mode>): Likewise.
	(sync_new_add<mode>): Likewise.
	(sync_new_sub<mode>): Likewise.
	(sync_<optab><mode>): Likewise.
	(sync_old_<optab><mode>): Likewise.
	(sync_new_<optab><mode>): Likewise.
	(sync_nand<mode>): Likewise.
	(sync_old_nand<mode>): Likewise.
	(sync_new_nand<mode>): Likewise.
	(sync_lock_test_and_set<mode>): Likewise.
	(test_and_set_12): Likewise.
	(atomic_compare_and_swap<mode>): Likewise.
	(atomic_exchange<mode>_llsc): Likewise.
	(atomic_fetch_add<mode>_llsc): Likewise.
	* config/mips/mips-cpus.def (m14kc, m14k): New processors.
	* config/mips/mips-protos.h (umips_output_save_restore): New prototype.
	(umips_save_restore_pattern_p): Likewise.
	(umips_load_store_pair_p): Likewise.
	(umips_output_load_store_pair): Likewise.
	(umips_movep_target_p): Likewise.
	(umips_12bit_offset_address_p): Likewise.
	* config/mips/mips.c (MIPS_MAX_FIRST_STEP): Update for microMIPS.
	(mips_base_mips16): Rename this...
	(mips_base_compression_flags): ...to this. Update all uses.
	(mips_attribute_table): Add micromips, nomicromips and nocompression.
	(mips_mips16_decl_p): Delete.
	(mips_nomips16_decl_p): Delete.
 	(mips_get_compress_on_flags): New function.
	(mips_get_compress_off_flags): New function.
	(mips_get_compress_mode): New function.
	(mips_get_compress_on_name): New function.
	(mips_get_compress_off_name): New function.
	(mips_get_compression_attrs): New function.
	(mips_get_nocompression_attrs): New function.
	(mips_insert_attributes): Support multiple compression types.
	(mips_merge_decl_attributes): Likewise.
	(umips_12bit_offset_address_p): New function.
	(mips_start_function_definition): Emit .set micromips directive.
	(mips_call_may_need_jalx_p): New function.
	(mips_function_ok_for_sibcall): Add microMIPS support.
	(mips_print_operand_punctuation): Support short delay slots and
	compact jumps.
	(umips_swm_mask, umips_swm_encoding): New.
	(umips_build_save_restore): New function.
	(mips_for_each_saved_gpr_and_fpr): Add microMIPS support.
	(was_mips16_p): Remove.
	(old_compression_mode): New.
	(mips_set_compression_mode): New function.
	(mips_set_current_function): Add microMIPS support.
	(mips_option_override): Likewise.
	(umips_save_restore_pattern_p): New function.
	(umips_output_save_restore): New function.
	(umips_load_store_pair_p_1): New function.
	(umips_load_store_pair_p): New function.
	(umips_output_load_store_pair_1): New function.
	(umips_output_load_store_pair): New function.
	(umips_movep_target_p) New function.
	(mips_prepare_pch_save): Add microMIPS support.
	* config/mips/mips.h (TARGET_COMPRESSION): New.
	(TARGET_CPU_CPP_BUILTINS): Update macro
	to use new compression flags and to support microMIPS.
	(MIPS_ISA_LEVEL_SPEC): Add m14k processors.
	(MIPS_ARCH_FLOAT_SPEC): Likewise.
	(ISA_HAS_LWXS): Include TARGET_MICROMIPS.
	(ASM_SPEC): Support mmicromips and mno-micromips.
	(M16STORE_REG_P): New macro.
	(MIPS_CALL): Support TARGET_MICROMIPS.
	(MICROMIPS_J): New macro.
	(mips_base_mips16): Rename this...
	(mips_base_compression_flags): ...to this.
	(UMIPS_12BIT_OFFSET_P): New macro.
	* config/mips/t-sde: (MULTILIB_OPTIONS): Add microMIPS.
	(MULTILIB_DIRNAMES): Likewise.

[-- Attachment #3: gcc.patch --]
[-- Type: application/octet-stream, Size: 91330 bytes --]

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 195900)
+++ doc/extend.texi	(working copy)
@@ -3053,6 +3053,25 @@
 may interact badly with some GCC extensions such as @code{__builtin_apply}
 (@pxref{Constructing Calls}).
 
+@item micromips/nomicromips
+@cindex @code{micromips} attribute
+@cindex @code{nomicromips} attribute
+
+On MIPS targets, you can use the @code{micromips} and @code{nomicromips}
+function attributes to locally select or turn off microMIPS code generation.
+A function with the @code{micromips} attribute is emitted as microMIPS code,
+while microMIPS code generation is disabled for functions with the
+@code{nomicromips} attribute.  These attributes override the
+@option{-mmicromips} and @option{-mno-micromips} options on the command line
+(@pxref{MIPS Options}).
+
+When compiling files containing mixed microMIPS and non-microMIPS code, the
+preprocessor symbol @code{__mips_micromips} reflects the setting on the
+command line,
+not that within individual functions.  Mixed microMIPS and non-microMIPS code
+may interact badly with some GCC extensions such as @code{__builtin_apply}
+(@pxref{Constructing Calls}).
+
 @item model (@var{model-name})
 @cindex function addressability on the M32R/D
 @cindex variable addressability on the IA-64
@@ -3155,6 +3174,13 @@
 exit sequences suitable for use in an NMI handler when this
 attribute is present.
 
+@item nocompression
+@cindex @code{nocompression} attribute
+On MIPS targets, you can use the @code{nocompression} function attribute
+to locally turn off MIPS16 and microMIPS code generation.  This attribute
+overrides the @option{-mips16} and @option{-mmicromips} options on the
+command line (@pxref{MIPS Options}).
+
 @item no_instrument_function
 @cindex @code{no_instrument_function} function attribute
 @opindex finstrument-functions
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 195900)
+++ doc/invoke.texi	(working copy)
@@ -740,6 +740,8 @@
 -mips1  -mips2  -mips3  -mips4  -mips32  -mips32r2 @gol
 -mips64  -mips64r2 @gol
 -mips16  -mno-mips16  -mflip-mips16 @gol
+-minterlink-compressed -mno-interlink-compressed @gol
+-minterlink-uncompressed -mno-interlink-uncompressed @gol
 -minterlink-mips16  -mno-interlink-mips16 @gol
 -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
@@ -747,6 +749,7 @@
 -mno-float -msingle-float  -mdouble-float  @gol
 -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -mmcu -mmno-mcu @gol
+-mmicromips -mno-micromips @gol
 -mfpu=@var{fpu-type} @gol
 -msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
@@ -15880,6 +15883,7 @@
 @samp{1004kc}, @samp{1004kf2_1}, @samp{1004kf1_1},
 @samp{loongson2e}, @samp{loongson2f}, @samp{loongson3a},
 @samp{m4k},
+@samp{m14k}, @samp{m14ke}, @samp{m14kec},
 @samp{octeon}, @samp{octeon+}, @samp{octeon2},
 @samp{orion},
 @samp{r2000}, @samp{r3000}, @samp{r3900}, @samp{r4000}, @samp{r4400},
@@ -15993,18 +15997,30 @@
 for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
 not intended for ordinary use in compiling user code.
 
+@item -minterlink-compressed
+@item -mno-interlink-compressed
+@item -minterlink-uncompressed
+@item -mno-interlink-uncompressed
+@opindex minterlink-compressed
+@opindex mno-interlink-compressed
+@opindex minterlink-compressed
+@opindex mno-interlink-compressed
+Require (do not require) that code using the standard (uncompressed) MIPS ISA
+be link-compatible with MIPS16 and microMIPS code, and vice versa.
+
+For example, code using the standard ISA encoding cannot jump directly
+to MIPS16 or microMIPS code; it must either use a call or an indirect jump.
+@option{-minterlink-compressed} therefore disables direct jumps unless GCC
+knows that the target of the jump is not compressed.
+
 @item -minterlink-mips16
 @itemx -mno-interlink-mips16
 @opindex minterlink-mips16
 @opindex mno-interlink-mips16
-Require (do not require) that non-MIPS16 code be link-compatible with
-MIPS16 code.
+Aliases of @option{-minterlink-compressed} and
+@option{-mno-interlink-compressed}.  These options predate the microMIPS ASE
+and are retained for backwards compatiblity.
 
-For example, non-MIPS16 code cannot jump directly to MIPS16 code;
-it must either use a call or an indirect jump.  @option{-minterlink-mips16}
-therefore disables direct jumps unless GCC knows that the target of the
-jump is not MIPS16.
-
 @item -mabi=32
 @itemx -mabi=o64
 @itemx -mabi=n32
@@ -16218,6 +16234,16 @@
 Use (do not use) the MIPS-3D ASE@.  @xref{MIPS-3D Built-in Functions}.
 The option @option{-mips3d} implies @option{-mpaired-single}.
 
+@item -mmicromips
+@itemx -mno-micromips
+@opindex mmicromips
+@opindex mno-mmicromips
+Generate (do not generate) microMIPS code.
+
+MicroMIPS code generation can also be controlled on a per-function basis
+by means of @code{micromips} and @code{nomicromips} attributes.
+@xref{Function Attributes}, for more information.
+
 @item -mmt
 @itemx -mno-mt
 @opindex mmt
Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 195900)
+++ doc/md.texi	(working copy)
@@ -2916,6 +2916,19 @@
 
 @item R
 An address that can be used in a non-macro load or store.
+
+@item ZC
+When compiling microMIPS code, this constraing matches a memory operand
+whose address is formed from a base register and a 12-bit offset.  These
+operands can be used for microMIPS instructions such as @code{ll} and
+@code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+equivalent to @code{R}.
+
+@item ZD
+When compiling microMIPS code, this constraint matches an address operand
+that is formed from a base register and a 12-bit offset.  These operands
+can be used for microMIPS instructions such as @code{prefetch}.  When
+not compiling for microMIPS code, @code{YC} is equivalent to @code{p}.
 @end table
 
 @item Motorola 680x0---@file{config/m68k/constraints.md}
Index: configure
===================================================================
--- configure	(revision 195900)
+++ configure	(working copy)
@@ -25708,6 +25708,37 @@
 
 fi
 
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .micromips support" >&5
+$as_echo_n "checking assembler for .micromips support... " >&6; }
+if test "${gcc_cv_as_micromips_support+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_micromips_support=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '.set micromips' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_micromips_support=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_micromips_support" >&5
+$as_echo "$gcc_cv_as_micromips_support" >&6; }
+if test $gcc_cv_as_micromips_support = yes; then
+
+$as_echo "#define HAVE_GAS_MICROMIPS 1" >>confdefs.h
+
+fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .dtprelword support" >&5
 $as_echo_n "checking assembler for .dtprelword support... " >&6; }
 if test "${gcc_cv_as_mips_dtprelword+set}" = set; then :
Index: config.in
===================================================================
--- config.in	(revision 195900)
+++ config.in	(working copy)
@@ -1034,6 +1034,12 @@
 #endif
 
 
+/* Define if your assembler supports the .set micromips directive */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GAS_MICROMIPS
+#endif
+
+
 /* Define if your assembler supports .nsubspa comdat option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GAS_NSUBSPA_COMDAT
Index: configure.ac
===================================================================
--- configure.ac	(revision 195900)
+++ configure.ac	(working copy)
@@ -4036,6 +4036,12 @@
       [AC_DEFINE(HAVE_AS_GNU_ATTRIBUTE, 1,
 	  [Define if your assembler supports .gnu_attribute.])])
 
+    gcc_GAS_CHECK_FEATURE([.micromips support],
+      gcc_cv_as_micromips_support,,,
+      [.set micromips],,
+      [AC_DEFINE(HAVE_GAS_MICROMIPS, 1,
+          [Define if your assembler supports the .set micromips directive])])
+
     gcc_GAS_CHECK_FEATURE([.dtprelword support],
       gcc_cv_as_mips_dtprelword, [2,18,0],,
       [.section .tdata,"awT",@progbits
Index: config/mips/mips-tables.opt
===================================================================
--- config/mips/mips-tables.opt	(revision 195900)
+++ config/mips/mips-tables.opt	(working copy)
@@ -373,254 +373,260 @@
 Enum(mips_arch_opt_value) String(m4k) Value(39) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kec) Value(40) Canonical
+Enum(mips_arch_opt_value) String(m14kc) Value(40) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kec) Value(40)
+Enum(mips_arch_opt_value) String(m14k) Value(41) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kem) Value(41) Canonical
+Enum(mips_arch_opt_value) String(4kec) Value(42) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kem) Value(41)
+Enum(mips_arch_opt_value) String(r4kec) Value(42)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kep) Value(42) Canonical
+Enum(mips_arch_opt_value) String(4kem) Value(43) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kep) Value(42)
+Enum(mips_arch_opt_value) String(r4kem) Value(43)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4ksd) Value(43) Canonical
+Enum(mips_arch_opt_value) String(4kep) Value(44) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4ksd) Value(43)
+Enum(mips_arch_opt_value) String(r4kep) Value(44)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kc) Value(44) Canonical
+Enum(mips_arch_opt_value) String(4ksd) Value(45) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kc) Value(44)
+Enum(mips_arch_opt_value) String(r4ksd) Value(45)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf2_1) Value(45) Canonical
+Enum(mips_arch_opt_value) String(24kc) Value(46) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf2_1) Value(45)
+Enum(mips_arch_opt_value) String(r24kc) Value(46)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf) Value(46) Canonical
+Enum(mips_arch_opt_value) String(24kf2_1) Value(47) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf) Value(46)
+Enum(mips_arch_opt_value) String(r24kf2_1) Value(47)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf1_1) Value(47) Canonical
+Enum(mips_arch_opt_value) String(24kf) Value(48) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf1_1) Value(47)
+Enum(mips_arch_opt_value) String(r24kf) Value(48)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kfx) Value(48) Canonical
+Enum(mips_arch_opt_value) String(24kf1_1) Value(49) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kfx) Value(48)
+Enum(mips_arch_opt_value) String(r24kf1_1) Value(49)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kx) Value(49) Canonical
+Enum(mips_arch_opt_value) String(24kfx) Value(50) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kx) Value(49)
+Enum(mips_arch_opt_value) String(r24kfx) Value(50)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kec) Value(50) Canonical
+Enum(mips_arch_opt_value) String(24kx) Value(51) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kec) Value(50)
+Enum(mips_arch_opt_value) String(r24kx) Value(51)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef2_1) Value(51) Canonical
+Enum(mips_arch_opt_value) String(24kec) Value(52) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef2_1) Value(51)
+Enum(mips_arch_opt_value) String(r24kec) Value(52)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef) Value(52) Canonical
+Enum(mips_arch_opt_value) String(24kef2_1) Value(53) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef) Value(52)
+Enum(mips_arch_opt_value) String(r24kef2_1) Value(53)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef1_1) Value(53) Canonical
+Enum(mips_arch_opt_value) String(24kef) Value(54) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef1_1) Value(53)
+Enum(mips_arch_opt_value) String(r24kef) Value(54)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kefx) Value(54) Canonical
+Enum(mips_arch_opt_value) String(24kef1_1) Value(55) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kefx) Value(54)
+Enum(mips_arch_opt_value) String(r24kef1_1) Value(55)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kex) Value(55) Canonical
+Enum(mips_arch_opt_value) String(24kefx) Value(56) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kex) Value(55)
+Enum(mips_arch_opt_value) String(r24kefx) Value(56)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kc) Value(56) Canonical
+Enum(mips_arch_opt_value) String(24kex) Value(57) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kc) Value(56)
+Enum(mips_arch_opt_value) String(r24kex) Value(57)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf2_1) Value(57) Canonical
+Enum(mips_arch_opt_value) String(34kc) Value(58) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf2_1) Value(57)
+Enum(mips_arch_opt_value) String(r34kc) Value(58)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf) Value(58) Canonical
+Enum(mips_arch_opt_value) String(34kf2_1) Value(59) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf) Value(58)
+Enum(mips_arch_opt_value) String(r34kf2_1) Value(59)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf1_1) Value(59) Canonical
+Enum(mips_arch_opt_value) String(34kf) Value(60) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf1_1) Value(59)
+Enum(mips_arch_opt_value) String(r34kf) Value(60)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kfx) Value(60) Canonical
+Enum(mips_arch_opt_value) String(34kf1_1) Value(61) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kfx) Value(60)
+Enum(mips_arch_opt_value) String(r34kf1_1) Value(61)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kx) Value(61) Canonical
+Enum(mips_arch_opt_value) String(34kfx) Value(62) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kx) Value(61)
+Enum(mips_arch_opt_value) String(r34kfx) Value(62)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kn) Value(62) Canonical
+Enum(mips_arch_opt_value) String(34kx) Value(63) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kn) Value(62)
+Enum(mips_arch_opt_value) String(r34kx) Value(63)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kc) Value(63) Canonical
+Enum(mips_arch_opt_value) String(34kn) Value(64) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kc) Value(63)
+Enum(mips_arch_opt_value) String(r34kn) Value(64)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf2_1) Value(64) Canonical
+Enum(mips_arch_opt_value) String(74kc) Value(65) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf2_1) Value(64)
+Enum(mips_arch_opt_value) String(r74kc) Value(65)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf) Value(65) Canonical
+Enum(mips_arch_opt_value) String(74kf2_1) Value(66) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf) Value(65)
+Enum(mips_arch_opt_value) String(r74kf2_1) Value(66)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf1_1) Value(66) Canonical
+Enum(mips_arch_opt_value) String(74kf) Value(67) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf1_1) Value(66)
+Enum(mips_arch_opt_value) String(r74kf) Value(67)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kfx) Value(67) Canonical
+Enum(mips_arch_opt_value) String(74kf1_1) Value(68) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kfx) Value(67)
+Enum(mips_arch_opt_value) String(r74kf1_1) Value(68)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kx) Value(68) Canonical
+Enum(mips_arch_opt_value) String(74kfx) Value(69) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kx) Value(68)
+Enum(mips_arch_opt_value) String(r74kfx) Value(69)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf3_2) Value(69) Canonical
+Enum(mips_arch_opt_value) String(74kx) Value(70) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf3_2) Value(69)
+Enum(mips_arch_opt_value) String(r74kx) Value(70)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kc) Value(70) Canonical
+Enum(mips_arch_opt_value) String(74kf3_2) Value(71) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kc) Value(70)
+Enum(mips_arch_opt_value) String(r74kf3_2) Value(71)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf2_1) Value(71) Canonical
+Enum(mips_arch_opt_value) String(1004kc) Value(72) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf2_1) Value(71)
+Enum(mips_arch_opt_value) String(r1004kc) Value(72)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf) Value(72) Canonical
+Enum(mips_arch_opt_value) String(1004kf2_1) Value(73) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf) Value(72)
+Enum(mips_arch_opt_value) String(r1004kf2_1) Value(73)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf1_1) Value(73) Canonical
+Enum(mips_arch_opt_value) String(1004kf) Value(74) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf1_1) Value(73)
+Enum(mips_arch_opt_value) String(r1004kf) Value(74)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kc) Value(74) Canonical
+Enum(mips_arch_opt_value) String(1004kf1_1) Value(75) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kc) Value(74)
+Enum(mips_arch_opt_value) String(r1004kf1_1) Value(75)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kf) Value(75) Canonical
+Enum(mips_arch_opt_value) String(5kc) Value(76) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kf) Value(75)
+Enum(mips_arch_opt_value) String(r5kc) Value(76)
 
 EnumValue
-Enum(mips_arch_opt_value) String(20kc) Value(76) Canonical
+Enum(mips_arch_opt_value) String(5kf) Value(77) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r20kc) Value(76)
+Enum(mips_arch_opt_value) String(r5kf) Value(77)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1) Value(77) Canonical
+Enum(mips_arch_opt_value) String(20kc) Value(78) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1a) Value(78) Canonical
+Enum(mips_arch_opt_value) String(r20kc) Value(78)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71000) Value(79) Canonical
+Enum(mips_arch_opt_value) String(sb1) Value(79) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71k) Value(79)
+Enum(mips_arch_opt_value) String(sb1a) Value(80) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlr) Value(80) Canonical
+Enum(mips_arch_opt_value) String(sr71000) Value(81) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(loongson3a) Value(81) Canonical
+Enum(mips_arch_opt_value) String(sr71k) Value(81)
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon) Value(82) Canonical
+Enum(mips_arch_opt_value) String(xlr) Value(82) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon+) Value(83) Canonical
+Enum(mips_arch_opt_value) String(loongson3a) Value(83) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon2) Value(84) Canonical
+Enum(mips_arch_opt_value) String(octeon) Value(84) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlp) Value(85) Canonical
+Enum(mips_arch_opt_value) String(octeon+) Value(85) Canonical
 
+EnumValue
+Enum(mips_arch_opt_value) String(octeon2) Value(86) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(xlp) Value(87) Canonical
+
Index: config/mips/gnu-user.h
===================================================================
--- config/mips/gnu-user.h	(revision 195900)
+++ config/mips/gnu-user.h	(working copy)
@@ -137,3 +137,12 @@
 #define ENDFILE_SPEC \
   GNU_USER_TARGET_MATHFILE_SPEC " " \
   GNU_USER_TARGET_ENDFILE_SPEC
+
+#undef SUBTARGET_OVERRIDE_OPTIONS
+#define SUBTARGET_OVERRIDE_OPTIONS                              \
+do {                                                            \
+  /* microMIPS PLT entries are non-microMIPS.  */               \
+  TARGET_INTERLINK_UNCOMPRESSED = 1;   				\
+} while (0)
+
+
Index: config/mips/micromips.md
===================================================================
--- config/mips/micromips.md	(revision 0)
+++ config/mips/micromips.md	(revision 0)
@@ -0,0 +1,108 @@
+(define_insn "*store_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "memory_operand")
+	     (match_operand:SI 2 "register_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (true, operands[0])"
+  { return umips_output_save_restore (true, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+(define_insn "*load_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "register_operand")
+	     (match_operand:SI 2 "memory_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (false, operands[0])"
+  { return umips_output_save_restore (false, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For lwp
+(define_peephole2
+  [(set (match_operand:SI 0 "d_operand" "")
+        (match_operand:SI 1 "non_volatile_mem_operand" ""))
+   (set (match_operand:SI 2 "d_operand" "")
+        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+;;  The behavior of the lwp insn is undefined if placed in a delay slot.
+(define_insn "*lwp"
+  [(parallel [(set (match_operand:SI 0 "d_operand")
+		   (match_operand:SI 1 "non_volatile_mem_operand"))
+	      (set (match_operand:SI 2 "d_operand")
+		   (match_operand:SI 3 "non_volatile_mem_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+{
+  umips_output_load_store_pair (true, operands);
+  return "";
+}
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For swp
+(define_peephole2
+  [(set (match_operand:SI 0 "non_volatile_mem_operand" "")
+        (match_operand:SI 1 "d_operand" ""))
+   (set (match_operand:SI 2 "non_volatile_mem_operand" "")
+        (match_operand:SI 3 "d_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*swp"
+  [(parallel [(set (match_operand:SI 0 "non_volatile_mem_operand")
+		   (match_operand:SI 1 "d_operand"))
+	      (set (match_operand:SI 2 "non_volatile_mem_operand")
+		   (match_operand:SI 3 "d_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+{
+  umips_output_load_store_pair (false, operands);
+  return "";
+}
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+; For movep
+(define_peephole2
+  [(set (match_operand:MOVEP1 0 "register_operand" "")
+        (match_operand:MOVEP1 1 "movep_src_operand" ""))
+   (set (match_operand:MOVEP2 2 "register_operand" "")
+        (match_operand:MOVEP2 3 "movep_src_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+;;  The behavior of the movep insn is undefined if placed in a delay slot.
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+		   (match_operand:MOVEP1 1 "movep_src_operand"))
+	      (set (match_operand:MOVEP2 2 "register_operand")
+		   (match_operand:MOVEP2 3 "movep_src_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+{
+  if (REGNO (operands[0]) < REGNO (operands[2]))
+    return "movep\t%0,%2,%z1,%z3";
+  else
+    return "movep\t%2,%0,%z3,%z1";
+}
+  [(set_attr "type" "move")
+   (set_attr "mode" "<MODE>")
+   (set_attr "can_delay" "no")])
Index: config/mips/constraints.md
===================================================================
--- config/mips/constraints.md	(revision 195900)
+++ config/mips/constraints.md	(working copy)
@@ -232,6 +232,26 @@
    "@internal"
    (match_operand 0 "low_bitmask_operand"))
 
+(define_memory_constraint "ZC"
+  "When compiling microMIPS code, this constraing matches a memory operand
+   whose address is formed from a base register and a 12-bit offset.  These
+   operands can be used for microMIPS instructions such as @code{ll} and
+   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+   equivalent to @code{R}."
+  (and (match_code "mem")
+       (ior (and (match_test "TARGET_MICROMIPS")
+		 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)"))
+	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "ZD"
+  "When compiling microMIPS code, this constraint matches an address operand
+   that is formed from a base register and a 12-bit offset.  These operands
+   can be used for microMIPS instructions such as @code{prefetch}.  When
+   not compiling for microMIPS code, @code{YC} is equivalent to @code{p}."
+   (ior (and (match_test "TARGET_MICROMIPS")
+	     (match_test "umips_12bit_offset_address_p (op, mode)"))
+	(match_test "mips_address_insns (op, mode, false)")))
+
 (define_memory_constraint "ZR"
  "@internal
   An address valid for loading/storing register exclusive"
Index: config/mips/predicates.md
===================================================================
--- config/mips/predicates.md	(revision 195900)
+++ config/mips/predicates.md	(working copy)
@@ -122,6 +122,15 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "movep_src_register"
+  (and (match_code "reg")
+       (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
+	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
+
+(define_predicate "movep_src_operand"
+  (ior (match_operand 0 "const_0_operand")
+       (match_operand 0 "movep_src_register")))
+
 (define_predicate "lo_operand"
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
@@ -371,3 +380,8 @@
 (define_predicate "mem_noofs_operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
+
+;; Return 1 if the operand is in non-volatile memory.
+(define_predicate "non_volatile_mem_operand"
+  (and (match_operand 0 "memory_operand")
+       (not (match_test "MEM_VOLATILE_P (op)"))))
Index: config/mips/mips.md
===================================================================
--- config/mips/mips.md	(revision 195900)
+++ config/mips/mips.md	(working copy)
@@ -342,13 +342,14 @@
 ;; syncloop	memory atomic operation implemented as a sync loop
 ;; nop		no operation
 ;; ghost	an instruction that produces no real code
+;; multimem	microMIPS multiword load and store
 (define_attr "type"
   "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
    prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
    shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
    fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
    frsqrt,frsqrt1,frsqrt2,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat,
-   multi,atomic,syncloop,nop,ghost"
+   multi,atomic,syncloop,nop,ghost,multimem"
   (cond [(eq_attr "jal" "!unset") (const_string "call")
 	 (eq_attr "got" "load") (const_string "load")
 
@@ -413,9 +414,15 @@
 
 ;; Length of instruction in bytes.
 (define_attr "length" ""
-   (cond [;; Direct branch instructions have a range of [-0x20000,0x1fffc],
-	  ;; relative to the address of the delay slot.  If a branch is
-	  ;; outside this range, we have a choice of two sequences.
+   (cond [(and (eq_attr "extended_mips16" "yes")
+	       (match_test "TARGET_MIPS16"))
+	  (const_int 8)
+
+	  ;; Direct microMIPS branch instructions have a range of
+	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
+	  ;; If a branch is outside this range, we have a choice of two
+	  ;; sequences.
+	  ;;
 	  ;; For PIC, an out-of-range branch like:
 	  ;;
 	  ;;	bne	r1,r2,target
@@ -451,10 +458,17 @@
 	  ;; from the shorten_branches reference address.
 	  (and (eq_attr "type" "branch")
 	       (not (match_test "TARGET_MIPS16")))
-	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
-		      (le (minus (pc) (match_dup 0)) (const_int 131068)))
+	  	 ;; any variant can handle the 17-bit range
+	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 65532))
+		      (le (minus (pc) (match_dup 0)) (const_int 65534)))
 		   (const_int 4)
 
+		 ;; The 18-bit range is OK other than for microMIPS.
+		 (and (eq (symbol_ref "TARGET_MICROMIPS") (const_int 0))
+		      (and (le (minus (match_dup 0) (pc)) (const_int 131064))
+		      	   (le (minus (pc) (match_dup 0)) (const_int 131068))))
+		   (const_int 4)
+
 		 ;; The non-PIC case: branch, first delay slot, and J.
 		 (match_test "TARGET_ABSOLUTE_JUMPS")
 		   (const_int 12)]
@@ -712,6 +726,9 @@
 ;; modes.
 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
 
+(define_mode_iterator MOVEP1 [SI SF])
+(define_mode_iterator MOVEP2 [SI SF])
+
 ;; This mode iterator allows :HILO to be used as the mode of the
 ;; concatenated HI and LO registers.
 (define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
@@ -3937,7 +3954,7 @@
 (define_insn "mov_<load>l"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_LOAD_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
   "<load>l\t%0,%2"
@@ -3947,7 +3964,7 @@
 (define_insn "mov_<load>r"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_operand:GPR 3 "register_operand" "0")]
 		    UNSPEC_LOAD_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
@@ -3958,7 +3975,7 @@
 (define_insn "mov_<store>l"
   [(set (match_operand:BLK 0 "memory_operand" "=m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_STORE_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
   "<store>l\t%z1,%2"
@@ -3968,7 +3985,7 @@
 (define_insn "mov_<store>r"
   [(set (match_operand:BLK 0 "memory_operand" "+m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_dup 0)]
 		    UNSPEC_STORE_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
@@ -5445,12 +5462,35 @@
 			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
 	 (label_ref (match_operand 0 "" ""))
 	 (pc)))]
-  "!TARGET_MIPS16"
+  "!TARGET_MIPS16 && !TARGET_MICROMIPS"
 {
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
 }
+  [(set_attr "type" "branch")
+   (set_attr "mode" "none")])
+
+(define_insn "*branch_equality<mode>_micromips"
+  [(set (pc)
+	(if_then_else
+	 (match_operator 1 "equality_operator"
+			 [(match_operand:GPR 2 "register_operand" "d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
+	 (label_ref (match_operand 0 "" ""))
+	 (pc)))]
+  "TARGET_MICROMIPS"
+{
+  /* For a simple bnez or beqz microMIPS branch.  */
+  if (operands[3] == const0_rtx && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%C1z%:\t%2,%0",
+					   "%*b%N1z%:\t%2,%0");
+
+  return mips_output_conditional_branch (insn, operands,
+					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
+					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
+}
   [(set_attr "type" "branch")])
 
 (define_insn "*branch_equality<mode>_inverted"
@@ -5461,7 +5501,7 @@
 			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
 	 (pc)
 	 (label_ref (match_operand 0 "" ""))))]
-  "!TARGET_MIPS16"
+  "!TARGET_MIPS16 && !TARGET_MICROMIPS"
 {
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
@@ -5532,6 +5572,29 @@
 		      (label_ref (match_operand 1))
 		      (pc)))])
 
+(define_insn "*branch_equality<mode>_inverted_micromips"
+  [(set (pc)
+	(if_then_else
+	 (match_operator 0 "equality_operator"
+			 [(match_operand:GPR 2 "register_operand" "d")
+			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
+	 (pc)
+	 (label_ref (match_operand 1 "" ""))))]
+  "TARGET_MICROMIPS"
+{
+  /* For a simple bnez or beqz microMIPS branch.  */
+  if (operands[3] == const0_rtx && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%N0z%:\t%2,%1",
+					   "%*b%C0z%:\t%2,%1");
+
+  return mips_output_conditional_branch (insn, operands,
+					 MIPS_BRANCH ("b%N0", "%2,%z3,%1"),
+					 MIPS_BRANCH ("b%C0", "%2,%z3,%1"));
+}
+  [(set_attr "type" "branch")
+   (set_attr "mode" "none")])
+
 ;; Branch if bit is set/clear.
 
 (define_insn "*branch_bit<bbv><mode>"
@@ -5766,7 +5829,14 @@
   [(set (pc)
 	(label_ref (match_operand 0)))]
   "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
-  { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
+{
+  /* Use a branch for microMIPS.  The assembler will choose
+     a 16-bit branch, a 32-bit branch, or a 32-bit jump.  */
+  if (TARGET_MICROMIPS && !TARGET_ABICALLS_PIC2)
+    return "%*b\t%l0%/";
+  else
+    return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+}
   [(set_attr "type" "jump")])
 
 (define_insn "*jump_pic"
@@ -5829,7 +5899,12 @@
 (define_insn "indirect_jump_<mode>"
   [(set (pc) (match_operand:P 0 "register_operand" "d"))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -5873,7 +5948,12 @@
 	(match_operand:P 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -6094,7 +6174,12 @@
   [(any_return)
    (use (match_operand 0 "pmode_register_operand" ""))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type"	"jump")
    (set_attr "mode"	"none")])
 
@@ -6350,7 +6435,12 @@
   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
 	 (match_operand 1 "" ""))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 0, 1); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J ("j", operands, 0);
+    else
+      return MIPS_CALL ("j", operands, 0, 1);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6371,7 +6461,12 @@
         (call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
               (match_operand 2 "" "")))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J ("j", operands, 1);
+    else
+      return MIPS_CALL ("j", operands, 1, 2);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6383,7 +6478,12 @@
 	(call (mem:SI (match_dup 1))
 	      (match_dup 2)))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+  {
+    if (TARGET_MICROMIPS)
+      return MICROMIPS_J ("j", operands, 1);
+    else
+      return MIPS_CALL ("j", operands, 1, 2);
+  }
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6629,7 +6729,7 @@
 
 
 (define_insn "prefetch"
-  [(prefetch (match_operand:QI 0 "address_operand" "p")
+  [(prefetch (match_operand:QI 0 "address_operand" "ZD")
 	     (match_operand 1 "const_int_operand" "n")
 	     (match_operand 2 "const_int_operand" "n"))]
   "ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
@@ -6922,6 +7022,9 @@
 ; MIPS fixed-point instructions.
 (include "mips-fixed.md")
 
+; microMIPS patterns.
+(include "micromips.md")
+
 ; ST-Microelectronics Loongson-2E/2F-specific patterns.
 (include "loongson.md")
 
Index: config/mips/mips.opt
===================================================================
--- config/mips/mips.opt	(revision 195900)
+++ config/mips/mips.opt	(working copy)
@@ -217,9 +217,18 @@
 Target Report RejectNegative InverseMask(SOFT_FLOAT_ABI, HARD_FLOAT_ABI)
 Allow the use of hardware floating-point ABI and instructions
 
+minterlink-compressed
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+Generate code that is link-compatible with MIPS16 and microMIPS code.
+
+minterlink-uncompressed
+Target Report Var(TARGET_INTERLINK_UNCOMPRESSED) Init(1)
+Generate code that is link-compatible with the standard (uncompressed)
+MIPS ISA.
+
 minterlink-mips16
-Target Report Var(TARGET_INTERLINK_MIPS16) Init(0)
-Generate code that can be safely linked with MIPS16 code.
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+An alias for minterlink-compressed provided for backward-compatibility.
 
 mips
 Target RejectNegative Joined ToLower Enum(mips_mips_opt_value) Var(mips_isa_option)
@@ -261,6 +270,10 @@
 Target Report Mask(MEMCPY)
 Don't optimize block moves
 
+mmicromips
+Target Report Mask(MICROMIPS)
+Use microMIPS instructions
+
 mmt
 Target Report Var(TARGET_MT)
 Allow the use of MT instructions
Index: config/mips/sync.md
===================================================================
--- config/mips/sync.md	(revision 195900)
+++ config/mips/sync.md	(working copy)
@@ -59,7 +59,7 @@
 ;; Can be removed in favor of atomic_compare_and_swap below.
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
 			      (match_operand:GPR 3 "arith_operand" "I,d")]
@@ -89,7 +89,7 @@
 ;; Helper insn for mips_expand_atomic_qihi.
 (define_insn "compare_and_swap_12"
   [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-	(match_operand:SI 1 "memory_operand" "+R,R"))
+	(match_operand:SI 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
 			     (match_operand:SI 3 "register_operand" "d,d")
@@ -106,7 +106,7 @@
    (set_attr "sync_insn1_op2" "5")])
 
 (define_insn "sync_add<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 0)
 		     (match_operand:GPR 1 "arith_operand" "I,d"))]
@@ -134,7 +134,7 @@
 
 ;; Helper insn for sync_<optab><mode>
 (define_insn "sync_<optab>_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -174,7 +174,7 @@
 ;; Helper insn for sync_old_<optab><mode>
 (define_insn "sync_old_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -217,7 +217,7 @@
 (define_insn "sync_new_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
@@ -257,7 +257,7 @@
 
 ;; Helper insn for sync_nand<mode>
 (define_insn "sync_nand_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -296,7 +296,7 @@
 ;; Helper insn for sync_old_nand<mode>
 (define_insn "sync_old_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -337,7 +337,7 @@
 (define_insn "sync_new_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (match_operand:SI 4 "reg_or_0_operand" "dJ")]
@@ -360,7 +360,7 @@
    (set_attr "sync_insn1_op2" "4")])
 
 (define_insn "sync_sub<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR")
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 0)
 		      (match_operand:GPR 1 "register_operand" "d"))]
@@ -374,7 +374,7 @@
 ;; Can be removed in favor of atomic_fetch_add below.
 (define_insn "sync_old_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 1)
@@ -389,7 +389,7 @@
 
 (define_insn "sync_old_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-	(match_operand:GPR 1 "memory_operand" "+R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 1)
@@ -404,7 +404,7 @@
 
 (define_insn "sync_new_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-        (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+        (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZR,ZR")
 		  (match_operand:GPR 2 "arith_operand" "I,d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -420,7 +420,7 @@
 
 (define_insn "sync_new_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-        (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+        (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZR")
 		   (match_operand:GPR 2 "register_operand" "d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -435,7 +435,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_<optab><mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
 			      (match_dup 0))]
@@ -448,7 +448,7 @@
 
 (define_insn "sync_old_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -463,7 +463,7 @@
 
 (define_insn "sync_new_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -478,7 +478,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_nand<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
@@ -490,7 +490,7 @@
 
 (define_insn "sync_old_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
@@ -504,7 +504,7 @@
 
 (define_insn "sync_new_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_NEW_OP))]
@@ -519,7 +519,7 @@
 
 (define_insn "sync_lock_test_and_set<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
 	 UNSPEC_SYNC_EXCHANGE))]
@@ -546,7 +546,7 @@
 
 (define_insn "test_and_set_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
 			     (match_operand:SI 3 "register_operand" "d")
@@ -576,7 +576,7 @@
 	;; TODO: the obscuring unspec can be relaxed for permissive memory
 	;; models.
 	;; Same applies to other atomic_* patterns.
-	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+R,R")
+	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZR,ZR")
 			      (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
 	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
    (set (match_operand:GPR 1 "register_operand" "=&d,&d")
@@ -629,7 +629,7 @@
 
 (define_insn "atomic_exchange<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_EXCHANGE))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
@@ -684,7 +684,7 @@
 
 (define_insn "atomic_fetch_add<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_FETCH_OP))
    (set (match_dup 1)
 	(unspec_volatile:GPR
Index: config/mips/mips-cpus.def
===================================================================
--- config/mips/mips-cpus.def	(revision 195900)
+++ config/mips/mips-cpus.def	(working copy)
@@ -92,6 +92,8 @@
 
 /* MIPS32 Release 2 processors.  */
 MIPS_CPU ("m4k", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14kc", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14k", PROCESSOR_M4K, 33, 0)
 MIPS_CPU ("4kec", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kem", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kep", PROCESSOR_4KP, 33, 0)
Index: config/mips/mips-protos.h
===================================================================
--- config/mips/mips-protos.h	(revision 195900)
+++ config/mips/mips-protos.h	(working copy)
@@ -350,6 +350,12 @@
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern const char *umips_output_save_restore (bool, rtx);
+extern bool umips_save_restore_pattern_p (bool, rtx);
+extern bool umips_load_store_pair_p (bool, rtx *);
+extern void umips_output_load_store_pair (bool, rtx *);
+extern bool umips_movep_target_p (rtx, rtx);
+extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 195900)
+++ config/mips/mips.c	(working copy)
@@ -77,6 +77,9 @@
    preserve the maximum stack alignment.  We therefore use a value
    of 0x7ff0 in this case.
 
+   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
+   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
+
    MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
    up to 0x7f8 bytes and can usually save or restore all the registers
    that we need to save or restore.  (Note that we can only use these
@@ -86,8 +89,10 @@
    RESTORE are not available.  We can then use unextended instructions
    to save and restore registers, and to allocate and deallocate the top
    part of the frame.  */
+
 #define MIPS_MAX_FIRST_STACK_STEP					\
-  (!TARGET_MIPS16 ? 0x7ff0						\
+  (TARGET_MICROMIPS ? 0x7f0						\
+   : !TARGET_MIPS16 ? 0x7ff0						\
    : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8				\
    : TARGET_64BIT ? 0x100 : 0x400)
 
@@ -560,8 +565,8 @@
 /* The ambient target flags, excluding MASK_MIPS16.  */
 static int mips_base_target_flags;
 
-/* True if MIPS16 is the default mode.  */
-bool mips_base_mips16;
+/* The default compression mode.  */
+unsigned int mips_base_compression_flags;
 
 /* The ambient values of other global variables.  */
 static int mips_base_schedule_insns; /* flag_schedule_insns */
@@ -674,6 +679,9 @@
      code generation but don't carry other semantics.  */
   { "mips16", 	   0, 0, true,  false, false, NULL, false },
   { "nomips16",    0, 0, true,  false, false, NULL, false },
+  { "micromips",   0, 0, true,  false, false, NULL, false },
+  { "nomicromips", 0, 0, true,  false, false, NULL, false },
+  { "nocompression", 0, 0, true,  false, false, NULL, false },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 0, false, true,  true, NULL, false },
   { "use_shadow_register_set",	0, 0, false, true,  true, NULL, false },
@@ -1167,10 +1175,11 @@
   const char *name;
   hashval_t hash;
   void **slot;
+  bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) != 0;
 
   /* Use the opposite of the command-line setting for anonymous decls.  */
   if (!DECL_NAME (decl))
-    return !mips_base_mips16;
+    return !base_is_mips16;
 
   if (!mflip_mips16_htab)
     mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
@@ -1185,7 +1194,7 @@
       mips16_flipper = !mips16_flipper;
       entry = ggc_alloc_mflip_mips16_entry ();
       entry->name = name;
-      entry->mips16_p = mips16_flipper ? !mips_base_mips16 : mips_base_mips16;
+      entry->mips16_p = mips16_flipper ? !base_is_mips16 : base_is_mips16;
       *slot = entry;
     }
   return entry->mips16_p;
@@ -1207,20 +1216,7 @@
 	  || lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
 }
 
-/* Similar predicates for "mips16"/"nomips16" function attributes.  */
 
-static bool
-mips_mips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
-static bool
-mips_nomips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
 /* Check if the interrupt attribute is set for a function.  */
 
 static bool
@@ -1257,12 +1253,51 @@
 			   TYPE_ATTRIBUTES (type)) != NULL;
 }
 
-/* Return true if function DECL is a MIPS16 function.  Return the ambient
-   setting if DECL is null.  */
+/* Return the set of compression modes that are explicitly required
+   by DECL.  */
 
-static bool
-mips_use_mips16_mode_p (tree decl)
+static unsigned int
+mips_get_compress_on_flags (tree decl)
 {
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the set of compression modes that are explicitly forbidden
+   by DECL.  */
+
+static unsigned int
+mips_get_compress_off_flags (tree decl)
+{
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MIPS16 | MASK_MICROMIPS;
+
+  if (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the compression mode that should be used for function DECL.
+   Return the ambient setting if DECL is null.  */
+static unsigned int
+mips_get_compress_mode (tree decl)
+{
+  unsigned int flags, force_on;
+
+  flags = mips_base_compression_flags;
   if (decl)
     {
       /* Nested functions must use the same frame pointer as their
@@ -1270,14 +1305,38 @@
       tree parent = decl_function_context (decl);
       if (parent)
 	decl = parent;
-      if (mips_mips16_decl_p (decl))
-	return true;
-      if (mips_nomips16_decl_p (decl))
-	return false;
+      force_on = mips_get_compress_on_flags (decl);
+      if (force_on)
+	return force_on;
+      flags &= ~mips_get_compress_off_flags (decl);
     }
-  return mips_base_mips16;
+  return flags;
 }
 
+/*  Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
+    flags FLAGS.  */
+
+static const char *
+mips_get_compress_on_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "mips16";
+  return "micromips";
+}
+
+/* Return the attribute name that forbids MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_off_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "nomips16";
+  if (flags == MASK_MICROMIPS)
+    return "nomicromips";
+  return "nocompression";
+}
+
 /* Implement TARGET_COMP_TYPE_ATTRIBUTES.  */
 
 static int
@@ -1291,44 +1350,93 @@
   return 1;
 }
 
+/* Set compression flags based on attributes.  */
+
+static unsigned int
+mips_get_compression_attrs (tree *attributes)
+{
+  unsigned int compression_flags = 0;
+  if (lookup_attribute ("mips16", *attributes) != NULL)
+    compression_flags |= MASK_MIPS16;
+  if (lookup_attribute ("micromips", *attributes) != NULL)
+    compression_flags |= MASK_MICROMIPS;
+  return compression_flags;
+}
+
+/* Set nocompression flags based on attributes.  */
+
+static unsigned int
+mips_get_nocompression_attrs (tree *attributes)
+{
+  unsigned int nocompression_flags = 0;
+
+  if (lookup_attribute ("nomips16", *attributes) != NULL)
+    nocompression_flags |= MASK_MIPS16;
+  if (lookup_attribute ("nomicromips", *attributes) != NULL)
+    nocompression_flags |= MASK_MICROMIPS;
+  if (lookup_attribute ("nocompression", *attributes) != NULL)
+    nocompression_flags |= MASK_MICROMIPS | MASK_MIPS16;
+  return nocompression_flags;
+}
+
 /* Implement TARGET_INSERT_ATTRIBUTES.  */
 
 static void
 mips_insert_attributes (tree decl, tree *attributes)
 {
   const char *name;
-  bool mips16_p, nomips16_p;
+  unsigned int compression_flags, nocompression_flags;
 
   /* Check for "mips16" and "nomips16" attributes.  */
-  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
-  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+  compression_flags = mips_get_compression_attrs (attributes);
+  nocompression_flags = mips_get_nocompression_attrs (attributes);
+
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
-      if (mips16_p)
-	error ("%qs attribute only applies to functions", "mips16");
-      if (nomips16_p)
-	error ("%qs attribute only applies to functions", "nomips16");
+      if (nocompression_flags)
+	error ("%qs attribute only applies to function",
+	       mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags)
+	error ("%qs attribute only applies to function",
+	       mips_get_compress_on_name (nocompression_flags));
     }
   else
     {
-      mips16_p |= mips_mips16_decl_p (decl);
-      nomips16_p |= mips_nomips16_decl_p (decl);
-      if (mips16_p || nomips16_p)
+      compression_flags |= mips_get_compress_on_flags (decl);
+      nocompression_flags |= mips_get_compress_off_flags (decl);
+
+      if (compression_flags && nocompression_flags)
+	error ("%qE cannot have both %qs and %qs attributes",
+	       DECL_NAME (decl), mips_get_compress_on_name (compression_flags),
+	       mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags & MASK_MIPS16
+          && compression_flags & MASK_MICROMIPS)
+	error ("%qE cannot have both %s and %s attributes",
+	       DECL_NAME (decl), "mips16", "micromips");
+
+      /* If DECL is "nocompression" set the "nomips16" and 
+	 "nomicromips" attributes.  */
+      if (nocompression_flags & MASK_MIPS16
+          && nocompression_flags & MASK_MICROMIPS)
 	{
-	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
-	  if (mips16_p && nomips16_p)
-	    error ("%qE cannot have both %<mips16%> and "
-		   "%<nomips16%> attributes",
-		   DECL_NAME (decl));
+	  name = "nomips16";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	  name = "nomicromips";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
 	}
-      else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
+     else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
 	{
 	  /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
 	     "mips16" attribute, arbitrarily pick one.  We must pick the same
 	     setting for duplicate declarations of a function.  */
 	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
+	  name = "nomips16";
+ 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	  name = "nomicromips";
 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
-	}
+ 	}
     }
 }
 
@@ -1337,14 +1445,24 @@
 static tree
 mips_merge_decl_attributes (tree olddecl, tree newdecl)
 {
-  /* The decls' "mips16" and "nomips16" attributes must match exactly.  */
-  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
+  unsigned int diff;
+
+  diff = (mips_get_compress_on_flags (olddecl)
+	  ^ mips_get_compress_on_flags (newdecl));
+
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "mips16");
-  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
+	   DECL_NAME (newdecl), mips_get_compress_on_name (diff));
+
+
+  diff = (mips_get_compress_off_flags (olddecl)
+	  ^ mips_get_compress_off_flags (newdecl));
+
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "nomips16");
+	   DECL_NAME (newdecl), mips_get_compress_off_name (diff));
 
+
   return merge_attributes (DECL_ATTRIBUTES (olddecl),
 			   DECL_ATTRIBUTES (newdecl));
 }
@@ -1550,7 +1668,7 @@
   return (GET_CODE (x) == SYMBOL_REF
 	  && SYMBOL_REF_LOCAL_P (x)
 	  && !SYMBOL_REF_EXTERNAL_P (x)
-	  && mips_use_mips16_mode_p (SYMBOL_REF_DECL (x)));
+	  && (mips_get_compress_mode (SYMBOL_REF_DECL (x)) & MASK_MIPS16));
 }
 
 /* Return true if SYMBOL_REF X binds locally.  */
@@ -2300,6 +2418,20 @@
   return 0;
 }
 
+/* Return true if X is a legitimate address with a 12-bit offset.
+   MODE is the mode of the value being accessed.  */
+
+bool
+umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && CONST_INT_P (addr.offset)
+	  && UMIPS_12BIT_OFFSET_P (addr.offset));
+}
+
 /* Return the number of instructions needed to load constant X.
    Return 0 if X isn't a valid constant.  */
 
@@ -6097,6 +6229,13 @@
   else
     fprintf (asm_out_file, "\t.set\tnomips16\n");
 
+  if (TARGET_MICROMIPS)
+    fprintf (asm_out_file, "\t.set\tmicromips\n");
+#ifdef HAVE_GAS_MICROMIPS
+  else 
+    fprintf (asm_out_file, "\t.set\tnomicromips\n");
+#endif
+
   if (!flag_inhibit_size_directive)
     {
       fputs ("\t.ent\t", asm_out_file);
@@ -6903,11 +7042,51 @@
     mips_restore_gp_from_cprestore_slot (gen_rtx_REG (Pmode, GP_ARG_FIRST + 2));
 }
 
+/* Return true if a call to DECL may need to use JALX.  */
+
+static bool
+mips_call_may_need_jalx_p (tree decl)
+{
+  /* If the current translation unit would use a different mode for DECL,
+     assume that the call needs JALX.  */
+  if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
+    return true;
+
+  /* mips_get_compress_mode is always accurate for locally-binding
+     functions in the current translation unit.  */
+  if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
+    return false;
+
+  /* PLTs use the standard encoding, so calls that might go via PLTs
+     must use JALX.  */
+  if (TARGET_COMPRESSION
+      && TARGET_ABICALLS_PIC0
+      && DECL_EXTERNAL (decl)
+      && !targetm.binds_local_p (decl))
+    return true;
+
+  /* When -minterlink-compressed is in effect, assume that functions
+     could use a different encoding mode unless an attribute explicitly
+     tells us otherwise.  */
+  if (TARGET_INTERLINK_COMPRESSED)
+    {
+      if (!TARGET_COMPRESSION && mips_get_compress_off_flags (decl) == 0)
+	return true;
+      if (TARGET_COMPRESSION && mips_get_compress_on_flags (decl) == 0)
+	return true;
+    }
+
+  return false;
+}
+
 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
 
 static bool
 mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
+
+  unsigned int compression_mode = mips_get_compress_mode (decl);
+
   if (!TARGET_SIBCALLS)
     return false;
 
@@ -6916,22 +7095,43 @@
   if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
     return false;
 
+  if (TARGET_MICROMIPS)
+    {
+
+      /* We can't do a sibcall if the called function isn't microMIPS.  */
+      if (decl
+	  && (compression_mode & MASK_MICROMIPS) == 0
+	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+	return false;
+
+      /* Direct Js are only possible to functions that use the same ISA
+	 encoding.  There is no JX counterpoart of JALX.  */
+      if (decl
+	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
+	  && mips_call_may_need_jalx_p (decl))
+	return false;
+
+      /* Otherwise OK.  */
+      return true;
+    }
+
   /* We can't do a sibcall if the called function is a MIPS16 function
      because there is no direct "jx" instruction equivalent to "jalx" to
      switch the ISA mode.  We only care about cases where the sibling
      and normal calls would both be direct.  */
   if (decl
-      && mips_use_mips16_mode_p (decl)
+      && ((compression_mode & (MASK_MIPS16 | MASK_MICROMIPS)) != 0)
       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
     return false;
 
-  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
-     functions could be MIPS16 ones unless an attribute explicitly tells
+  /* When -minterlink-compressed is in effect, assume that non-locally-binding
+     functions could be MIPS16 or microMIPS unless an attribute explicitly tells
      us otherwise.  */
-  if (TARGET_INTERLINK_MIPS16
+  if (TARGET_INTERLINK_COMPRESSED
       && decl
       && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
-      && !mips_nomips16_decl_p (decl)
+      && (compression_mode & MASK_MICROMIPS) == 0
+      && (compression_mode & MASK_MIPS16) == 0
       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
     return false;
 
@@ -7798,6 +7998,9 @@
    '^'	Print the name of the pic call-through register (t9 or $25).
    '+'	Print the name of the gp register (usually gp or $28).
    '$'	Print the name of the stack pointer register (sp or $29).
+   ':'  Print "c" to use the compact version if the delay slot is a nop.
+   '!'  Print "s" to use the short version if the delay slot contains a
+	16-bit instruction.
 
    See also mips_init_print_operand_pucnt.  */
 
@@ -7881,6 +8084,20 @@
       fputs (reg_names[STACK_POINTER_REGNUM], file);
       break;
 
+    case ':':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+	 use the compact version for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('c', file);
+      break;
+
+    case '!':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+	 a 16-bit delay slot for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('s', file);
+      break;
+
     default:
       gcc_unreachable ();
       break;
@@ -7894,7 +8111,7 @@
 {
   const char *p;
 
-  for (p = "()[]<>*#/?~.@^+$"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$:!"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -10236,6 +10453,129 @@
       }
 }
 
+/* Save register REG to MEM.  Make the instruction frame-related.  */
+
+static void
+mips_save_reg (rtx reg, rtx mem)
+{
+  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
+    {
+      rtx x1, x2;
+
+      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
+
+      x1 = mips_frame_set (mips_subword (mem, false),
+			   mips_subword (reg, false));
+      x2 = mips_frame_set (mips_subword (mem, true),
+			   mips_subword (reg, true));
+      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
+    }
+  else
+    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
+}
+
+
+/* Capture the register combinations that are allowed in a swm or lwm
+   instruction.  The entries are ordered by number of registers set in
+   the mask.  We also ignore the single register encodings because a
+   normal sw/lw is preferred.  */
+   
+static const unsigned int umips_swm_mask[17] = {
+ 0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
+ 0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,	
+ 0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
+ 0x000f0000, 0x80030000, 0x00070000, 0x80010000,
+ 0x00030000 };
+
+static const unsigned int umips_swm_encoding[17] = {
+ 25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2 };
+
+
+/* Try to use a microMIPS LWM or SWM instruction to save or restore
+   as many GPRs in *MASK as possible.  *OFFSET is the offset from the
+   stack pointer of the topmost save slot.
+
+   Remove from *MASK all registers that were handled using LWM and SWM.
+   Update *OFFSET so that it points to the first unused save slot.  */
+
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+			  unsigned *mask, HOST_WIDE_INT *offset)
+{
+  int i, nregs;
+  unsigned int j;
+  rtx pattern, set, reg, mem;
+  HOST_WIDE_INT this_offset;
+  rtx this_base;
+
+  /* Try matching $16 to $31 (s0 to ra).  */
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if ((*mask & 0xffff0000) == umips_swm_mask[i])
+      break;
+
+  if (i == ARRAY_SIZE (umips_swm_mask))
+    return false;
+
+  /* Adjust offset for output.  */
+  nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
+  *offset -= (UNITS_PER_WORD * (nregs - 1));
+
+  /* LWM/SWM can only support offsets from -2048 to 2047.  */
+  if (!UMIPS_12BIT_OFFSET_P (*offset))
+    return false;
+
+  /* Create the final PARALLEL.  */
+  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs));
+
+  this_base = stack_pointer_rtx;
+  this_offset = *offset;
+
+  /* For registers $16-$23 and $30.  */
+  for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
+    {
+      unsigned int regno;
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      regno = (j != 8) ? 16 + j : 30;
+      *mask &= 0 << regno;
+      reg = gen_rtx_REG (SImode, regno);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  /* For register $31.  */
+  if (umips_swm_encoding[i] >> 4)
+    {
+      long long offset = this_offset + j * UNITS_PER_WORD;
+      *mask &= 0 << 31;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      reg = gen_rtx_REG (SImode, 31);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  pattern = emit_insn (pattern);
+  if (fn == mips_save_reg)
+    RTX_FRAME_RELATED_P (pattern) = 1;  
+
+  /* Adjust the last offset.  */
+  offset -= UNITS_PER_WORD;
+
+  return true;
+}
+
 /* Call FN for each register that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -10245,16 +10585,21 @@
 				 mips_save_restore_fn fn)
 {
   enum machine_mode fpr_mode;
-  HOST_WIDE_INT offset;
   int regno;
+  const struct mips_frame_info *frame = &cfun->machine->frame;
+  HOST_WIDE_INT offset = frame->gp_sp_offset - sp_offset;
+  unsigned int mask = frame->mask;
 
   /* Save registers starting from high to low.  The debuggers prefer at least
      the return register be stored at func+4, and also it allows us not to
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
-  offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+
+  if (TARGET_MICROMIPS)
+    umips_build_save_restore (fn, &mask, &offset);
+
   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
-    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+    if (BITSET_P (mask, regno - GP_REG_FIRST))
       {
 	/* Record the ra offset for use by mips_function_profiler.  */
 	if (regno == RETURN_ADDR_REGNUM)
@@ -10501,27 +10846,7 @@
   emit_clobber (gen_frame_mem (BLKmode, stack_pointer_rtx));
 }
 
-/* Save register REG to MEM.  Make the instruction frame-related.  */
 
-static void
-mips_save_reg (rtx reg, rtx mem)
-{
-  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
-    {
-      rtx x1, x2;
-
-      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
-
-      x1 = mips_frame_set (mips_subword (mem, false),
-			   mips_subword (reg, false));
-      x2 = mips_frame_set (mips_subword (mem, true),
-			   mips_subword (reg, true));
-      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
-    }
-  else
-    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
-}
-
 /* The __gnu_local_gp symbol.  */
 
 static GTY(()) rtx mips_gnu_local_gp;
@@ -16211,17 +16536,19 @@
   reload_completed = 0;
 }
 \f
-/* The last argument passed to mips_set_mips16_mode, or negative if the
-   function hasn't been called yet.  */
-static int was_mips16_p = -1;
 
-/* Set up the target-dependent global state so that it matches the
-   current function's ISA mode.  */
+/* The last argument passed to mips_set_compression_mode,
+   or negative if the function hasn't been called yet.  */
+static unsigned int old_compression_mode = -1;
 
+/* Set up the target-dependent global state for ISA mode COMPRESSION_MODE,
+   which is either MASK_MIPS16 or MASK_MICROMIPS.  */
+
 static void
-mips_set_mips16_mode (int mips16_p)
+mips_set_compression_mode (unsigned int compression_mode)
 {
-  if (mips16_p == was_mips16_p)
+
+  if (compression_mode == old_compression_mode)
     return;
 
   /* Restore base settings of various flags.  */
@@ -16233,7 +16560,7 @@
   align_jumps = mips_base_align_jumps;
   align_functions = mips_base_align_functions;
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       /* Switch to MIPS16 mode.  */
       target_flags |= MASK_MIPS16;
@@ -16288,8 +16615,15 @@
   else
     {
       /* Switch to normal (non-MIPS16) mode.  */
-      target_flags &= ~MASK_MIPS16;
+      target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
+      target_flags |= compression_mode;
 
+      if (TARGET_MICROMIPS)
+	{
+	  /* Avoid branch likely.  */
+	  target_flags &= ~MASK_BRANCHLIKELY;
+	}
+
       /* Provide default values for align_* for 64-bit targets.  */
       if (TARGET_64BIT)
 	{
@@ -16310,7 +16644,7 @@
   /* (Re)initialize MIPS target internals for new ISA.  */
   mips_init_relocs ();
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       if (!mips16_globals)
 	mips16_globals = save_target_globals ();
@@ -16320,16 +16654,21 @@
   else
     restore_target_globals (&default_target_globals);
 
-  was_mips16_p = mips16_p;
+  old_compression_mode = compression_mode;
 }
 
 /* Implement TARGET_SET_CURRENT_FUNCTION.  Decide whether the current
-   function should use the MIPS16 ISA and switch modes accordingly.  */
+   function should use the MIPS16 or microMIPS ISA and switch modes
+   accordingly.  */
 
 static void
 mips_set_current_function (tree fndecl)
 {
-  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+
+  unsigned int compression_p = mips_get_compress_mode (fndecl);
+
+  mips_set_compression_mode (compression_p & (MASK_MIPS16 | MASK_MICROMIPS));
+
 }
 \f
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -16437,14 +16776,19 @@
   if (global_options_set.x_mips_isa_option)
     mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
 
-  /* Process flags as though we were generating non-MIPS16 code.  */
-  mips_base_mips16 = TARGET_MIPS16;
-  target_flags &= ~MASK_MIPS16;
-
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
+  /* MIPS16 and microMIPS cannot coexist  */
+  if (TARGET_MICROMIPS && TARGET_MIPS16)
+    error ("unsupported combination: %s", "-mips16 -mmicromips");
+
+  /* Save the base compression state and process flags as though we
+     are generating uncompressed code.  */
+  mips_base_compression_flags = TARGET_COMPRESSION;
+  target_flags &= ~TARGET_COMPRESSION;
+
   /* -mno-float overrides -mhard-float and -msoft-float.  */
   if (TARGET_NO_FLOAT)
     {
@@ -16453,7 +16797,7 @@
     }
 
   if (TARGET_FLIP_MIPS16)
-    TARGET_INTERLINK_MIPS16 = 1;
+    TARGET_INTERLINK_COMPRESSED = 1;
 
   /* Set the small data limit.  */
   mips_small_data_threshold = (global_options_set.x_g_switch_value
@@ -16826,9 +17170,9 @@
 
   /* Now select the ISA mode.
 
-     Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
-     MIPS16 mode afterwards if need be.  */
-  mips_set_mips16_mode (false);
+     Do all CPP-sensitive stuff in non-MIPS16/non-microMIPS mode;
+     We'll switch modes later if required.  */
+  mips_set_compression_mode (false);
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -17088,6 +17432,279 @@
       return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
     }
 }
+
+
+/* Return true if PATTERN matches the kind of instruction generated by
+   umips_build_save_restore.  SAVE_P is true for store.  */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+  int n;
+  unsigned int i;
+  HOST_WIDE_INT first_offset = 0;
+  rtx first_base = 0;
+  unsigned int regmask = 0;
+
+  for (n = 0; n < XVECLEN (pattern, 0); n++)
+    {
+      rtx set, reg, mem, this_base;
+      HOST_WIDE_INT this_offset;
+      unsigned int this_regno;
+
+      /* Check that we have a SET.  */
+      set = XVECEXP (pattern, 0, n);
+      if (GET_CODE (set) != SET)
+	return false;
+
+      /* Check that the SET is a load (if restoring) or a store
+	 (if saving).  */
+      mem = save_p ? SET_DEST (set) : SET_SRC (set);
+      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
+	return false;
+
+      /* Check that the address is the sum of base and a possibly-zero
+	 constant offset.  Determine if the offset is in range.  */
+      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+      if (!REG_P (this_base))
+	return false;
+
+      if (n == 0)
+	{
+	  if (!UMIPS_12BIT_OFFSET_P (this_offset))
+	    return false;
+	  first_base = this_base;
+	  first_offset = this_offset;
+	}
+      else
+	{
+	  /* Check that the save slots are consecutive.  */
+	  if (REGNO (this_base) != REGNO (first_base)
+	      || this_offset != first_offset + UNITS_PER_WORD * n)
+	    return false;
+	}
+
+      /* Check that SET's other operand is a register.  */
+      reg = save_p ? SET_SRC (set) : SET_DEST (set);
+      if (!REG_P (reg))
+	return false;
+
+      this_regno = REGNO (reg);
+      regmask |= 1 << this_regno;
+    }
+
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if (regmask == umips_swm_mask[i])
+      return true;
+
+  return false;
+}
+/* Return the assembly instruction for microMIPS lwm or swm.
+   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+  static char buffer[300];
+  char *s;
+  int n;
+  HOST_WIDE_INT offset;
+  rtx base, mem, set, reg, last_set, last_reg;
+
+  /* Parse the pattern.  */
+  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
+
+  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
+  s += strlen (s);
+  n = XVECLEN (pattern, 0);
+
+  set = XVECEXP (pattern, 0, 0);
+  reg = save_p ? SET_SRC (set) : SET_DEST (set);
+  mem = save_p ? SET_DEST (set) : SET_SRC (set);
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+
+  last_set = XVECEXP (pattern, 0, n - 1);
+  last_reg = save_p ? SET_SRC (last_set) : SET_DEST (last_set);
+
+  if (REGNO (last_reg) == 31)
+    n--;
+
+  gcc_assert (n <= 9);
+  if (n == 0)
+    ;
+  else if (n == 1)
+    s += sprintf (s, "%s,", reg_names[16]);
+  else if (n < 9)
+    s += sprintf (s, "%s-%s,", reg_names[16], reg_names[15 + n]);
+  else if (n == 9)
+    s += sprintf (s, "%s-%s,%s,", reg_names[16], reg_names[23],
+		  reg_names[30]);
+
+  if (REGNO (last_reg) == 31)
+    s += sprintf (s, "%s,", reg_names[31]);
+
+  s += sprintf (s, "%d(%s)", (int)offset, reg_names[REGNO (base)]);
+  return buffer;
+}
+
+/* Return true if MEM1 and MEM2 use the same base register, and the
+   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
+   register into (from) which the contents of MEM1 will be loaded
+   (stored), depending on the value of LOAD_P.
+   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
+
+static bool
+umips_load_store_pair_p_1 (bool load_p, bool swap_p, rtx first_reg,
+			   rtx mem1, rtx mem2)
+{
+  rtx base1, base2;
+  HOST_WIDE_INT offset1, offset2;
+
+  if (!MEM_P (mem1) || !MEM_P (mem2))
+    return false;
+
+  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
+  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
+
+  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
+    return false;
+
+  /* Avoid invalid load pair instructions.  */
+  if (load_p && REGNO (first_reg) == REGNO (base1))
+    return false;
+
+  /* We must avoid this case for anti-dependence.
+     Ex:  lw $3, 4($3)
+          lw $2, 0($3)
+     first_reg is $2, but the base is $3.  */
+  if (load_p
+      && swap_p
+      && REGNO (first_reg) + 1 == REGNO (base1))
+    return false;
+
+  if (swap_p
+      && offset2 + 4 != offset1)
+    return false;
+
+  if (!swap_p
+      && offset1 + 4 != offset2)
+    return false;
+
+  if (!UMIPS_12BIT_OFFSET_P (offset1))
+    return false;
+
+  return true;
+}
+
+/* Return true if operands can be used in an lwp or swp instruction.  */
+
+bool
+umips_load_store_pair_p (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    return umips_load_store_pair_p_1 (load_p, false, reg1, mem1, mem2);
+
+  if (REGNO (reg1) == REGNO (reg2) + 1)
+    return umips_load_store_pair_p_1 (load_p, true, reg2, mem1, mem2);
+
+  return false;
+}
+
+/* Return the assembly instruction for microMIPS lwp or swp.
+   LOAD_P is true for load.  */
+
+static void
+umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
+{
+  rtx ops[] = {reg, mem};
+
+  if (load_p)
+    output_asm_insn ("lwp %0,%1", ops);
+  else
+    output_asm_insn ("swp %0,%1", ops);
+}
+
+void
+umips_output_load_store_pair (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+   
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    {
+      umips_output_load_store_pair_1 (load_p, reg1, mem1);
+      return;
+    }
+
+  gcc_assert (REGNO (reg1) == REGNO (reg2) + 1);
+  umips_output_load_store_pair_1 (load_p, reg2, mem2);
+}
+
+/* Return true if reg1 and reg2 match the criteria for a movep insn.  */
+
+bool
+umips_movep_target_p (rtx reg1, rtx reg2)
+{
+  int regno1, regno2, pair;
+  unsigned int i;
+  static const int match[8] = {
+   0x00000060,	/* 5, 6 */
+   0x000000a0,	/* 5, 7 */
+   0x000000c0,	/* 6, 7 */
+   0x00200010,	/* 4, 21 */
+   0x00400010,	/* 4, 22 */
+   0x00000030,	/* 4, 5 */
+   0x00000050,  /* 4, 6 */
+   0x00000090   /* 4, 7 */
+  };
+
+  if (!REG_P (reg1) || !REG_P (reg2))
+    return false;
+
+  regno1 = REGNO (reg1);
+  regno2 = REGNO (reg2);
+
+  if (!GP_REG_P (regno1)  || !GP_REG_P (regno2))
+    return false;
+
+  pair = (1 << regno1) | (1 << regno2);
+
+  for (i = 0; i < ARRAY_SIZE (match); i++)
+    if (pair == match[i])
+      return true;
+
+  return false;
+}
 \f
 /* Return the size in bytes of the trampoline code, padded to
    TRAMPOLINE_ALIGNMENT bits.  The static chain pointer and target
@@ -17342,7 +17959,7 @@
      It therefore seems best to switch back to non-MIPS16 mode at
      save time, and to ensure that mips16_globals remains null after
      a PCH load.  */
-  mips_set_mips16_mode (false);
+  mips_set_compression_mode (false);
   mips16_globals = 0;
 }
 \f
Index: config/mips/mips.h
===================================================================
--- config/mips/mips.h	(revision 195900)
+++ config/mips/mips.h	(working copy)
@@ -174,6 +174,9 @@
 #define ISA_HAS_DSP_MULT ISA_HAS_DSPR2
 #endif
 
+/* The ISA compression flags that are currently in effect.  */
+#define TARGET_COMPRESSION (target_flags & (MASK_MIPS16 | MASK_MICROMIPS))
+
 /* Generate mips16 code */
 #define TARGET_MIPS16		((target_flags & MASK_MIPS16) != 0)
 /* Generate mips16e code. Default 16bit ASE for mips32* and mips64* */
@@ -374,7 +377,7 @@
       else								\
 	builtin_define ("__mips_fpr=32");				\
 									\
-      if (mips_base_mips16)						\
+      if (mips_base_compression_flags & MASK_MIPS16)			\
 	builtin_define ("__mips16");					\
 									\
       if (TARGET_MIPS3D)						\
@@ -383,6 +386,9 @@
       if (TARGET_SMARTMIPS)						\
 	builtin_define ("__mips_smartmips");				\
 									\
+      if (mips_base_compression_flags & MASK_MICROMIPS)			\
+	builtin_define ("__mips_micromips");				\
+									\
       if (TARGET_MCU)							\
 	builtin_define ("__mips_mcu");					\
 									\
@@ -702,7 +708,7 @@
        |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
      %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
      %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
-       |march=34k*|march=74k*|march=1004k*: -mips32r2} \
+       |march=34k*|march=74k*|march=m14k*|march=1004k*: -mips32r2} \
      %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
        |march=xlr|march=loongson3a: -mips64} \
      %{march=mips64r2|march=octeon|march=xlp: -mips64r2} \
@@ -716,7 +722,7 @@
   "%{mhard-float|msoft-float|mno-float|march=mips*:; \
      march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
      |march=34kc|march=34kn|march=74kc|march=1004kc|march=5kc \
-     |march=octeon|march=xlr: -msoft-float;		  \
+     |march=m14k*|march=octeon|march=xlr: -msoft-float;		  \
      march=*: -mhard-float}"
 
 /* A spec condition that matches 32-bit options.  It only works if
@@ -989,7 +995,8 @@
 				     || ISA_MIPS64R2))
 
 /* ISA has lwxs instruction (load w/scaled index address.  */
-#define ISA_HAS_LWXS		(TARGET_SMARTMIPS && !TARGET_MIPS16)
+#define ISA_HAS_LWXS		((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
+				 && !TARGET_MIPS16)
 
 /* ISA has lbx, lbux, lhx, lhx, lhux, lwx, lwux, or ldx instruction. */
 #define ISA_HAS_LBX		(TARGET_OCTEON2)
@@ -1123,6 +1130,7 @@
 %{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
 %{mips32*} %{mips64*} \
 %{mips16} %{mno-mips16:-no-mips16} \
+%{mmicromips} %{mno-micromips} \
 %{mips3d} %{mno-mips3d:-no-mips3d} \
 %{mdmx} %{mno-mdmx:-no-mdmx} \
 %{mdsp} %{mno-dsp} \
@@ -1672,6 +1680,8 @@
   ((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define M16_REG_P(REGNO) \
   (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 16 || (REGNO) == 17)
+#define M16STORE_REG_P(REGNO) \
+  (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 0 || (REGNO) == 17)
 #define FP_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
 #define MD_REG_P(REGNO) \
@@ -2034,6 +2044,7 @@
 #define SMALL_INT(X) SMALL_OPERAND (INTVAL (X))
 #define SMALL_INT_UNSIGNED(X) SMALL_OPERAND_UNSIGNED (INTVAL (X))
 #define LUI_INT(X) LUI_OPERAND (INTVAL (X))
+#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))
 
 /* The HI and LO registers can only be reloaded via the general
    registers.  Condition code registers can only be loaded to the
@@ -2452,18 +2463,32 @@
    all calls should use assembly macros.  Otherwise, all indirect
    calls should use "jr" or "jalr"; we will arrange to restore $gp
    afterwards if necessary.  Finally, we can only generate direct
-   calls for -mabicalls by temporarily switching to non-PIC mode.  */
+   calls for -mabicalls by temporarily switching to non-PIC mode.
+
+   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+   instruction is in the delay slot of jal(r).  */
 #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
   (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
    ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
-   : (REG_P (OPERANDS[TARGET_OPNO])				\
-      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
-   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
-      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
    : REG_P (OPERANDS[TARGET_OPNO])				\
-   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"				\
+   ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)		\
+      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
+	 "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
+      : TARGET_MICROMIPS && TARGET_INTERLINK_UNCOMPRESSED	\
+      ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"			\
+      : "%*" INSN "r\t%" #TARGET_OPNO "%/")			\
    : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
-\f
+
+/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
+   "jrc" when nop is in the delay slot of "jr".  */
+
+#define MICROMIPS_J(INSN, OPERANDS, OPNO)			\
+  (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
+   ? "%*j\t%" #OPNO "%/"					\
+   : REG_P (OPERANDS[OPNO])					\
+   ? "%*jr%:\t%" #OPNO						\
+   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #OPNO "%/"))
+
 /* Control the assembler format that we output.  */
 
 /* Output to assembler file text saying following lines
@@ -2877,7 +2902,7 @@
 extern int mips_isa;			/* architectural level */
 extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
-extern bool mips_base_mips16;
+extern unsigned int mips_base_compression_flags;
 extern GTY(()) struct target_globals *mips16_globals;
 #endif
 
Index: config/mips/t-sde
===================================================================
--- config/mips/t-sde	(revision 195900)
+++ config/mips/t-sde	(working copy)
@@ -16,8 +16,8 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16 msoft-float/mfp64 mcode-readable=no
-MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 sof f64 spram
+MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16/mmicromips msoft-float/mfp64 mcode-readable=no
+MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 micromips sof f64 spram
 MULTILIB_MATCHES = EL=mel EB=meb
 
 # The -mfp64 option is only valid in conjunction with -mips32r2.
@@ -33,3 +33,6 @@
 else
 MULTILIB_EXCLUSIONS += mips64/mips16 mips64r2/mips16
 endif
+
+# The -mcode-readable=no is only in conjunction with -mips16.
+MULTILIB_EXCLUSIONS += mcode-readable=no/!mips16

[-- Attachment #4: libgcc.patch --]
[-- Type: application/octet-stream, Size: 2727 bytes --]

Index: Makefile.in
===================================================================
--- Makefile.in	(revision 195931)
+++ Makefile.in	(working copy)
@@ -223,7 +223,7 @@
 # Options to use when compiling libgcc2.a.
 #
 LIBGCC2_DEBUG_CFLAGS = -g
-LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(HOST_LIBGCC2_CFLAGS) \
+LIBGCC2_CFLAGS = $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(HOST_LIBGCC2_CFLAGS) \
 		 $(LIBGCC2_DEBUG_CFLAGS) -DIN_LIBGCC2 \
 		 -fbuilding-libgcc -fno-stack-protector \
 		 $(INHIBIT_LIBC_CFLAGS)
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 195931)
+++ ChangeLog	(working copy)
@@ -1,3 +1,11 @@
+2013-02-08  Catherine Moore  <clm@codesourcery.com>
+	    Joseph Myers  <joseph@codesourcery.com>
+	    Chao-ying Fu  <fu@mips.com>
+
+	* config/mips/mips16.S:  Don't build for microMIPS.
+	* config/mips/linux-unwind.h: Handle microMIPS frame.
+	* config/mips/crtn.S (fini, init): New labels.
+
 2013-02-08  Georg-Johann Lay  <avr@gjlay.de>
 
 	PR target/54222
Index: config/mips/mips16.S
===================================================================
--- config/mips/mips16.S	(revision 195931)
+++ config/mips/mips16.S	(working copy)
@@ -21,6 +21,10 @@
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#ifdef __mips_micromips
+  /* DO NOTHING */
+#else
+
 /* This file contains mips16 floating point support functions.  These
    functions are called by mips16 code to handle floating point when
    -msoft-float is not used.  They accept the arguments and return
@@ -718,3 +722,4 @@
 #endif /* !__mips_single_float */
 
 #endif
+#endif /* __mips_micromips */
Index: config/mips/linux-unwind.h
===================================================================
--- config/mips/linux-unwind.h	(revision 195931)
+++ config/mips/linux-unwind.h	(working copy)
@@ -51,6 +51,11 @@
   _Unwind_Ptr new_cfa, reg_offset;
   int i;
 
+  /* A MIPS16 or microMIPS frame.  Signal frames always use the standard
+     ISA encoding.  */
+  if ((_Unwind_Ptr) pc & 3)
+    return _URC_END_OF_STACK;
+
   /* 24021061 li v0, 0x1061 (rt_sigreturn)*/
   /* 0000000c syscall    */
   /*    or */
Index: config/mips/crtn.S
===================================================================
--- config/mips/crtn.S	(revision 195931)
+++ config/mips/crtn.S	(working copy)
@@ -31,6 +31,7 @@
 #endif
 
 	.section .init,"ax",@progbits
+init:	
 #ifdef __mips64
 	ld      RA,40($sp)
 	daddu	$sp,$sp,48
@@ -41,6 +42,7 @@
 	j	RA
 
 	.section .fini,"ax",@progbits
+fini:	
 #ifdef	__mips64
 	ld	RA,40($sp)
 	daddu	$sp,$sp,48

[-- Attachment #5: libgcc.cl --]
[-- Type: application/octet-stream, Size: 296 bytes --]

2013-02-12  Catherine Moore  <clm@codesourcery.com>
	    Joseph Myers  <joseph@codesourcery.com>
	    Chao-ying Fu  <fu@mips.com>

	* config/mips/mips16.S:  Don't build for microMIPS.
	* config/mips/linux-unwind.h: Handle microMIPS frame.
	* config/mips/crtn.S (fini, init): New labels.


[-- Attachment #6: gcc-testsuite.patch --]
[-- Type: application/octet-stream, Size: 8129 bytes --]

Index: gcc.target/mips/mips.exp
===================================================================
--- gcc.target/mips/mips.exp	(revision 195578)
+++ gcc.target/mips/mips.exp	(working copy)
@@ -238,6 +238,7 @@ set mips_option_groups {
     fp "-mfp(32|64)"
     gp "-mgp(32|64)"
     long "-mlong(32|64)"
+    micromips "-mmicromips|-mno-micromips"
     mips16 "-mips16|-mno-mips16|-mflip-mips16"
     mips3d "-mips3d|-mno-mips3d"
     pic "-f(no-|)(pic|PIC)"
@@ -1246,6 +1247,10 @@ proc mips-dg-options { args } {
 	append extra_tool_flags " -DMIPS16=__attribute__((mips16))"
     }
 
+    if { [mips_have_test_option_p options "-mmicromips"] } {
+	append extra_tool_flags " -DMICROMIPS=__attribute__((micromips))"
+    }
+
     # Use our version of gcc-dg-test for this test.
     if { ![string equal [info procs "mips-gcc-dg-test"] ""] } {
 	rename gcc-dg-test mips-old-gcc-dg-test
@@ -1275,6 +1280,6 @@ proc mips-gcc-dg-test { prog do_what extra_tool_fl
 dg-init
 mips-dg-init
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
-    "-DNOMIPS16=__attribute__((nomips16))"
+    "-DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression)) -DMICROMIPS=__attribute__((micromips))"
 mips-dg-finish
 dg-finish
Index: gcc.target/mips/umips-lwp-swp-1.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-1.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-1.c	(revision 0)
@@ -0,0 +1,19 @@
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
+
+void MICROMIPS
+foo (long long l1, long long *l2)
+{
+  *l2 = l1;
+}
+
+long long MICROMIPS
+bar (long long d)
+{
+  register long long l1 asm ("$8") = d;
+  register long long l2 asm ("$12") = 0;
+  asm ("#foo" : "=r" (l1) : "r" (l1));
+  asm volatile ("#foo" :: "r" (l2));
+  return l1;
+}
+
+/* { dg-final { scan-assembler "\tswp" } */
Index: gcc.target/mips/umips-save-restore-1.c
===================================================================
--- gcc.target/mips/umips-save-restore-1.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-1.c	(revision 0)
@@ -0,0 +1,19 @@
+/* Check that we can use the swm/lwm instructions.  */
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+#include <stdarg.h>
+
+int bar (int, int, int, int, int);
+
+MICROMIPS int
+foo (int n, int a, int b, int c, int d) 
+{
+  int i, j;
+
+  i = bar (n, a, b, c, d);
+  j = bar (n, a, b, c, d);
+  return i + j;
+}
+/* { dg-final { scan-assembler "\tswm\t" } } */
+/* { dg-final { scan-assembler "\tlwm\t" } } */
Index: gcc.target/mips/umips-lwp-swp-2.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
@@ -0,0 +1,19 @@
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
+
+void MICROMIPS
+foo (long long *l1, long long l2)
+{
+  *l1 = l2;
+}
+
+long long MICROMIPS
+bar (long long d)
+{
+  register long long l1 asm ("$8") = d;
+  register long long l2 asm ("$12") = 0;
+  asm ("#foo" : "=r" (l1) : "r" (l1));
+  asm volatile ("#foo" :: "r" (l2));
+  return l1;
+}
+
+/* { dg-final { scan-assembler "\tswp" } */
Index: gcc.target/mips/umips-save-restore-2.c
===================================================================
--- gcc.target/mips/umips-save-restore-2.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-2.c	(revision 0)
@@ -0,0 +1,15 @@
+/* Check that we can use the save instruction to save spilled arguments.  */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *a, int b, int c)
+{
+  asm volatile ("" ::: "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+		"$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16",
+		"$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24",
+		"$25", "$30", "memory");
+  a[b] = 1;
+  a[c] = 1;
+}
+/* { dg-final { scan-assembler "\tswm\t" } } */
+/* { dg-final { scan-assembler "\tlwm\t" } } */
Index: gcc.target/mips/umips-lwp-swp-volatile.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+
+/* This test ensures that we do not generate microMIPS SWP or LWP
+   instructions when any component of the accessed memory is volatile; 
+   they are unsafe for such since they might cause replay of partial 
+   accesses if interrupted by an exception.  */
+
+static void set_csr (volatile void *p, int v)
+{
+  *(volatile int *) (p) = v;
+}
+
+static int get_csr (volatile void *p)
+{
+  return *(volatile int *) (p);
+}
+
+int main ()
+{
+  int i, q = 0, p = 0, r = 0;
+
+  for (i = 0; i < 20; i++)
+    {
+      set_csr ((volatile void *) 0xbf0100a8, 0xffff0002);
+      set_csr ((volatile void *) 0xbf0100a4, 0x80000008);
+    }
+
+  for (i = 0; i < 20; i++)
+    {
+      register int k, j;
+      k = get_csr ((volatile void *) 0xbf0100b8);
+      p += k;
+      j = get_csr ((volatile void *) 0xbf0100b4);
+      r += j;
+      q = j + k;
+    }
+  return q + r + p;
+}
+
+/* { dg-final { scan-assembler-not "\tswp\t\\\$" } } */
+/* { dg-final { scan-assembler-not "\tlwp\t\\\$" } } */
Index: gcc.target/mips/umips-save-restore-3.c
===================================================================
--- gcc.target/mips/umips-save-restore-3.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-3.c	(revision 0)
@@ -0,0 +1,13 @@
+/* Check that we can use the swm instruction to save $16, $17 and $31.  */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void bar (void);
+
+MICROMIPS void
+foo (void)
+{
+  bar ();
+  asm volatile ("" ::: "$16", "$17");
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$17,\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$17,\\\$31" } } */
Index: gcc.target/mips/umips-movep.c
===================================================================
--- gcc.target/mips/umips-movep.c	(revision 0)
+++ gcc.target/mips/umips-movep.c	(revision 0)
@@ -0,0 +1,18 @@
+/* Check that we can use the save instruction to save varargs.  */
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
+
+#include <stdarg.h>
+
+long long bar (long long, long long);
+
+MICROMIPS long long
+foo (long long n, long long a)
+{
+  long long i, j;
+
+  i = bar (n, a);
+  j = bar (n, a);
+  return i + j;
+}
+/* { dg-final { scan-assembler "\tmovep\t" } } */
Index: gcc.c-torture/execute/ieee/ieee.exp
===================================================================
--- gcc.c-torture/execute/ieee/ieee.exp	(revision 195378)
+++ gcc.c-torture/execute/ieee/ieee.exp	(working copy)
@@ -54,6 +54,9 @@ if { [istarget "alpha*-*-*"]
      || [istarget "sh*-*-*"] } then {
   lappend additional_flags "-mieee"
 }
+if [istarget "mips*-sde-*"] then {
+  lappend additional_flags "-Wl,--defsym=__cs3_mips_float_type=2" "-lcs3-mips-cp1" "-lcs3-mips-fpemu"
+}
 
 # load support procs
 load_lib c-torture.exp
Index: ChangeLog
===================================================================
--- ChangeLog	(revision 195904)
+++ ChangeLog	(working copy)
@@ -1,3 +1,14 @@
+2012-02-08  Catherine Moore  <clm@codesourcery.com>
+
+	* gcc.target/mips/mips.exp: Add microMIPS support.
+	* gcc.target/mips/umips-lwp-swp-1.c: New test.
+	* gcc.target/mips/umips-save-restore-1.c: New test.
+	* gcc.target/mips/umips-lwp-swp-2.c: New test.
+	* gcc.target/mips/umips-save-restore-2.c: New test.
+	* gcc.target/mips/umips-lwp-swp-volatile.c: New test.
+	* gcc.target/mips/umips-save-restore-3.c: New test.
+	* gcc.target/mips/umips-movep.c: New test.
+
 2013-02-08  Vladimir Makarov  <vmakarov@redhat.com>
 
 	PR rtl-optimization/56246

[-- Attachment #7: gcc-testsuite.cl --]
[-- Type: application/octet-stream, Size: 471 bytes --]

2012-02-12  Catherine Moore  <clm@codesourcery.com>

	* gcc.target/mips/mips.exp: Add microMIPS support.
	* gcc.target/mips/umips-lwp-swp-1.c: New test.
	* gcc.target/mips/umips-save-restore-1.c: New test.
	* gcc.target/mips/umips-lwp-swp-2.c: New test.
	* gcc.target/mips/umips-save-restore-2.c: New test.
	* gcc.target/mips/umips-lwp-swp-volatile.c: New test.
	* gcc.target/mips/umips-save-restore-3.c: New test.
	* gcc.target/mips/umips-movep.c: New test.


^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-12 19:00           ` Moore, Catherine
@ 2013-02-13 11:43             ` Richard Sandiford
  2013-02-19 16:31               ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-02-13 11:43 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> > Index: config/mips/mips.c
>> >
>> ==========================================================
>> =========
>> > --- config/mips/mips.c	(revision 195351)
>> > +++ config/mips/mips.c	(working copy)
>> > @@ -77,6 +77,9 @@ along with GCC; see the file COPYING3.  If not see
>> >     preserve the maximum stack alignment.  We therefore use a value
>> >     of 0x7ff0 in this case.
>> >
>> > +   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
>> > +   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
>> > +
>> >     MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
>> >     up to 0x7f8 bytes and can usually save or restore all the registers
>> >     that we need to save or restore.  (Note that we can only use these
>> > @@ -87,7 +90,8 @@ along with GCC; see the file COPYING3.  If not see
>> >     to save and restore registers, and to allocate and deallocate the top
>> >     part of the frame.  */
>> >  #define MIPS_MAX_FIRST_STACK_STEP
>> 	\
>> > -  (!TARGET_MIPS16 ? 0x7ff0						\
>> > +  ((!TARGET_MIPS16 && !TARGET_MICROMIPS) ? 0x7ff0
>> 	\
>> > +   : TARGET_MICROMIPS ? 0x7f0
>> 	\
>> >     : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8
>> 	\
>> >     : TARGET_64BIT ? 0x100 : 0x400)
>> 
>> I'd prefer:
>> 
>>   (TARGET_MICROMIPS ? 0x7f0						\
>>    : !TARGET_MIPS16 ? 0x7ff0						\
>>    : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8			 	\
>>    : TARGET_64BIT ? 0x100 : 0x400)

Thanks for doing this, but...

>> The comment doesn't really explain the reason for 0x7f0 rather than 0x7f8.
>> Is this in anticipation of future n32 and n64 support, where the stack must be
>> 16-byte aligned?  If so, that's OK, but worth mentioning.

...it looks like you haven't addressed this part.  What I mean is:
the stack alignment is 8 bytes rather than 16 bytes on 32-bit ABIs,
so I would have expected 0x7f8 rather than 0x7f0, as for the MIPS16
case quoted above.  I wasn't sure why you went for 0x7f0 instead.

I'm not saying it must be 0x7f8, just that the comment ought to give
the reason for using 0x7f0 instead.

>> > +; For movep
>> > +(define_peephole2
>> > +  [(set (match_operand:MOVEP1 0 "register_operand" "")
>> > +        (match_operand:MOVEP1 1 "movep_operand" ""))
>> > +   (set (match_operand:MOVEP2 2 "register_operand" "")
>> > +        (match_operand:MOVEP2 3 "movep_operand" ""))]
>> > +  "TARGET_MICROMIPS
>> > +   && umips_movep_target_p (operands[0], operands[2])"
>> > +  [(parallel [(set (match_dup 0) (match_dup 1))
>> > +              (set (match_dup 2) (match_dup 3))])]
>> > +)
>> 
>> Probably not worth having movep_operand, because all the checking is done
>> by umips_movep_target_p.  reg_or_0_operand should be OK.      
>
> The source and target register criteria are not identical.  I've now
> renamed the movep_operand predicate to movep_src_operand.

Ah, yeah, sorry.

>> > +      /* If DECL is "nocompression" set the "nomips16" and
>> > +	 "nomicromips" attributes.  */
>> > +      if (nocompression_p & MASK_MIPS16
>> > +          && nocompression_p & MASK_MICROMIPS)
>> > +	{
>> > +	  name = "nomips16";
>> > +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
>> > +	  name = "nomicromips";
>> > +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
>> > +	}
>> 
>> Hmm, why is this necessary?  Anything that cares should be using
>> mips_get_compress_off_flags.

It looks like you haven't addressed this part.  Why do we need to add
tree-level "nomips16" and "nomicromips" attributes to a function that
has "nocompression"?

>> > +	  && addr.type == ADDRESS_REG
>> > +	  && CONST_INT_P (addr.offset)
>> > +	  && UMIPS_12BIT_OFFSET_P (addr.offset));
>> 
>> Isn't there a missing INTVAL here?  Please check the patch to make sure
>> there are no compiler warnings.

This too.  The point is that addr.offset is an rtx, while UMIPS_12BIT_OFFSET_P
takes a HOST_WIDE_INT:

#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))

So you're comparing an rtx pointer against [-2048, 2047], rather than
the integer that the rtx contains.

As it stands, I don't see how umips_12bit_offset_address_p would ever
return true on normal hosts.  That in turn should mean that ZC and ZD
never accept anything for microMIPS, so I would have expected this to
show up as a reload failure during the microMIPS testsuite run.

Please add tests that ZC and ZD work for microMIPS.  E.g. the ZC
one could be something like:

   MICROMIPS void
   foo (int *x)
   {
     asm volatile ("insn1\t%0" :: "ZC" (x[0]));
     asm volatile ("insn2\t%0" :: "ZC" (x[511]));
     asm volatile ("insn3\t%0" :: "ZC" (x[512]));
   }

   /* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
   /* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
   /* { dg-final { scan-assembler-not "\tinsn3\t2048\\(" } } */

Completely untested :-)  Similar idea for ZD.

> +@item -minterlink-compressed
> +@item -mno-interlink-compressed
> +@item -minterlink-uncompressed
> +@item -mno-interlink-uncompressed
> +@opindex minterlink-compressed
> +@opindex mno-interlink-compressed
> +@opindex minterlink-compressed
> +@opindex mno-interlink-compressed
> +Require (do not require) that code using the standard (uncompressed) MIPS ISA
> +be link-compatible with MIPS16 and microMIPS code, and vice versa.

What I meant in my previous reply was that there should be only one
set of options.  I.e. everything would use -minterlink-compressed and
-mno-interlink-compressed.  There would be no -minterlink-uncompressed/
-mno-interlink-uncompressed

Sorry for going back on the earlier -mno-jals suggestion here,
but I hadn't realised until I saw the previous patch just how
confusing it would be to have both.

> +@item ZC
> +When compiling microMIPS code, this constraing matches a memory operand

s/constraing/constraint/

> +@item ZD
> +When compiling microMIPS code, this constraint matches an address operand
> +that is formed from a base register and a 12-bit offset.  These operands
> +can be used for microMIPS instructions such as @code{prefetch}.  When
> +not compiling for microMIPS code, @code{YC} is equivalent to @code{p}.

s/YC/ZD/

> Index: config/mips/gnu-user.h
> ===================================================================
> --- config/mips/gnu-user.h	(revision 195900)
> +++ config/mips/gnu-user.h	(working copy)
> @@ -137,3 +137,12 @@
>  #define ENDFILE_SPEC \
>    GNU_USER_TARGET_MATHFILE_SPEC " " \
>    GNU_USER_TARGET_ENDFILE_SPEC
> +
> +#undef SUBTARGET_OVERRIDE_OPTIONS
> +#define SUBTARGET_OVERRIDE_OPTIONS                              \
> +do {                                                            \
> +  /* microMIPS PLT entries are non-microMIPS.  */               \
> +  TARGET_INTERLINK_UNCOMPRESSED = 1;   				\
> +} while (0)

Please leave this out.  As discussed, we'll rely on Maciej's linker
patch to handle PLTs.

> Index: config/mips/micromips.md
> ===================================================================
> --- config/mips/micromips.md	(revision 0)
> +++ config/mips/micromips.md	(revision 0)
> @@ -0,0 +1,108 @@
> +(define_insn "*store_word_multiple"

Sorry, forgot to say earlier, but this needs a copyright header.  Also:

;; The behaviour of SWM is undefined if placed in a delay slot.

(Sorry for the extremely minor nit, but I prefer caps for mnemonics,
like in the manual.  Please update the others too.)

> +(define_insn "*load_word_multiple"
> +  [(match_parallel 0 ""
> +       [(set (match_operand:SI 1 "register_operand")
> +	     (match_operand:SI 2 "memory_operand"))])]
> +  "TARGET_MICROMIPS
> +   && umips_save_restore_pattern_p (false, operands[0])"
> +  { return umips_output_save_restore (false, operands[0]); }
> +  [(set_attr "type" "multimem")
> +   (set_attr "mode" "SI")
> +   (set_attr "can_delay" "no")])

;; The behaviour of LWM is undefined if placed in a delay slot.

> +; For lwp
> +(define_peephole2

;; For LWP.

(Two semicolons, period at the end.)

> +  [(set (match_operand:SI 0 "d_operand" "")
> +        (match_operand:SI 1 "non_volatile_mem_operand" ""))
> +   (set (match_operand:SI 2 "d_operand" "")
> +        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
> +  "TARGET_MICROMIPS
> +   && umips_load_store_pair_p (true, operands)"
> +  [(parallel [(set (match_dup 0) (match_dup 1))
> +              (set (match_dup 2) (match_dup 3))])]
> +)
> +
> +;;  The behavior of the lwp insn is undefined if placed in a delay slot.

Single space after ";;".

> +; For swp

;; For SWP.

> +(define_insn "*swp"

;; The behaviour of SWP is undefined if placed in a delay slot.

> +; For movep

;; For MOVEP.

> +;;  The behavior of the movep insn is undefined if placed in a delay slot.

Single space after ";;" rather than two.

> +(define_memory_constraint "ZC"
> +  "When compiling microMIPS code, this constraing matches a memory operand

s/constraing/constraint/

> +   whose address is formed from a base register and a 12-bit offset.  These
> +   operands can be used for microMIPS instructions such as @code{ll} and
> +   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
> +   equivalent to @code{R}."
> +  (and (match_code "mem")
> +       (ior (and (match_test "TARGET_MICROMIPS")
> +		 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)"))
> +	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
> +
> +(define_address_constraint "ZD"
> +  "When compiling microMIPS code, this constraint matches an address operand
> +   that is formed from a base register and a 12-bit offset.  These operands
> +   can be used for microMIPS instructions such as @code{prefetch}.  When
> +   not compiling for microMIPS code, @code{YC} is equivalent to @code{p}."

s/YC/ZD/

> +(define_predicate "movep_src_register"
> +  (and (match_code "reg")
> +       (ior (match_test ("IN_RANGE (REGNO (op), 0, 3)"))
> +	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))

s/0, 3/2, 3/.  $1 isn't valid, and $0 should always be represented
as zero in RTL.

> @@ -451,10 +458,17 @@
>  	  ;; from the shorten_branches reference address.
>  	  (and (eq_attr "type" "branch")
>  	       (not (match_test "TARGET_MIPS16")))
> -	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
> -		      (le (minus (pc) (match_dup 0)) (const_int 131068)))
> +	  	 ;; any variant can handle the 17-bit range
> +	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 65532))
> +		      (le (minus (pc) (match_dup 0)) (const_int 65534)))
>  		   (const_int 4)

Formatting:
	  	 
	  (cond [;; Any variant can handle the 17-bit range.
		 (and (le (minus (match_dup 0) (pc)) (const_int 65532))
		      (le (minus (pc) (match_dup 0)) (const_int 65534)))
		   (const_int 4)

> +		 ;; The 18-bit range is OK other than for microMIPS.
> +		 (and (eq (symbol_ref "TARGET_MICROMIPS") (const_int 0))

(not (match_test "TARGET_MICROMIPS"))

> @@ -5445,12 +5462,35 @@
>  			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
>  	 (label_ref (match_operand 0 "" ""))
>  	 (pc)))]
> -  "!TARGET_MIPS16"
> +  "!TARGET_MIPS16 && !TARGET_MICROMIPS"
>  {
>    return mips_output_conditional_branch (insn, operands,
>  					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
>  					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
>  }
> +  [(set_attr "type" "branch")
> +   (set_attr "mode" "none")])
> +
> +(define_insn "*branch_equality<mode>_micromips"
> +  [(set (pc)
> +	(if_then_else
> +	 (match_operator 1 "equality_operator"
> +			 [(match_operand:GPR 2 "register_operand" "d")
> +			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
> +	 (label_ref (match_operand 0 "" ""))
> +	 (pc)))]
> +  "TARGET_MICROMIPS"
> +{
> +  /* For a simple bnez or beqz microMIPS branch.  */
> +  if (operands[3] == const0_rtx && get_attr_length (insn) <= 8)
> +    return mips_output_conditional_branch (insn, operands,
> +					   "%*b%C1z%:\t%2,%0",
> +					   "%*b%N1z%:\t%2,%0");
> +
> +  return mips_output_conditional_branch (insn, operands,
> +					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
> +					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
> +}

The pattern and the fallback case look the same as for !TARGET_MICRORMIPS.
I think we should use the existing *branch_equality<mode> for microMIPS
and just add:

  /* For a simple BNEZ or BEQZ microMIPS branch.  */
  if (TARGET_MICROMIPS
      && operands[3] == const0_rtx
      && get_attr_length (insn) <= 8)
    return mips_output_conditional_branch (insn, operands,
					   "%*b%C1z%:\t%2,%0",
					   "%*b%N1z%:\t%2,%0");

> @@ -5461,7 +5501,7 @@
>  			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
>  	 (pc)
>  	 (label_ref (match_operand 0 "" ""))))]
> -  "!TARGET_MIPS16"
> +  "!TARGET_MIPS16 && !TARGET_MICROMIPS"
>  {
>    return mips_output_conditional_branch (insn, operands,
>  					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
> @@ -5532,6 +5572,29 @@
>  		      (label_ref (match_operand 1))
>  		      (pc)))])
> 
> +(define_insn "*branch_equality<mode>_inverted_micromips"
> +  [(set (pc)
> +	(if_then_else
> +	 (match_operator 0 "equality_operator"
> +			 [(match_operand:GPR 2 "register_operand" "d")
> +			  (match_operand:GPR 3 "reg_or_0_operand" "dJ")])
> +	 (pc)
> +	 (label_ref (match_operand 1 "" ""))))]
> +  "TARGET_MICROMIPS"
> +{
> +  /* For a simple bnez or beqz microMIPS branch.  */
> +  if (operands[3] == const0_rtx && get_attr_length (insn) <= 8)
> +    return mips_output_conditional_branch (insn, operands,
> +					   "%*b%N0z%:\t%2,%1",
> +					   "%*b%C0z%:\t%2,%1");
> +
> +  return mips_output_conditional_branch (insn, operands,
> +					 MIPS_BRANCH ("b%N0", "%2,%z3,%1"),
> +					 MIPS_BRANCH ("b%C0", "%2,%z3,%1"));
> +}
> +  [(set_attr "type" "branch")
> +   (set_attr "mode" "none")])
> +

Same comment here.

> @@ -6350,7 +6435,12 @@
>    [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
>  	 (match_operand 1 "" ""))]
>    "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
> -  { return MIPS_CALL ("j", operands, 0, 1); }
> +  {
> +    if (TARGET_MICROMIPS)
> +      return MICROMIPS_J ("j", operands, 0);
> +    else
> +      return MIPS_CALL ("j", operands, 0, 1);
> +  }

Please put the multiline { ... } block in column 0:

{
  if (TARGET_MICROMIPS)
    return MICROMIPS_J ("j", operands, 0);
  else
    return MIPS_CALL ("j", operands, 0, 1);
}

(You did this in the bits I snipped, thanks.)

> @@ -6371,7 +6461,12 @@
>          (call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
>                (match_operand 2 "" "")))]
>    "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
> -  { return MIPS_CALL ("j", operands, 1, 2); }
> +  {
> +    if (TARGET_MICROMIPS)
> +      return MICROMIPS_J ("j", operands, 1);
> +    else
> +      return MIPS_CALL ("j", operands, 1, 2);
> +  }
>    [(set_attr "jal" "indirect,direct")
>     (set_attr "jal_macro" "no")])

Same here.
 
> @@ -6383,7 +6478,12 @@
>  	(call (mem:SI (match_dup 1))
>  	      (match_dup 2)))]
>    "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
> -  { return MIPS_CALL ("j", operands, 1, 2); }
> +  {
> +    if (TARGET_MICROMIPS)
> +      return MICROMIPS_J ("j", operands, 1);
> +    else
> +      return MIPS_CALL ("j", operands, 1, 2);
> +  }

Same here.

> Index: config/mips/mips.c
> ===================================================================
> --- config/mips/mips.c	(revision 195900)
> +++ config/mips/mips.c	(working copy)
> @@ -77,6 +77,9 @@
>     preserve the maximum stack alignment.  We therefore use a value
>     of 0x7ff0 in this case.
 
> +   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
> +   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
> +
>     MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
>     up to 0x7f8 bytes and can usually save or restore all the registers
>     that we need to save or restore.  (Note that we can only use these
> @@ -86,8 +89,10 @@
>     RESTORE are not available.  We can then use unextended instructions
>     to save and restore registers, and to allocate and deallocate the top
>     part of the frame.  */
> +

No extra whitespace.

> +/*  Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
> +    flags FLAGS.  */

Too much indentation:

/* Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
   flags FLAGS.  */

> +/* Return the set of compression modes that are explicitly required
> +   by DECL.  */
> +
> +static unsigned int
> +mips_get_compress_on_flags (tree decl)
>  {
> +  unsigned int flags = 0;
> +
> +  if (lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL)
> +    flags |= MASK_MIPS16;
> +
> +  if (lookup_attribute ("micromips", DECL_ATTRIBUTES (decl)) != NULL)
> +    flags |= MASK_MICROMIPS;
> +
> +  return flags;
> +}
> +
> +/* Return the set of compression modes that are explicitly forbidden
> +   by DECL.  */
> +
> +static unsigned int
> +mips_get_compress_off_flags (tree decl)
> +{
> +  unsigned int flags = 0;
> +
> +  if (lookup_attribute ("nocompression", DECL_ATTRIBUTES (decl)) != NULL)
> +    flags |= MASK_MIPS16 | MASK_MICROMIPS;
> +
> +  if (lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL)
> +    flags |= MASK_MIPS16;
> +
> +  if (lookup_attribute ("nomicromips", DECL_ATTRIBUTES (decl)) != NULL)
> +    flags |= MASK_MICROMIPS;
> +
> +  return flags;
> +}

This and...

> +/* Set compression flags based on attributes.  */
> +
> +static unsigned int
> +mips_get_compression_attrs (tree *attributes)
> +{
> +  unsigned int compression_flags = 0;
> +  if (lookup_attribute ("mips16", *attributes) != NULL)
> +    compression_flags |= MASK_MIPS16;
> +  if (lookup_attribute ("micromips", *attributes) != NULL)
> +    compression_flags |= MASK_MICROMIPS;
> +  return compression_flags;
> +}
> +
> +/* Set nocompression flags based on attributes.  */
> +
> +static unsigned int
> +mips_get_nocompression_attrs (tree *attributes)
> +{
> +  unsigned int nocompression_flags = 0;
> +
> +  if (lookup_attribute ("nomips16", *attributes) != NULL)
> +    nocompression_flags |= MASK_MIPS16;
> +  if (lookup_attribute ("nomicromips", *attributes) != NULL)
> +    nocompression_flags |= MASK_MICROMIPS;
> +  if (lookup_attribute ("nocompression", *attributes) != NULL)
> +    nocompression_flags |= MASK_MICROMIPS | MASK_MIPS16;
> +  return nocompression_flags;
> +}

...this are really duplicates of each other.  Let's just have one.

/* Return the set of compression modes that are explicitly required
   by ATTRIBUTES.  */

static unsigned int
mips_get_compress_on_flags (tree attributes)
{
  unsigned int flags = 0;

  if (lookup_attribute ("mips16", attributes) != NULL)
    flags |= MASK_MIPS16;

  if (lookup_attribute ("micromips", attributes) != NULL)
    flags |= MASK_MICROMIPS;

  return flags;
}

/* Return the set of compression modes that are explicitly forbidden
   by ATTRIBUTES.  */

static unsigned int
mips_get_compress_off_flags (tree attributes)
{
  unsigned int flags = 0;

  if (lookup_attribute ("nocompression", attributes) != NULL)
    flags |= MASK_MIPS16 | MASK_MICROMIPS;

  if (lookup_attribute ("nomips16", attributes) != NULL)
    flags |= MASK_MIPS16;

  if (lookup_attribute ("nomicromips", attributes) != NULL)
    flags |= MASK_MICROMIPS;

  return flags;
}

Then pass DECL_ATTRIBUTES (decl) when we have a decl.

> +      /* If DECL is "nocompression" set the "nomips16" and 
> +	 "nomicromips" attributes.  */
> +      if (nocompression_flags & MASK_MIPS16
> +          && nocompression_flags & MASK_MICROMIPS)
>  	{
> -	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
> -	  if (mips16_p && nomips16_p)
> -	    error ("%qE cannot have both %<mips16%> and "
> -		   "%<nomips16%> attributes",
> -		   DECL_NAME (decl));
> +	  name = "nomips16";
> +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> +	  name = "nomicromips";
> +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
>  	}

As above, I don't think we want this.

> -      else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
> +     else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))

The original indentation was correct.

>  	{
>  	  /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
>  	     "mips16" attribute, arbitrarily pick one.  We must pick the same
>  	     setting for duplicate declarations of a function.  */
>  	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
> +	  name = "nomips16";
> + 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> +	  name = "nomicromips";
>  	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> -	}
> + 	}

This looks wrong; it unconditionally overrides the first "name" assignment.

The point is that we want to alternately add "nomips16" and "mips16"
attributes to functions that have neither.  I think this should be:

     if (TARGET_FLIP_MIPS16
         && !DECL_ARTIFICIAL (decl)
         && compression_flags == 0
         && nocompression_flags == 0)
       {
         ...existing block...
       }

> +/* Return true if X is a legitimate address with a 12-bit offset.
> +   MODE is the mode of the value being accessed.  */
> +
> +bool
> +umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
> +{
> +  struct mips_address_info addr;
> +
> +  return (mips_classify_address (&addr, x, mode, false)
> +	  && addr.type == ADDRESS_REG
> +	  && CONST_INT_P (addr.offset)
> +	  && UMIPS_12BIT_OFFSET_P (addr.offset));

As mentioned above, this is missing an INTVAL:

	&& UMIPS_12BIT_OFFSET_P (INTVAL (addr.offset)));

> +/* Return true if a call to DECL may need to use JALX.  */
> +
> +static bool
> +mips_call_may_need_jalx_p (tree decl)
> +{
> +  /* If the current translation unit would use a different mode for DECL,
> +     assume that the call needs JALX.  */
> +  if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
> +    return true;
> +
> +  /* mips_get_compress_mode is always accurate for locally-binding
> +     functions in the current translation unit.  */
> +  if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
> +    return false;
> +
> +  /* PLTs use the standard encoding, so calls that might go via PLTs
> +     must use JALX.  */
> +  if (TARGET_COMPRESSION
> +      && TARGET_ABICALLS_PIC0
> +      && DECL_EXTERNAL (decl)
> +      && !targetm.binds_local_p (decl))
> +    return true;

As before, please leave the PLT block out; we'll rely on Maciej's linker
patch instead.

>  /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
 
>  static bool
>  mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
>  {
> +
> +  unsigned int compression_mode = mips_get_compress_mode (decl);

No blank line here.

> @@ -6916,22 +7095,43 @@
>    if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
>      return false;
 
> +  if (TARGET_MICROMIPS)
> +    {
> +
> +      /* We can't do a sibcall if the called function isn't microMIPS.  */
> +      if (decl
> +	  && (compression_mode & MASK_MICROMIPS) == 0
> +	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
> +	return false;
> +
> +      /* Direct Js are only possible to functions that use the same ISA
> +	 encoding.  There is no JX counterpoart of JALX.  */
> +      if (decl
> +	  && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
> +	  && mips_call_may_need_jalx_p (decl))
> +	return false;
> +
> +      /* Otherwise OK.  */
> +      return true;
> +    }
> +
>
>    /* We can't do a sibcall if the called function is a MIPS16 function
>       because there is no direct "jx" instruction equivalent to "jalx" to
>       switch the ISA mode.  We only care about cases where the sibling
>       and normal calls would both be direct.  */
>    if (decl
> -      && mips_use_mips16_mode_p (decl)
> +      && ((compression_mode & (MASK_MIPS16 | MASK_MICROMIPS)) != 0)
>        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
>      return false;
 
> -  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
> -     functions could be MIPS16 ones unless an attribute explicitly tells
> +  /* When -minterlink-compressed is in effect, assume that non-locally-binding
> +     functions could be MIPS16 or microMIPS unless an attribute explicitly tells
>       us otherwise.  */
> -  if (TARGET_INTERLINK_MIPS16
> +  if (TARGET_INTERLINK_COMPRESSED
>        && decl
>        && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
> -      && !mips_nomips16_decl_p (decl)
> +      && (compression_mode & MASK_MICROMIPS) == 0
> +      && (compression_mode & MASK_MIPS16) == 0
>        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
>      return false;
 
The idea was that all this ("if (TARGET_MICROMIPS)" onwards) would be
replaced by a call to mips_call_may_need_jalx_p.  I.e.:

  if (decl
      && mips_call_may_need_jalx_p (decl)
      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
    return false;

> +/* Save register REG to MEM.  Make the instruction frame-related.  */
> +
> +static void
> +mips_save_reg (rtx reg, rtx mem)
> +{
> +  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
> +    {
> +      rtx x1, x2;
> +
> +      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
> +
> +      x1 = mips_frame_set (mips_subword (mem, false),
> +			   mips_subword (reg, false));
> +      x2 = mips_frame_set (mips_subword (mem, true),
> +			   mips_subword (reg, true));
> +      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
> +    }
> +  else
> +    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
> +}
> +
> +

Just one blank line between functions.

> +/* Capture the register combinations that are allowed in a swm or lwm
> +   instruction.  The entries are ordered by number of registers set in
> +   the mask.  We also ignore the single register encodings because a
> +   normal sw/lw is preferred.  */

As above, please use caps for instruction names.

> +   
> +static const unsigned int umips_swm_mask[17] = {
> + 0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
> + 0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,	
> + 0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
> + 0x000f0000, 0x80030000, 0x00070000, 0x80010000,
> + 0x00030000 };
> +
> +static const unsigned int umips_swm_encoding[17] = {
> + 25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2 };
> +
> +

Indent the conents of { ... } by two spaces rather than one.  "};"
should go on its own line.

Just one blank line after "umips_swm_encoding".

> +/* Try to use a microMIPS LWM or SWM instruction to save or restore
> +   as many GPRs in *MASK as possible.  *OFFSET is the offset from the
> +   stack pointer of the topmost save slot.
> +
> +   Remove from *MASK all registers that were handled using LWM and SWM.
> +   Update *OFFSET so that it points to the first unused save slot.  */
> +
> +static bool
> +umips_build_save_restore (mips_save_restore_fn fn,
> +			  unsigned *mask, HOST_WIDE_INT *offset)
> +{
> +  int i, nregs;
> +  unsigned int j;
> +  rtx pattern, set, reg, mem;
> +  HOST_WIDE_INT this_offset;
> +  rtx this_base;
> +
> +  /* Try matching $16 to $31 (s0 to ra).  */
> +  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
> +    if ((*mask & 0xffff0000) == umips_swm_mask[i])
> +      break;
> +
> +  if (i == ARRAY_SIZE (umips_swm_mask))
> +    return false;
> +
> +  /* Adjust offset for output.  */
> +  nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
> +  *offset -= (UNITS_PER_WORD * (nregs - 1));
> +
> +  /* LWM/SWM can only support offsets from -2048 to 2047.  */
> +  if (!UMIPS_12BIT_OFFSET_P (*offset))
> +    return false;

This changes "*offset" even on a false return.  Please use:

  /* Work out the offset of the first register.  */
  nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
  this_offset = *offset - UNITS_PER_WORD * (nregs - 1);

  /* LWM/SWM can only support offsets from -2048 to 2047.  */
  if (!UMIPS_12BIT_OFFSET_P (this_offset))
    return false;

> +  /* Create the final PARALLEL.  */
> +  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs));
> +
> +  this_base = stack_pointer_rtx;
> +  this_offset = *offset;
> +
> +  /* For registers $16-$23 and $30.  */
> +  for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
> +    {
> +      unsigned int regno;
> +      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
> +      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
> +      regno = (j != 8) ? 16 + j : 30;
> +      *mask &= 0 << regno;

*mask &= ~(1 << regno);

("*mask &= 0 << regno" sets *mask to 0).

> +      reg = gen_rtx_REG (SImode, regno);
> +      if (fn == mips_save_reg)
> +	set = mips_frame_set (mem, reg);
> +      else
> +	{
> +	  set = gen_rtx_SET (VOIDmode, reg, mem);
> +	  mips_add_cfa_restore (reg);
> +	}
> +      XVECEXP (pattern, 0, j) = set;
> +    }
> +
> +  /* For register $31.  */
> +  if (umips_swm_encoding[i] >> 4)
> +    {
> +      long long offset = this_offset + j * UNITS_PER_WORD;
> +      *mask &= 0 << 31;

Same here.  Also, HOST_WIDE_INT rather than "long long".

> +      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
> +      reg = gen_rtx_REG (SImode, 31);
> +      if (fn == mips_save_reg)
> +	set = mips_frame_set (mem, reg);
> +      else
> +	{
> +	  set = gen_rtx_SET (VOIDmode, reg, mem);
> +	  mips_add_cfa_restore (reg);
> +	}
> +      XVECEXP (pattern, 0, j) = set;
> +    }
> +
> +  pattern = emit_insn (pattern);
> +  if (fn == mips_save_reg)
> +    RTX_FRAME_RELATED_P (pattern) = 1;  
> +
> +  /* Adjust the last offset.  */
> +  offset -= UNITS_PER_WORD;

After the change above, this becaomes:

  *offset -= UNITS_PER_WORD * nregs;

> @@ -10245,16 +10585,21 @@
>  				 mips_save_restore_fn fn)
>  {
>    enum machine_mode fpr_mode;
> -  HOST_WIDE_INT offset;
>    int regno;
> +  const struct mips_frame_info *frame = &cfun->machine->frame;
> +  HOST_WIDE_INT offset = frame->gp_sp_offset - sp_offset;
> +  unsigned int mask = frame->mask;
 
>    /* Save registers starting from high to low.  The debuggers prefer at least
>       the return register be stored at func+4, and also it allows us not to
>       need a nop in the epilogue if at least one register is reloaded in
>       addition to return address.  */
> -  offset = cfun->machine->frame.gp_sp_offset - sp_offset;

Please keep this as it is and set up "mask" here too.  Now that we're C++,
there's no need to move everything to the head of the function.

> @@ -16233,7 +16560,7 @@
>    align_jumps = mips_base_align_jumps;
>    align_functions = mips_base_align_functions;
 
> -  if (mips16_p)
> +  if (compression_mode & MASK_MIPS16)
>      {
>        /* Switch to MIPS16 mode.  */
>        target_flags |= MASK_MIPS16;
> @@ -16288,8 +16615,15 @@
>    else
>      {
>        /* Switch to normal (non-MIPS16) mode.  */
> -      target_flags &= ~MASK_MIPS16;
> +      target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
> +      target_flags |= compression_mode;

This part:

   target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
   target_flags |= compression_mode;

should go before:

  if (compression_mode & MASK_MIPS16)

replacing both:

      target_flags |= MASK_MIPS16;

and:

      target_flags &= ~MASK_MIPS16;

"Switch to normal (non-MIPS16) mode." should become "Switch to microMIPS
or the standard encoding."

> +      if (TARGET_MICROMIPS)
> +	{
> +	  /* Avoid branch likely.  */
> +	  target_flags &= ~MASK_BRANCHLIKELY;
> +	}

Redundant { ... }

>  static void
>  mips_set_current_function (tree fndecl)
>  {
> -  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
> +

There shouldn't be a blank line here.

> +  unsigned int compression_p = mips_get_compress_mode (fndecl);
> +
> +  mips_set_compression_mode (compression_p & (MASK_MIPS16 | MASK_MICROMIPS));

This should just be:

  mips_set_compression_mode (mips_get_compress_mode (fndecl));

> -     Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
> -     MIPS16 mode afterwards if need be.  */
> -  mips_set_mips16_mode (false);
> +     Do all CPP-sensitive stuff in non-MIPS16/non-microMIPS mode;

"uncompressed" rather than "non-MIPS16/non-microMIPS".

> +     We'll switch modes later if required.  */
> +  mips_set_compression_mode (false);

0 rather than false.

> +
> +
> +/* Return true if PATTERN matches the kind of instruction generated by
> +   umips_build_save_restore.  SAVE_P is true for store.  */

Only one blank line between functions.

> +
> +bool
> +umips_save_restore_pattern_p (bool save_p, rtx pattern)
> +{
> +  int n;
> +  unsigned int i;
> +  HOST_WIDE_INT first_offset = 0;
> +  rtx first_base = 0;
> +  unsigned int regmask = 0;
> +
> +  for (n = 0; n < XVECLEN (pattern, 0); n++)
> +    {
> +      rtx set, reg, mem, this_base;
> +      HOST_WIDE_INT this_offset;
> +      unsigned int this_regno;
> +
> +      /* Check that we have a SET.  */
> +      set = XVECEXP (pattern, 0, n);
> +      if (GET_CODE (set) != SET)
> +	return false;
> +
> +      /* Check that the SET is a load (if restoring) or a store
> +	 (if saving).  */
> +      mem = save_p ? SET_DEST (set) : SET_SRC (set);
> +      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
> +	return false;
> +
> +      /* Check that the address is the sum of base and a possibly-zero
> +	 constant offset.  Determine if the offset is in range.  */
> +      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
> +      if (!REG_P (this_base))
> +	return false;
> +
> +      if (n == 0)
> +	{
> +	  if (!UMIPS_12BIT_OFFSET_P (this_offset))
> +	    return false;
> +	  first_base = this_base;
> +	  first_offset = this_offset;
> +	}
> +      else
> +	{
> +	  /* Check that the save slots are consecutive.  */
> +	  if (REGNO (this_base) != REGNO (first_base)
> +	      || this_offset != first_offset + UNITS_PER_WORD * n)
> +	    return false;
> +	}
> +
> +      /* Check that SET's other operand is a register.  */
> +      reg = save_p ? SET_SRC (set) : SET_DEST (set);
> +      if (!REG_P (reg))
> +	return false;
> +
> +      this_regno = REGNO (reg);
> +      regmask |= 1 << this_regno;

I'd prefer just:

      regmask |= 1 << REGNO (reg);

I don't think the this_regno temporary buys anything.

> +/* Return true if MEM1 and MEM2 use the same base register, and the
> +   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
> +   register into (from) which the contents of MEM1 will be loaded
> +   (stored), depending on the value of LOAD_P.
> +   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
> +
> +static bool
> +umips_load_store_pair_p_1 (bool load_p, bool swap_p, rtx first_reg,
> +			   rtx mem1, rtx mem2)
> +{
> +  rtx base1, base2;
> +  HOST_WIDE_INT offset1, offset2;
> +
> +  if (!MEM_P (mem1) || !MEM_P (mem2))
> +    return false;
> +
> +  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
> +  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
> +
> +  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
> +    return false;
> +
> +  /* Avoid invalid load pair instructions.  */
> +  if (load_p && REGNO (first_reg) == REGNO (base1))
> +    return false;
> +
> +  /* We must avoid this case for anti-dependence.
> +     Ex:  lw $3, 4($3)
> +          lw $2, 0($3)
> +     first_reg is $2, but the base is $3.  */
> +  if (load_p
> +      && swap_p
> +      && REGNO (first_reg) + 1 == REGNO (base1))
> +    return false;
> +
> +  if (swap_p
> +      && offset2 + 4 != offset1)
> +    return false;
> +
> +  if (!swap_p
> +      && offset1 + 4 != offset2)
> +    return false;
> +
> +  if (!UMIPS_12BIT_OFFSET_P (offset1))
> +    return false;

Looks like this tests the wrong offset in the swap_p case.  offset2 is
the one that will be used in the instruction.

I think it would be easier to swap MEM1 and MEM2 around when calling
this function with SWAP_P true.  Then the last three conditions become:

  if (offset2 != offset1 + 4)
    return false;

  if (!UMIPS_12BIT_OFFSET_P (offset1))
    return false;

This also makes the function behave in the way that the comment above says
(it says that MEM2 must be 4 bytes after MEM1).

I.e swap mem1 and mem2...

> +  if (REGNO (reg1) == REGNO (reg2) + 1)
> +    return umips_load_store_pair_p_1 (load_p, true, reg2, mem1, mem2);

...here.

> +/* Return true if reg1 and reg2 match the criteria for a movep insn.  */
> +
> +bool
> +umips_movep_target_p (rtx reg1, rtx reg2)

REG1 and REG2 (caps) in the comment.

> +{
> +  int regno1, regno2, pair;
> +  unsigned int i;
> +  static const int match[8] = {
> +   0x00000060,	/* 5, 6 */
> +   0x000000a0,	/* 5, 7 */
> +   0x000000c0,	/* 6, 7 */
> +   0x00200010,	/* 4, 21 */
> +   0x00400010,	/* 4, 22 */
> +   0x00000030,	/* 4, 5 */
> +   0x00000050,  /* 4, 6 */
> +   0x00000090   /* 4, 7 */
> +  };

Two spaces of indentation in match[8] = { ... };

> @@ -17342,7 +17959,7 @@
>       It therefore seems best to switch back to non-MIPS16 mode at
>       save time, and to ensure that mips16_globals remains null after
>       a PCH load.  */
> -  mips_set_mips16_mode (false);
> +  mips_set_compression_mode (false);

0 rather than false.

> Index: Makefile.in
> ===================================================================
> --- Makefile.in	(revision 195931)
> +++ Makefile.in	(working copy)
> @@ -223,7 +223,7 @@
>  # Options to use when compiling libgcc2.a.
>  #
>  LIBGCC2_DEBUG_CFLAGS = -g
> -LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(HOST_LIBGCC2_CFLAGS) \
> +LIBGCC2_CFLAGS = $(LIBGCC2_INCLUDES) $(GCC_CFLAGS) $(HOST_LIBGCC2_CFLAGS) \
>  		 $(LIBGCC2_DEBUG_CFLAGS) -DIN_LIBGCC2 \
>  		 -fbuilding-libgcc -fno-stack-protector \
>  		 $(INHIBIT_LIBC_CFLAGS)

Looks like this snuck in accidentally.  Please make sure that the patch
works without it. :-)

> Index: gcc.target/mips/umips-lwp-swp-1.c
> ===================================================================
> --- gcc.target/mips/umips-lwp-swp-1.c	(revision 0)
> +++ gcc.target/mips/umips-lwp-swp-1.c	(revision 0)
> @@ -0,0 +1,19 @@
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
> +
> +void MICROMIPS
> +foo (long long l1, long long *l2)
> +{
> +  *l2 = l1;
> +}
> +
> +long long MICROMIPS
> +bar (long long d)
> +{
> +  register long long l1 asm ("$8") = d;
> +  register long long l2 asm ("$12") = 0;
> +  asm ("#foo" : "=r" (l1) : "r" (l1));
> +  asm volatile ("#foo" :: "r" (l2));
> +  return l1;
> +}
> +
> +/* { dg-final { scan-assembler "\tswp" } */

I don't understand what bar() does here.  It looks like the SWP comes
from foo() alone.

Using SWP for "long long" requires a 32-bit target, so please add:

/* { dg-options "-mgp32 (-mmicromips)" } */

I notice you're changing mips-sde-elf; that'd be a good target to make
sure that the testsuite is still 64-bit clean.  E.g. one run with -mips64r2
(and without -mmicromips).

Also, please add specific registers to the scan-assembler line.
The SWP in foo() should always be "swp $4,0($6)".

> Index: gcc.target/mips/umips-save-restore-1.c
> ===================================================================
> --- gcc.target/mips/umips-save-restore-1.c	(revision 0)
> +++ gcc.target/mips/umips-save-restore-1.c	(revision 0)
> +/* Check that we can use the swm/lwm instructions.  */
> +/* { dg-options "(-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +#include <stdarg.h>
> +
> +int bar (int, int, int, int, int);
> +
> +MICROMIPS int
> +foo (int n, int a, int b, int c, int d) 
> +{
> +  int i, j;
> +
> +  i = bar (n, a, b, c, d);
> +  j = bar (n, a, b, c, d);
> +  return i + j;
> +}
> +/* { dg-final { scan-assembler "\tswm\t" } } */
> +/* { dg-final { scan-assembler "\tlwm\t" } } */

No need for stdarg.h.

Again I think the scan-assembler should have specific registers and
offsets, since all the interesting code is to do with picking ranges
and offsets.  It's easier to check for specific offsets if we fix an ABI:

/* { dg-options "-mabi=32 (-mmicromips)" } */

> Index: gcc.target/mips/umips-lwp-swp-2.c
> ===================================================================
> --- gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
> +++ gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
> @@ -0,0 +1,19 @@
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
> +
> +void MICROMIPS
> +foo (long long *l1, long long l2)
> +{
> +  *l1 = l2;
> +}
> +
> +long long MICROMIPS
> +bar (long long d)
> +{
> +  register long long l1 asm ("$8") = d;
> +  register long long l2 asm ("$12") = 0;
> +  asm ("#foo" : "=r" (l1) : "r" (l1));
> +  asm volatile ("#foo" :: "r" (l2));
> +  return l1;
> +}
> +
> +/* { dg-final { scan-assembler "\tswp" } */

Same comments as for umips-lwp-swp-1.c.  All this really does is swap
the arguments to foo() around, so that instead of:

	swp	$4, 0($6)

we have:

	swp	$6, 0($4)

I certainly don't mind having both, but they really test the same code path.
What we don't have is a test for the swap_p case.  I think we need one,
in addition to one or both of the above.

> Index: gcc.target/mips/umips-save-restore-2.c
> ===================================================================
> --- gcc.target/mips/umips-save-restore-2.c	(revision 0)
> +++ gcc.target/mips/umips-save-restore-2.c	(revision 0)
> @@ -0,0 +1,15 @@
> +/* Check that we can use the save instruction to save spilled arguments.  */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +MICROMIPS void
> +foo (int *a, int b, int c)
> +{
> +  asm volatile ("" ::: "$2", "$3", "$4", "$5", "$6", "$7", "$8",
> +		"$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16",
> +		"$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24",
> +		"$25", "$30", "memory");
> +  a[b] = 1;
> +  a[c] = 1;
> +}
> +/* { dg-final { scan-assembler "\tswm\t" } } */
> +/* { dg-final { scan-assembler "\tlwm\t" } } */

Same comments as for umips-save-restore-1.c.

> Index: gcc.target/mips/umips-lwp-swp-volatile.c
> ===================================================================
> --- gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
> +++ gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +
> +/* This test ensures that we do not generate microMIPS SWP or LWP
> +   instructions when any component of the accessed memory is volatile; 
> +   they are unsafe for such since they might cause replay of partial 
> +   accesses if interrupted by an exception.  */
> +
> +static void set_csr (volatile void *p, int v)
> +{
> +  *(volatile int *) (p) = v;
> +}
> +
> +static int get_csr (volatile void *p)
> +{
> +  return *(volatile int *) (p);
> +}
> +
> +int main ()
> +{
> +  int i, q = 0, p = 0, r = 0;
> +
> +  for (i = 0; i < 20; i++)
> +    {
> +      set_csr ((volatile void *) 0xbf0100a8, 0xffff0002);
> +      set_csr ((volatile void *) 0xbf0100a4, 0x80000008);
> +    }
> +
> +  for (i = 0; i < 20; i++)
> +    {
> +      register int k, j;
> +      k = get_csr ((volatile void *) 0xbf0100b8);
> +      p += k;
> +      j = get_csr ((volatile void *) 0xbf0100b4);
> +      r += j;
> +      q = j + k;
> +    }
> +  return q + r + p;
> +}
> +
> +/* { dg-final { scan-assembler-not "\tswp\t\\\$" } } */
> +/* { dg-final { scan-assembler-not "\tlwp\t\\\$" } } */

Just "\tswp" and "\tlwp" for scan-assembler-not.  Longer strings
run the risk that the regexps will accidentally miss SWP and LWP
instructions because of incorrect backslashes, etc.

> Index: gcc.target/mips/umips-save-restore-3.c
> ===================================================================
> --- gcc.target/mips/umips-save-restore-3.c	(revision 0)
> +++ gcc.target/mips/umips-save-restore-3.c	(revision 0)
> @@ -0,0 +1,13 @@
> +/* Check that we can use the swm instruction to save $16, $17 and $31.  */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void bar (void);
> +
> +MICROMIPS void
> +foo (void)
> +{
> +  bar ();
> +  asm volatile ("" ::: "$16", "$17");
> +}
> +/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$17,\\\$31" } } */
> +/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$17,\\\$31" } } */

Looks good, thanks, but it needs:

/* { dg-options "-mgp32 (-mmicromips)" } */

> Index: gcc.target/mips/umips-movep.c
> ===================================================================
> --- gcc.target/mips/umips-movep.c	(revision 0)
> +++ gcc.target/mips/umips-movep.c	(revision 0)
> @@ -0,0 +1,18 @@
> +/* Check that we can use the save instruction to save varargs.  */
> +/* { dg-options "(-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
> +
> +#include <stdarg.h>
> +
> +long long bar (long long, long long);
> +
> +MICROMIPS long long
> +foo (long long n, long long a)
> +{
> +  long long i, j;
> +
> +  i = bar (n, a);
> +  j = bar (n, a);
> +  return i + j;
> +}
> +/* { dg-final { scan-assembler "\tmovep\t" } } */

The comment at the head of the file doesn't seem to match the test.
No need for <stdarg.h>.

If I understand correctly:

int bar (int, int);

MICROMIPS 
foo (int a, int b)
{
  return bar (0, 0);
}

ought to be able to use MOVEP too, is that right?  A test for this
kind of zero case would be good.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-13 11:43             ` Richard Sandiford
@ 2013-02-19 16:31               ` Moore, Catherine
  2013-02-19 18:25                 ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-02-19 16:31 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 6297 bytes --]

Hi Richard,

I've now attached updated patches.  WDYT?  Are we ready to commit?

I'd also like to support -mno-jals for backward compatibility.  Are you okay with that?  If so, I'll submit as a separate patch.

Thanks,
Catherine

> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Wednesday, February 13, 2013 6:43 AM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> >> > Index: config/mips/mips.c
> >> >
> >>
> ==========================================================
> >> =========
> >> > --- config/mips/mips.c	(revision 195351)
> >> > +++ config/mips/mips.c	(working copy)
> >> > @@ -77,6 +77,9 @@ along with GCC; see the file COPYING3.  If not see
> >> >     preserve the maximum stack alignment.  We therefore use a value
> >> >     of 0x7ff0 in this case.
> >> >
> >> > +   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to
> 0x7ff),
> >> > +   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
> >> > +
> >> >     MIPS16e SAVE and RESTORE instructions can adjust the stack pointer
> by
> >> >     up to 0x7f8 bytes and can usually save or restore all the registers
> >> >     that we need to save or restore.  (Note that we can only use
> >> > these @@ -87,7 +90,8 @@ along with GCC; see the file COPYING3.  If
> not see
> >> >     to save and restore registers, and to allocate and deallocate the top
> >> >     part of the frame.  */
> >> >  #define MIPS_MAX_FIRST_STACK_STEP
> >> 	\
> >> > -  (!TARGET_MIPS16 ? 0x7ff0
> 	\
> >> > +  ((!TARGET_MIPS16 && !TARGET_MICROMIPS) ? 0x7ff0
> >> 	\
> >> > +   : TARGET_MICROMIPS ? 0x7f0
> >> 	\
> >> >     : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8
> >> 	\
> >> >     : TARGET_64BIT ? 0x100 : 0x400)
> >>
> >> I'd prefer:
> >>
> >>   (TARGET_MICROMIPS ? 0x7f0
> 	\
> >>    : !TARGET_MIPS16 ? 0x7ff0
> 	\
> >>    : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8
> 	\
> >>    : TARGET_64BIT ? 0x100 : 0x400)
> 
> Thanks for doing this, but...
> 
> >> The comment doesn't really explain the reason for 0x7f0 rather than
> 0x7f8.
> >> Is this in anticipation of future n32 and n64 support, where the
> >> stack must be 16-byte aligned?  If so, that's OK, but worth mentioning.
> 
> ...it looks like you haven't addressed this part.  What I mean is:
> the stack alignment is 8 bytes rather than 16 bytes on 32-bit ABIs, so I would
> have expected 0x7f8 rather than 0x7f0, as for the MIPS16 case quoted
> above.  I wasn't sure why you went for 0x7f0 instead.
> 
> I'm not saying it must be 0x7f8, just that the comment ought to give the
> reason for using 0x7f0 instead.

I've now changed the constant to 0x7f8.  0x7f0 was used in the initial port, but I couldn't find the reason.  Testing with 0x7f8 looks fine.

> 
> >> > +      /* If DECL is "nocompression" set the "nomips16" and
> >> > +	 "nomicromips" attributes.  */
> >> > +      if (nocompression_p & MASK_MIPS16
> >> > +          && nocompression_p & MASK_MICROMIPS)
> >> > +	{
> >> > +	  name = "nomips16";
> >> > +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> >> > +	  name = "nomicromips";
> >> > +	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> >> > +	}
> >>
> >> Hmm, why is this necessary?  Anything that cares should be using
> >> mips_get_compress_off_flags.
> 
> It looks like you haven't addressed this part.  Why do we need to add tree-
> level "nomips16" and "nomicromips" attributes to a function that has
> "nocompression"?

Now removed.
> 
> >> > +	  && addr.type == ADDRESS_REG
> >> > +	  && CONST_INT_P (addr.offset)
> >> > +	  && UMIPS_12BIT_OFFSET_P (addr.offset));
> >>
> >> Isn't there a missing INTVAL here?  Please check the patch to make
> >> sure there are no compiler warnings.
> 
> This too.  The point is that addr.offset is an rtx, while
> UMIPS_12BIT_OFFSET_P takes a HOST_WIDE_INT:

Now done.

> Please add tests that ZC and ZD work for microMIPS.  E.g. the ZC one could be
> something like:
> 
Now done.
> 
> > +@item -minterlink-compressed
> > +@item -mno-interlink-compressed
> > +@item -minterlink-uncompressed
> > +@item -mno-interlink-uncompressed
> > +@opindex minterlink-compressed
> > +@opindex mno-interlink-compressed
> > +@opindex minterlink-compressed
> > +@opindex mno-interlink-compressed
> > +Require (do not require) that code using the standard (uncompressed)
> > +MIPS ISA be link-compatible with MIPS16 and microMIPS code, and vice
> versa.
> 
> What I meant in my previous reply was that there should be only one set of
> options.  I.e. everything would use -minterlink-compressed and -mno-
> interlink-compressed.  There would be no -minterlink-uncompressed/ -mno-
> interlink-uncompressed
> 
> Sorry for going back on the earlier -mno-jals suggestion here, but I hadn't
> realised until I saw the previous patch just how confusing it would be to have
> both.
> 
That's okay -- I think I've now captured your intent.  I wasn't sure from your earlier reply if you meant to remove the no-interlink-uncompressed altogether.  I do agree that this approach is less confusing.

--Lots of comments addressed and snipped 

> > Index: Makefile.in
> >
> ==========================================================
> =========
> > --- Makefile.in	(revision 195931)
> > +++ Makefile.in	(working copy)
> > @@ -223,7 +223,7 @@
> >  # Options to use when compiling libgcc2.a.
> >  #
> >  LIBGCC2_DEBUG_CFLAGS = -g
> > -LIBGCC2_CFLAGS = -O2 $(LIBGCC2_INCLUDES) $(GCC_CFLAGS)
> > $(HOST_LIBGCC2_CFLAGS) \
> > +LIBGCC2_CFLAGS = $(LIBGCC2_INCLUDES) $(GCC_CFLAGS)
> > +$(HOST_LIBGCC2_CFLAGS) \
> >  		 $(LIBGCC2_DEBUG_CFLAGS) -DIN_LIBGCC2 \
> >  		 -fbuilding-libgcc -fno-stack-protector \
> >  		 $(INHIBIT_LIBC_CFLAGS)
> 
> Looks like this snuck in accidentally.  Please make sure that the patch works
> without it. :-)
Yep, sorry.  Tested with -O2.
> 
> I notice you're changing mips-sde-elf; that'd be a good target to make sure
> that the testsuite is still 64-bit clean.  E.g. one run with -mips64r2 (and
> without -mmicromips).
Also done.



[-- Attachment #2: gcc-testsuite.cl --]
[-- Type: application/octet-stream, Size: 620 bytes --]

2013-02-18  Catherine Moore  <clm@codesourcery.com>

	* gcc.target/mips/mips.exp: microMIPS support.
	* gcc.target/mips/umips-movep-2.c: New test.
	* gcc.target/mips/umips-constraints-1.c: New test.
	* gcc.target/mips/umips-lwp-swp-1.c: New test.
	* gcc.target/mips/umips-constraints-2.c: New test.
	* gcc.target/mips/umips-save-restore-1.c: New test.
	* gcc.target/mips/umips-lwp-swp-2.c: New test.
	* gcc.target/mips/umips-save-restore-2.c: New test.
	* gcc.target/mips/umips-lwp-swp-volatile.c: New test.
	* gcc.target/mips/umips-save-restore-3.c: New test.
	* gcc.target/mips/umips-movep-1.c: New test.

[-- Attachment #3: gcc-testsuite.patch --]
[-- Type: application/octet-stream, Size: 8745 bytes --]

Index: gcc.target/mips/umips-movep-2.c
===================================================================
--- gcc.target/mips/umips-movep-2.c	(revision 0)
+++ gcc.target/mips/umips-movep-2.c	(revision 0)
@@ -0,0 +1,12 @@
+/* Check that we can generate the MOVEP instruction.  */
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
+
+int bar (int, int);
+
+int
+foo (int n, int a)
+{
+  return bar (0, 0);
+}
+/* { dg-final { scan-assembler "\tmovep\t" } } */
Index: gcc.target/mips/umips-constraints-1.c
===================================================================
--- gcc.target/mips/umips-constraints-1.c	(revision 0)
+++ gcc.target/mips/umips-constraints-1.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *x)
+{
+  asm volatile ("insn1\t%a0" :: "ZD" (&x[0]));
+  asm volatile ("insn2\t%a0" :: "ZD" (&x[511]));
+  asm volatile ("insn3\t%a0" :: "ZD" (&x[512]));
+}
+
+/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
+/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
+/* { dg-final { scan-assembler "\tinsn3\t2048\\(" } } */
Index: gcc.target/mips/mips.exp
===================================================================
--- gcc.target/mips/mips.exp	(revision 195578)
+++ gcc.target/mips/mips.exp	(working copy)
@@ -238,6 +238,7 @@ set mips_option_groups {
     fp "-mfp(32|64)"
     gp "-mgp(32|64)"
     long "-mlong(32|64)"
+    micromips "-mmicromips|-mno-micromips"
     mips16 "-mips16|-mno-mips16|-mflip-mips16"
     mips3d "-mips3d|-mno-mips3d"
     pic "-f(no-|)(pic|PIC)"
@@ -1246,6 +1247,10 @@ proc mips-dg-options { args } {
 	append extra_tool_flags " -DMIPS16=__attribute__((mips16))"
     }
 
+    if { [mips_have_test_option_p options "-mmicromips"] } {
+	append extra_tool_flags " -DMICROMIPS=__attribute__((micromips))"
+    }
+
     # Use our version of gcc-dg-test for this test.
     if { ![string equal [info procs "mips-gcc-dg-test"] ""] } {
 	rename gcc-dg-test mips-old-gcc-dg-test
@@ -1275,6 +1280,6 @@ proc mips-gcc-dg-test { prog do_what extra_tool_fl
 dg-init
 mips-dg-init
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
-    "-DNOMIPS16=__attribute__((nomips16))"
+    "-DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression)) -DMICROMIPS=__attribute__((micromips))"
 mips-dg-finish
 dg-finish
Index: gcc.target/mips/umips-lwp-swp-1.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-1.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-1.c	(revision 0)
@@ -0,0 +1,9 @@
+/* { dg-options "-mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
+
+void MICROMIPS
+foo (long long l1, long long *l2)
+{
+  *l2 = l1;
+}
+/* { dg-final { scan-assembler "\tswp\t\\\$4,0\\(\\\$6\\)" } }*/
Index: gcc.target/mips/umips-constraints-2.c
===================================================================
--- gcc.target/mips/umips-constraints-2.c	(revision 0)
+++ gcc.target/mips/umips-constraints-2.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *x)
+{
+  asm volatile ("insn1\t%0" :: "ZC" (x[0]));
+  asm volatile ("insn2\t%0" :: "ZC" (x[511]));
+  asm volatile ("insn3\t%0" :: "ZC" (x[512]));
+}
+
+/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
+/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
+/* { dg-final { scan-assembler "\tinsn3\t2048\\(" } } */
Index: gcc.target/mips/umips-save-restore-1.c
===================================================================
--- gcc.target/mips/umips-save-restore-1.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-1.c	(revision 0)
@@ -0,0 +1,18 @@
+/* Check that we can use the swm/lwm instructions.  */
+/* { dg-options "-mabi=32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+int bar (int, int, int, int, int);
+
+MICROMIPS int
+foo (int n, int a, int b, int c, int d) 
+{
+  int i, j;
+
+  i = bar (n, a, b, c, d);
+  j = bar (n, a, b, c, d);
+  return i + j;
+}
+
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$21,\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$21,\\\$31" } } */
Index: gcc.target/mips/umips-lwp-swp-2.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
@@ -0,0 +1,19 @@
+/* { dg-options "-mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" "-Os" } { "" } } */
+int a[2];
+
+MICROMIPS f (b)
+{
+  unsigned int i;
+  int *p;
+  for (p = &a[b], i = b; --i < ~0; )
+    *--p = i * 3 + (int)a;
+
+}
+
+MICROMIPS main ()
+{
+  a[0] = a[1] = 0;
+  f (2);
+}
+/* { dg-final { scan-assembler "\tswp\t\\\$3,0\\(\\\$3\\)" } }*/
Index: gcc.target/mips/umips-save-restore-2.c
===================================================================
--- gcc.target/mips/umips-save-restore-2.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-2.c	(revision 0)
@@ -0,0 +1,16 @@
+/* Check that we can use the save instruction to save spilled arguments.  */
+/* { dg-options "-mabi=32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *a, int b, int c)
+{
+  asm volatile ("" ::: "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+		"$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16",
+		"$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24",
+		"$25", "$30", "memory");
+  a[b] = 1;
+  a[c] = 1;
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$23,\\\$fp" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$23,\\\$fp" } } */
Index: gcc.target/mips/umips-lwp-swp-volatile.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-do compile } */
+
+/* This test ensures that we do not generate microMIPS SWP or LWP
+   instructions when any component of the accessed memory is volatile; 
+   they are unsafe for such since they might cause replay of partial 
+   accesses if interrupted by an exception.  */
+
+static void set_csr (volatile void *p, int v)
+{
+  *(volatile int *) (p) = v;
+}
+
+static int get_csr (volatile void *p)
+{
+  return *(volatile int *) (p);
+}
+
+int main ()
+{
+  int i, q = 0, p = 0, r = 0;
+
+  for (i = 0; i < 20; i++)
+    {
+      set_csr ((volatile void *) 0xbf0100a8, 0xffff0002);
+      set_csr ((volatile void *) 0xbf0100a4, 0x80000008);
+    }
+
+  for (i = 0; i < 20; i++)
+    {
+      register int k, j;
+      k = get_csr ((volatile void *) 0xbf0100b8);
+      p += k;
+      j = get_csr ((volatile void *) 0xbf0100b4);
+      r += j;
+      q = j + k;
+    }
+  return q + r + p;
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } } */
+/* { dg-final { scan-assembler-not "\tlwp" } } */
Index: gcc.target/mips/umips-save-restore-3.c
===================================================================
--- gcc.target/mips/umips-save-restore-3.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-3.c	(revision 0)
@@ -0,0 +1,14 @@
+/* Check that we can use the swm instruction to save $16, $17 and $31.  */
+/* { dg-options "-mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void bar (void);
+
+MICROMIPS void
+foo (void)
+{
+  bar ();
+  asm volatile ("" ::: "$16", "$17");
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$17,\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$17,\\\$31" } } */
Index: gcc.target/mips/umips-movep-1.c
===================================================================
--- gcc.target/mips/umips-movep-1.c	(revision 0)
+++ gcc.target/mips/umips-movep-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* Check that we can generate the MOVEP instruction.  */
+/* { dg-options "-mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */
+
+long long bar (long long, long long);
+
+MICROMIPS long long
+foo (long long n, long long a)
+{
+  long long i, j;
+
+  i = bar (n, a);
+  j = bar (n, a);
+  return i + j;
+}
+/* { dg-final { scan-assembler "\tmovep\t" } } */

[-- Attachment #4: libgcc.cl --]
[-- Type: application/octet-stream, Size: 296 bytes --]

2013-02-18  Catherine Moore  <clm@codesourcery.com>
	    Joseph Myers  <joseph@codesourcery.com>
	    Chao-ying Fu  <fu@mips.com>

	* config/mips/mips16.S:  Don't build for microMIPS.
	* config/mips/linux-unwind.h: Handle microMIPS frame.
	* config/mips/crtn.S (fini, init): New labels.


[-- Attachment #5: libgcc.patch --]
[-- Type: application/octet-stream, Size: 2195 bytes --]

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 195931)
+++ ChangeLog	(working copy)
@@ -1,3 +1,11 @@
+2013-02-18  Catherine Moore  <clm@codesourcery.com>
+	    Joseph Myers  <joseph@codesourcery.com>
+	    Chao-ying Fu  <fu@mips.com>
+
+	* config/mips/mips16.S:  Don't build for microMIPS.
+	* config/mips/linux-unwind.h: Handle microMIPS frame.
+	* config/mips/crtn.S (fini, init): New labels.
+
 2013-02-08  Georg-Johann Lay  <avr@gjlay.de>
 
 	PR target/54222
Index: config/mips/mips16.S
===================================================================
--- config/mips/mips16.S	(revision 195931)
+++ config/mips/mips16.S	(working copy)
@@ -21,6 +21,10 @@
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#ifdef __mips_micromips
+  /* DO NOTHING */
+#else
+
 /* This file contains mips16 floating point support functions.  These
    functions are called by mips16 code to handle floating point when
    -msoft-float is not used.  They accept the arguments and return
@@ -718,3 +722,4 @@
 #endif /* !__mips_single_float */
 
 #endif
+#endif /* __mips_micromips */
Index: config/mips/linux-unwind.h
===================================================================
--- config/mips/linux-unwind.h	(revision 195931)
+++ config/mips/linux-unwind.h	(working copy)
@@ -51,6 +51,11 @@
   _Unwind_Ptr new_cfa, reg_offset;
   int i;
 
+  /* A MIPS16 or microMIPS frame.  Signal frames always use the standard
+     ISA encoding.  */
+  if ((_Unwind_Ptr) pc & 3)
+    return _URC_END_OF_STACK;
+
   /* 24021061 li v0, 0x1061 (rt_sigreturn)*/
   /* 0000000c syscall    */
   /*    or */
Index: config/mips/crtn.S
===================================================================
--- config/mips/crtn.S	(revision 195931)
+++ config/mips/crtn.S	(working copy)
@@ -31,6 +31,7 @@
 #endif
 
 	.section .init,"ax",@progbits
+init:	
 #ifdef __mips64
 	ld      RA,40($sp)
 	daddu	$sp,$sp,48
@@ -41,6 +42,7 @@
 	j	RA
 
 	.section .fini,"ax",@progbits
+fini:	
 #ifdef	__mips64
 	ld	RA,40($sp)
 	daddu	$sp,$sp,48

[-- Attachment #6: gcc.cl --]
[-- Type: application/octet-stream, Size: 5345 bytes --]

2013-02-12  Catherine Moore  <clm@codesourcery.com>
	    Maciej W. Rozycki  <macro@codesourcery.com>
	    Tom de Vries  <tom@codesourcery.com>
	    Nathan Sidwell <nathan@codesourcery.com>
	    Iain Sandoe  <iain@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>
	    Chao-ying Fu <fu@mips.com>

	* doc/extend.texi: (micromips, nomicromips, nocompression):
	Document new function attributes. 
	* doc/invoke.texi (minterlink-compressed, mmicromips,
	m14k, m14ke, m14kec): Document new options.
	(minterlink-mips16): Update documentation.
	* doc/md.texi (ZC, ZD): Document new constraints.
	* configure.ac (gcc_cv_as_micromips): Check if linker
	supports the .set micromips directive.
	* configure: Regenerate.
	* config.in: Regenerate.
	* config/mips/mips-tables.opt: Regenerate.
	* config/mips/micromips.md: New file.
	* constraints.md (ZC, AD): New constraints.
	* config/mips/predicates.md (movep_src_register): New predicate.
	(movep_src_operand): New predicate.
	(non_volatile_mem_operand): New predicate.
	* config/mips/mips.md (multimem): New type.
	(length): Differentiate between 17-bit and 18-bit branch offsets.
	(MOVEP1, MOVEP2): New mode iterator.
 	(mov_<load>l): Use ZC constraint.
	(mov_<load>r): Likewise.
	(mov_<store>l): Likewise.
	(mov_<store>r): Likewise.
	(*branch_equality<mode>_inverted): Add microMIPS support.
	(*branch_equality<mode>): Likewise.
	(*jump_absolute): Likewise.
	(indirect_jump_<mode>): Likewise.
	(tablejump_<mode>): Likewise.
	(<optab>_internal): Likewise.
	(sibcall_internal): Likewise.
	(sibcall_value_internal): Likewise.
	(prefetch): Use constraint ZD.
	* config/mips/mips.opt (minterlink-compressed): New option.
	(minterlink-mips16): Now an alias for minterlink-compressed.
	(mmicromips): New option.
	* config/mips/sync.md (sync_compare_and_swap<mode>): Use ZR constraint.
	(compare_and_swap_12): Likewise.
	(sync_add<mode>): Likewise.
	(sync_<optab>_12): Likewise.
	(sync_old_<optab>_12): Likewise.
	(sync_new_<optab>_12): Likewise.
	(sync_nand_12): Likewise.
	(sync_old_nand_12): Likewise.
	(sync_new_nand_12): Likewise.
	(sync_sub<mode>): Likewise.
	(sync_old_add<mode>): Likewise.
	(sync_old_sub<mode>): Likewise.
	(sync_new_add<mode>): Likewise.
	(sync_new_sub<mode>): Likewise.
	(sync_<optab><mode>): Likewise.
	(sync_old_<optab><mode>): Likewise.
	(sync_new_<optab><mode>): Likewise.
	(sync_nand<mode>): Likewise.
	(sync_old_nand<mode>): Likewise.
	(sync_new_nand<mode>): Likewise.
	(sync_lock_test_and_set<mode>): Likewise.
	(test_and_set_12): Likewise.
	(atomic_compare_and_swap<mode>): Likewise.
	(atomic_exchange<mode>_llsc): Likewise.
	(atomic_fetch_add<mode>_llsc): Likewise.
	* config/mips/mips-cpus.def (m14kc, m14k): New processors.
	* config/mips/mips-protos.h (umips_output_save_restore): New prototype.
	(umips_save_restore_pattern_p): Likewise.
	(umips_load_store_pair_p): Likewise.
	(umips_output_load_store_pair): Likewise.
	(umips_movep_target_p): Likewise.
	(umips_12bit_offset_address_p): Likewise.
	* config/mips/mips.c (MIPS_MAX_FIRST_STEP): Update for microMIPS.
	(mips_base_mips16): Rename this...
	(mips_base_compression_flags): ...to this. Update all uses.
	(mips_attribute_table): Add micromips, nomicromips and nocompression.
	(mips_mips16_decl_p): Delete.
	(mips_nomips16_decl_p): Delete.
 	(mips_get_compress_on_flags): New function.
	(mips_get_compress_off_flags): New function.
	(mips_get_compress_mode): New function.
	(mips_get_compress_on_name): New function.
	(mips_get_compress_off_name): New function.
	(mips_insert_attributes): Support multiple compression types.
	(mips_merge_decl_attributes): Likewise.
	(umips_12bit_offset_address_p): New function.
	(mips_start_function_definition): Emit .set micromips directive.
	(mips_call_may_need_jalx_p): New function.
	(mips_function_ok_for_sibcall): Add microMIPS support.
	(mips_print_operand_punctuation): Support short delay slots and
	compact jumps.
	(umips_swm_mask, umips_swm_encoding): New.
	(umips_build_save_restore): New function.
	(mips_for_each_saved_gpr_and_fpr): Add microMIPS support.
	(was_mips16_p): Remove.
	(old_compression_mode): New.
	(mips_set_compression_mode): New function.
	(mips_set_current_function): Add microMIPS support.
	(mips_option_override): Likewise.
	(umips_save_restore_pattern_p): New function.
	(umips_output_save_restore): New function.
	(umips_load_store_pair_p_1): New function.
	(umips_load_store_pair_p): New function.
	(umips_output_load_store_pair_1): New function.
	(umips_output_load_store_pair): New function.
	(umips_movep_target_p) New function.
	(mips_prepare_pch_save): Add microMIPS support.
	* config/mips/mips.h (TARGET_COMPRESSION): New.
	(TARGET_CPU_CPP_BUILTINS): Update macro
	to use new compression flags and to support microMIPS.
	(MIPS_ISA_LEVEL_SPEC): Add m14k processors.
	(MIPS_ARCH_FLOAT_SPEC): Likewise.
	(ISA_HAS_LWXS): Include TARGET_MICROMIPS.
	(ASM_SPEC): Support mmicromips and mno-micromips.
	(M16STORE_REG_P): New macro.
	(MIPS_CALL): Support TARGET_MICROMIPS.
	(MICROMIPS_J): New macro.
	(mips_base_mips16): Rename this...
	(mips_base_compression_flags): ...to this.
	(UMIPS_12BIT_OFFSET_P): New macro.
	* config/mips/t-sde: (MULTILIB_OPTIONS): Add microMIPS.
	(MULTILIB_DIRNAMES): Likewise.

[-- Attachment #7: gcc.patch --]
[-- Type: application/octet-stream, Size: 89508 bytes --]

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 195900)
+++ doc/extend.texi	(working copy)
@@ -3053,6 +3053,25 @@ not that within individual functions.  Mixed MIPS1
 may interact badly with some GCC extensions such as @code{__builtin_apply}
 (@pxref{Constructing Calls}).
 
+@item micromips/nomicromips
+@cindex @code{micromips} attribute
+@cindex @code{nomicromips} attribute
+
+On MIPS targets, you can use the @code{micromips} and @code{nomicromips}
+function attributes to locally select or turn off microMIPS code generation.
+A function with the @code{micromips} attribute is emitted as microMIPS code,
+while microMIPS code generation is disabled for functions with the
+@code{nomicromips} attribute.  These attributes override the
+@option{-mmicromips} and @option{-mno-micromips} options on the command line
+(@pxref{MIPS Options}).
+
+When compiling files containing mixed microMIPS and non-microMIPS code, the
+preprocessor symbol @code{__mips_micromips} reflects the setting on the
+command line,
+not that within individual functions.  Mixed microMIPS and non-microMIPS code
+may interact badly with some GCC extensions such as @code{__builtin_apply}
+(@pxref{Constructing Calls}).
+
 @item model (@var{model-name})
 @cindex function addressability on the M32R/D
 @cindex variable addressability on the IA-64
@@ -3155,6 +3174,13 @@ is an NMI handler.  The compiler generates functio
 exit sequences suitable for use in an NMI handler when this
 attribute is present.
 
+@item nocompression
+@cindex @code{nocompression} attribute
+On MIPS targets, you can use the @code{nocompression} function attribute
+to locally turn off MIPS16 and microMIPS code generation.  This attribute
+overrides the @option{-mips16} and @option{-mmicromips} options on the
+command line (@pxref{MIPS Options}).
+
 @item no_instrument_function
 @cindex @code{no_instrument_function} function attribute
 @opindex finstrument-functions
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 195900)
+++ doc/invoke.texi	(working copy)
@@ -740,6 +740,7 @@ Objective-C and Objective-C++ Dialects}.
 -mips1  -mips2  -mips3  -mips4  -mips32  -mips32r2 @gol
 -mips64  -mips64r2 @gol
 -mips16  -mno-mips16  -mflip-mips16 @gol
+-minterlink-compressed -mno-interlink-compressed @gol
 -minterlink-mips16  -mno-interlink-mips16 @gol
 -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
@@ -747,6 +748,7 @@ Objective-C and Objective-C++ Dialects}.
 -mno-float -msingle-float  -mdouble-float  @gol
 -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -mmcu -mmno-mcu @gol
+-mmicromips -mno-micromips @gol
 -mfpu=@var{fpu-type} @gol
 -msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
@@ -15880,6 +15882,7 @@ The processor names are:
 @samp{1004kc}, @samp{1004kf2_1}, @samp{1004kf1_1},
 @samp{loongson2e}, @samp{loongson2f}, @samp{loongson3a},
 @samp{m4k},
+@samp{m14k}, @samp{m14ke}, @samp{m14kec},
 @samp{octeon}, @samp{octeon+}, @samp{octeon2},
 @samp{orion},
 @samp{r2000}, @samp{r3000}, @samp{r3900}, @samp{r4000}, @samp{r4400},
@@ -15993,18 +15996,26 @@ Generate MIPS16 code on alternating functions.  Th
 for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
 not intended for ordinary use in compiling user code.
 
+@item -minterlink-compressed
+@item -mno-interlink-compressed
+@opindex minterlink-compressed
+@opindex mno-interlink-compressed
+Require (do not require) that code using the standard (uncompressed) MIPS ISA
+be link-compatible with MIPS16 and microMIPS code, and vice versa.
+
+For example, code using the standard ISA encoding cannot jump directly
+to MIPS16 or microMIPS code; it must either use a call or an indirect jump.
+@option{-minterlink-compressed} therefore disables direct jumps unless GCC
+knows that the target of the jump is not compressed.
+
 @item -minterlink-mips16
 @itemx -mno-interlink-mips16
 @opindex minterlink-mips16
 @opindex mno-interlink-mips16
-Require (do not require) that non-MIPS16 code be link-compatible with
-MIPS16 code.
+Aliases of @option{-minterlink-compressed} and
+@option{-mno-interlink-compressed}.  These options predate the microMIPS ASE
+and are retained for backwards compatiblity.
 
-For example, non-MIPS16 code cannot jump directly to MIPS16 code;
-it must either use a call or an indirect jump.  @option{-minterlink-mips16}
-therefore disables direct jumps unless GCC knows that the target of the
-jump is not MIPS16.
-
 @item -mabi=32
 @itemx -mabi=o64
 @itemx -mabi=n32
@@ -16218,6 +16229,16 @@ hardware floating-point support to be enabled.
 Use (do not use) the MIPS-3D ASE@.  @xref{MIPS-3D Built-in Functions}.
 The option @option{-mips3d} implies @option{-mpaired-single}.
 
+@item -mmicromips
+@itemx -mno-micromips
+@opindex mmicromips
+@opindex mno-mmicromips
+Generate (do not generate) microMIPS code.
+
+MicroMIPS code generation can also be controlled on a per-function basis
+by means of @code{micromips} and @code{nomicromips} attributes.
+@xref{Function Attributes}, for more information.
+
 @item -mmt
 @itemx -mno-mt
 @opindex mmt
Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 195900)
+++ doc/md.texi	(working copy)
@@ -2916,6 +2916,19 @@ Floating-point zero.
 
 @item R
 An address that can be used in a non-macro load or store.
+
+@item ZC
+When compiling microMIPS code, this constraing matches a memory operand
+whose address is formed from a base register and a 12-bit offset.  These
+operands can be used for microMIPS instructions such as @code{ll} and
+@code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+equivalent to @code{R}.
+
+@item ZD
+When compiling microMIPS code, this constraint matches an address operand
+that is formed from a base register and a 12-bit offset.  These operands
+can be used for microMIPS instructions such as @code{prefetch}.  When
+not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}.
 @end table
 
 @item Motorola 680x0---@file{config/m68k/constraints.md}
Index: configure
===================================================================
--- configure	(revision 195900)
+++ configure	(working copy)
@@ -25708,6 +25708,37 @@ $as_echo "#define HAVE_AS_GNU_ATTRIBUTE 1" >>confd
 
 fi
 
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .micromips support" >&5
+$as_echo_n "checking assembler for .micromips support... " >&6; }
+if test "${gcc_cv_as_micromips_support+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_micromips_support=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '.set micromips' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_micromips_support=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_micromips_support" >&5
+$as_echo "$gcc_cv_as_micromips_support" >&6; }
+if test $gcc_cv_as_micromips_support = yes; then
+
+$as_echo "#define HAVE_GAS_MICROMIPS 1" >>confdefs.h
+
+fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .dtprelword support" >&5
 $as_echo_n "checking assembler for .dtprelword support... " >&6; }
 if test "${gcc_cv_as_mips_dtprelword+set}" = set; then :
Index: config.in
===================================================================
--- config.in	(revision 195900)
+++ config.in	(working copy)
@@ -1034,6 +1034,12 @@
 #endif
 
 
+/* Define if your assembler supports the .set micromips directive */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GAS_MICROMIPS
+#endif
+
+
 /* Define if your assembler supports .nsubspa comdat option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GAS_NSUBSPA_COMDAT
Index: configure.ac
===================================================================
--- configure.ac	(revision 195900)
+++ configure.ac	(working copy)
@@ -4036,6 +4036,12 @@ LCF0:
       [AC_DEFINE(HAVE_AS_GNU_ATTRIBUTE, 1,
 	  [Define if your assembler supports .gnu_attribute.])])
 
+    gcc_GAS_CHECK_FEATURE([.micromips support],
+      gcc_cv_as_micromips_support,,,
+      [.set micromips],,
+      [AC_DEFINE(HAVE_GAS_MICROMIPS, 1,
+          [Define if your assembler supports the .set micromips directive])])
+
     gcc_GAS_CHECK_FEATURE([.dtprelword support],
       gcc_cv_as_mips_dtprelword, [2,18,0],,
       [.section .tdata,"awT",@progbits
Index: config/mips/mips-tables.opt
===================================================================
--- config/mips/mips-tables.opt	(revision 195900)
+++ config/mips/mips-tables.opt	(working copy)
@@ -373,254 +373,260 @@ EnumValue
 Enum(mips_arch_opt_value) String(m4k) Value(39) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kec) Value(40) Canonical
+Enum(mips_arch_opt_value) String(m14kc) Value(40) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kec) Value(40)
+Enum(mips_arch_opt_value) String(m14k) Value(41) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kem) Value(41) Canonical
+Enum(mips_arch_opt_value) String(4kec) Value(42) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kem) Value(41)
+Enum(mips_arch_opt_value) String(r4kec) Value(42)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kep) Value(42) Canonical
+Enum(mips_arch_opt_value) String(4kem) Value(43) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kep) Value(42)
+Enum(mips_arch_opt_value) String(r4kem) Value(43)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4ksd) Value(43) Canonical
+Enum(mips_arch_opt_value) String(4kep) Value(44) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4ksd) Value(43)
+Enum(mips_arch_opt_value) String(r4kep) Value(44)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kc) Value(44) Canonical
+Enum(mips_arch_opt_value) String(4ksd) Value(45) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kc) Value(44)
+Enum(mips_arch_opt_value) String(r4ksd) Value(45)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf2_1) Value(45) Canonical
+Enum(mips_arch_opt_value) String(24kc) Value(46) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf2_1) Value(45)
+Enum(mips_arch_opt_value) String(r24kc) Value(46)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf) Value(46) Canonical
+Enum(mips_arch_opt_value) String(24kf2_1) Value(47) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf) Value(46)
+Enum(mips_arch_opt_value) String(r24kf2_1) Value(47)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf1_1) Value(47) Canonical
+Enum(mips_arch_opt_value) String(24kf) Value(48) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf1_1) Value(47)
+Enum(mips_arch_opt_value) String(r24kf) Value(48)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kfx) Value(48) Canonical
+Enum(mips_arch_opt_value) String(24kf1_1) Value(49) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kfx) Value(48)
+Enum(mips_arch_opt_value) String(r24kf1_1) Value(49)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kx) Value(49) Canonical
+Enum(mips_arch_opt_value) String(24kfx) Value(50) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kx) Value(49)
+Enum(mips_arch_opt_value) String(r24kfx) Value(50)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kec) Value(50) Canonical
+Enum(mips_arch_opt_value) String(24kx) Value(51) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kec) Value(50)
+Enum(mips_arch_opt_value) String(r24kx) Value(51)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef2_1) Value(51) Canonical
+Enum(mips_arch_opt_value) String(24kec) Value(52) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef2_1) Value(51)
+Enum(mips_arch_opt_value) String(r24kec) Value(52)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef) Value(52) Canonical
+Enum(mips_arch_opt_value) String(24kef2_1) Value(53) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef) Value(52)
+Enum(mips_arch_opt_value) String(r24kef2_1) Value(53)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef1_1) Value(53) Canonical
+Enum(mips_arch_opt_value) String(24kef) Value(54) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef1_1) Value(53)
+Enum(mips_arch_opt_value) String(r24kef) Value(54)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kefx) Value(54) Canonical
+Enum(mips_arch_opt_value) String(24kef1_1) Value(55) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kefx) Value(54)
+Enum(mips_arch_opt_value) String(r24kef1_1) Value(55)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kex) Value(55) Canonical
+Enum(mips_arch_opt_value) String(24kefx) Value(56) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kex) Value(55)
+Enum(mips_arch_opt_value) String(r24kefx) Value(56)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kc) Value(56) Canonical
+Enum(mips_arch_opt_value) String(24kex) Value(57) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kc) Value(56)
+Enum(mips_arch_opt_value) String(r24kex) Value(57)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf2_1) Value(57) Canonical
+Enum(mips_arch_opt_value) String(34kc) Value(58) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf2_1) Value(57)
+Enum(mips_arch_opt_value) String(r34kc) Value(58)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf) Value(58) Canonical
+Enum(mips_arch_opt_value) String(34kf2_1) Value(59) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf) Value(58)
+Enum(mips_arch_opt_value) String(r34kf2_1) Value(59)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf1_1) Value(59) Canonical
+Enum(mips_arch_opt_value) String(34kf) Value(60) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf1_1) Value(59)
+Enum(mips_arch_opt_value) String(r34kf) Value(60)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kfx) Value(60) Canonical
+Enum(mips_arch_opt_value) String(34kf1_1) Value(61) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kfx) Value(60)
+Enum(mips_arch_opt_value) String(r34kf1_1) Value(61)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kx) Value(61) Canonical
+Enum(mips_arch_opt_value) String(34kfx) Value(62) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kx) Value(61)
+Enum(mips_arch_opt_value) String(r34kfx) Value(62)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kn) Value(62) Canonical
+Enum(mips_arch_opt_value) String(34kx) Value(63) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kn) Value(62)
+Enum(mips_arch_opt_value) String(r34kx) Value(63)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kc) Value(63) Canonical
+Enum(mips_arch_opt_value) String(34kn) Value(64) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kc) Value(63)
+Enum(mips_arch_opt_value) String(r34kn) Value(64)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf2_1) Value(64) Canonical
+Enum(mips_arch_opt_value) String(74kc) Value(65) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf2_1) Value(64)
+Enum(mips_arch_opt_value) String(r74kc) Value(65)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf) Value(65) Canonical
+Enum(mips_arch_opt_value) String(74kf2_1) Value(66) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf) Value(65)
+Enum(mips_arch_opt_value) String(r74kf2_1) Value(66)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf1_1) Value(66) Canonical
+Enum(mips_arch_opt_value) String(74kf) Value(67) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf1_1) Value(66)
+Enum(mips_arch_opt_value) String(r74kf) Value(67)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kfx) Value(67) Canonical
+Enum(mips_arch_opt_value) String(74kf1_1) Value(68) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kfx) Value(67)
+Enum(mips_arch_opt_value) String(r74kf1_1) Value(68)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kx) Value(68) Canonical
+Enum(mips_arch_opt_value) String(74kfx) Value(69) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kx) Value(68)
+Enum(mips_arch_opt_value) String(r74kfx) Value(69)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf3_2) Value(69) Canonical
+Enum(mips_arch_opt_value) String(74kx) Value(70) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf3_2) Value(69)
+Enum(mips_arch_opt_value) String(r74kx) Value(70)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kc) Value(70) Canonical
+Enum(mips_arch_opt_value) String(74kf3_2) Value(71) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kc) Value(70)
+Enum(mips_arch_opt_value) String(r74kf3_2) Value(71)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf2_1) Value(71) Canonical
+Enum(mips_arch_opt_value) String(1004kc) Value(72) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf2_1) Value(71)
+Enum(mips_arch_opt_value) String(r1004kc) Value(72)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf) Value(72) Canonical
+Enum(mips_arch_opt_value) String(1004kf2_1) Value(73) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf) Value(72)
+Enum(mips_arch_opt_value) String(r1004kf2_1) Value(73)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf1_1) Value(73) Canonical
+Enum(mips_arch_opt_value) String(1004kf) Value(74) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf1_1) Value(73)
+Enum(mips_arch_opt_value) String(r1004kf) Value(74)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kc) Value(74) Canonical
+Enum(mips_arch_opt_value) String(1004kf1_1) Value(75) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kc) Value(74)
+Enum(mips_arch_opt_value) String(r1004kf1_1) Value(75)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kf) Value(75) Canonical
+Enum(mips_arch_opt_value) String(5kc) Value(76) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kf) Value(75)
+Enum(mips_arch_opt_value) String(r5kc) Value(76)
 
 EnumValue
-Enum(mips_arch_opt_value) String(20kc) Value(76) Canonical
+Enum(mips_arch_opt_value) String(5kf) Value(77) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r20kc) Value(76)
+Enum(mips_arch_opt_value) String(r5kf) Value(77)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1) Value(77) Canonical
+Enum(mips_arch_opt_value) String(20kc) Value(78) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1a) Value(78) Canonical
+Enum(mips_arch_opt_value) String(r20kc) Value(78)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71000) Value(79) Canonical
+Enum(mips_arch_opt_value) String(sb1) Value(79) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71k) Value(79)
+Enum(mips_arch_opt_value) String(sb1a) Value(80) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlr) Value(80) Canonical
+Enum(mips_arch_opt_value) String(sr71000) Value(81) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(loongson3a) Value(81) Canonical
+Enum(mips_arch_opt_value) String(sr71k) Value(81)
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon) Value(82) Canonical
+Enum(mips_arch_opt_value) String(xlr) Value(82) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon+) Value(83) Canonical
+Enum(mips_arch_opt_value) String(loongson3a) Value(83) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon2) Value(84) Canonical
+Enum(mips_arch_opt_value) String(octeon) Value(84) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlp) Value(85) Canonical
+Enum(mips_arch_opt_value) String(octeon+) Value(85) Canonical
 
+EnumValue
+Enum(mips_arch_opt_value) String(octeon2) Value(86) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(xlp) Value(87) Canonical
+
Index: config/mips/micromips.md
===================================================================
--- config/mips/micromips.md	(revision 0)
+++ config/mips/micromips.md	(revision 0)
@@ -0,0 +1,127 @@
+;; Copyright (C) 2013 Free Software Foundation, Inc.
+;;
+;; micromips.md   Machine Description for the microMIPS instruction set
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_insn "*store_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "memory_operand")
+	     (match_operand:SI 2 "register_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (true, operands[0])"
+  { return umips_output_save_restore (true, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+(define_insn "*load_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "register_operand")
+	     (match_operand:SI 2 "memory_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (false, operands[0])"
+  { return umips_output_save_restore (false, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For LWP.
+(define_peephole2
+  [(set (match_operand:SI 0 "d_operand" "")
+        (match_operand:SI 1 "non_volatile_mem_operand" ""))
+   (set (match_operand:SI 2 "d_operand" "")
+        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+;; The behavior of the LWP insn is undefined if placed in a delay slot.
+(define_insn "*lwp"
+  [(parallel [(set (match_operand:SI 0 "d_operand")
+		   (match_operand:SI 1 "non_volatile_mem_operand"))
+	      (set (match_operand:SI 2 "d_operand")
+		   (match_operand:SI 3 "non_volatile_mem_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+{
+  umips_output_load_store_pair (true, operands);
+  return "";
+}
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For SWP.
+(define_peephole2
+  [(set (match_operand:SI 0 "non_volatile_mem_operand" "")
+        (match_operand:SI 1 "d_operand" ""))
+   (set (match_operand:SI 2 "non_volatile_mem_operand" "")
+        (match_operand:SI 3 "d_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+(define_insn "*swp"
+  [(parallel [(set (match_operand:SI 0 "non_volatile_mem_operand")
+		   (match_operand:SI 1 "d_operand"))
+	      (set (match_operand:SI 2 "non_volatile_mem_operand")
+		   (match_operand:SI 3 "d_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+{
+  umips_output_load_store_pair (false, operands);
+  return "";
+}
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For MOVEP.
+(define_peephole2
+  [(set (match_operand:MOVEP1 0 "register_operand" "")
+        (match_operand:MOVEP1 1 "movep_src_operand" ""))
+   (set (match_operand:MOVEP2 2 "register_operand" "")
+        (match_operand:MOVEP2 3 "movep_src_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+;; The behavior of the MOVEP insn is undefined if placed in a delay slot.
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+		   (match_operand:MOVEP1 1 "movep_src_operand"))
+	      (set (match_operand:MOVEP2 2 "register_operand")
+		   (match_operand:MOVEP2 3 "movep_src_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+{
+  if (REGNO (operands[0]) < REGNO (operands[2]))
+    return "movep\t%0,%2,%z1,%z3";
+  else
+    return "movep\t%2,%0,%z3,%z1";
+}
+  [(set_attr "type" "move")
+   (set_attr "mode" "<MODE>")
+   (set_attr "can_delay" "no")])
Index: config/mips/constraints.md
===================================================================
--- config/mips/constraints.md	(revision 195900)
+++ config/mips/constraints.md	(working copy)
@@ -232,6 +232,26 @@
    "@internal"
    (match_operand 0 "low_bitmask_operand"))
 
+(define_memory_constraint "ZC"
+  "When compiling microMIPS code, this constraint matches a memory operand
+   whose address is formed from a base register and a 12-bit offset.  These
+   operands can be used for microMIPS instructions such as @code{ll} and
+   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+   equivalent to @code{R}."
+  (and (match_code "mem")
+       (ior (and (match_test "TARGET_MICROMIPS")
+		 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)"))
+	    (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "ZD"
+  "When compiling microMIPS code, this constraint matches an address operand
+   that is formed from a base register and a 12-bit offset.  These operands
+   can be used for microMIPS instructions such as @code{prefetch}.  When
+   not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}."
+   (ior (and (match_test "TARGET_MICROMIPS")
+	     (match_test "umips_12bit_offset_address_p (op, mode)"))
+	(match_test "mips_address_insns (op, mode, false)")))
+
 (define_memory_constraint "ZR"
  "@internal
   An address valid for loading/storing register exclusive"
Index: config/mips/predicates.md
===================================================================
--- config/mips/predicates.md	(revision 195900)
+++ config/mips/predicates.md	(working copy)
@@ -122,6 +122,15 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "movep_src_register"
+  (and (match_code "reg")
+       (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
+	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
+
+(define_predicate "movep_src_operand"
+  (ior (match_operand 0 "const_0_operand")
+       (match_operand 0 "movep_src_register")))
+
 (define_predicate "lo_operand"
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
@@ -371,3 +380,8 @@
 (define_predicate "mem_noofs_operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
+
+;; Return 1 if the operand is in non-volatile memory.
+(define_predicate "non_volatile_mem_operand"
+  (and (match_operand 0 "memory_operand")
+       (not (match_test "MEM_VOLATILE_P (op)"))))
Index: config/mips/mips.md
===================================================================
--- config/mips/mips.md	(revision 195900)
+++ config/mips/mips.md	(working copy)
@@ -342,13 +342,14 @@
 ;; syncloop	memory atomic operation implemented as a sync loop
 ;; nop		no operation
 ;; ghost	an instruction that produces no real code
+;; multimem	microMIPS multiword load and store
 (define_attr "type"
   "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
    prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
    shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
    fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
    frsqrt,frsqrt1,frsqrt2,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat,
-   multi,atomic,syncloop,nop,ghost"
+   multi,atomic,syncloop,nop,ghost,multimem"
   (cond [(eq_attr "jal" "!unset") (const_string "call")
 	 (eq_attr "got" "load") (const_string "load")
 
@@ -413,9 +414,15 @@
 
 ;; Length of instruction in bytes.
 (define_attr "length" ""
-   (cond [;; Direct branch instructions have a range of [-0x20000,0x1fffc],
-	  ;; relative to the address of the delay slot.  If a branch is
-	  ;; outside this range, we have a choice of two sequences.
+   (cond [(and (eq_attr "extended_mips16" "yes")
+	       (match_test "TARGET_MIPS16"))
+	  (const_int 8)
+
+	  ;; Direct microMIPS branch instructions have a range of
+	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
+	  ;; If a branch is outside this range, we have a choice of two
+	  ;; sequences.
+	  ;;
 	  ;; For PIC, an out-of-range branch like:
 	  ;;
 	  ;;	bne	r1,r2,target
@@ -451,10 +458,17 @@
 	  ;; from the shorten_branches reference address.
 	  (and (eq_attr "type" "branch")
 	       (not (match_test "TARGET_MIPS16")))
-	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
-		      (le (minus (pc) (match_dup 0)) (const_int 131068)))
+	  (cond [;; Any variant can handle the 17-bit range.
+		 (and (le (minus (match_dup 0) (pc)) (const_int 65532))
+		      (le (minus (pc) (match_dup 0)) (const_int 65534)))
 		   (const_int 4)
 
+		 ;; The 18-bit range is OK other than for microMIPS.
+		 (and (not (match_test "TARGET_MICROMIPS"))
+		      (and (le (minus (match_dup 0) (pc)) (const_int 131064))
+		      	   (le (minus (pc) (match_dup 0)) (const_int 131068))))
+		   (const_int 4)
+
 		 ;; The non-PIC case: branch, first delay slot, and J.
 		 (match_test "TARGET_ABSOLUTE_JUMPS")
 		   (const_int 12)]
@@ -712,6 +726,9 @@
 ;; modes.
 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
 
+(define_mode_iterator MOVEP1 [SI SF])
+(define_mode_iterator MOVEP2 [SI SF])
+
 ;; This mode iterator allows :HILO to be used as the mode of the
 ;; concatenated HI and LO registers.
 (define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
@@ -3937,7 +3954,7 @@
 (define_insn "mov_<load>l"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_LOAD_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
   "<load>l\t%0,%2"
@@ -3947,7 +3964,7 @@
 (define_insn "mov_<load>r"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_operand:GPR 3 "register_operand" "0")]
 		    UNSPEC_LOAD_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
@@ -3958,7 +3975,7 @@
 (define_insn "mov_<store>l"
   [(set (match_operand:BLK 0 "memory_operand" "=m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_STORE_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
   "<store>l\t%z1,%2"
@@ -3968,7 +3985,7 @@
 (define_insn "mov_<store>r"
   [(set (match_operand:BLK 0 "memory_operand" "+m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_dup 0)]
 		    UNSPEC_STORE_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
@@ -5447,11 +5464,20 @@
 	 (pc)))]
   "!TARGET_MIPS16"
 {
+  /* For a simple BNEZ or BEQZ microMIPS branch.  */
+  if (TARGET_MICROMIPS
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%C1z%:\t%2,%0",
+					   "%*b%N1z%:\t%2,%0");
+    
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
 }
-  [(set_attr "type" "branch")])
+  [(set_attr "type" "branch")
+   (set_attr "mode" "none")])
 
 (define_insn "*branch_equality<mode>_inverted"
   [(set (pc)
@@ -5463,6 +5489,14 @@
 	 (label_ref (match_operand 0 "" ""))))]
   "!TARGET_MIPS16"
 {
+  /* For a simple BNEZ or BEQZ microMIPS branch.  */
+  if (TARGET_MICROMIPS
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%N0z%:\t%2,%1",
+					   "%*b%C0z%:\t%2,%1");
+
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
@@ -5766,7 +5800,14 @@
   [(set (pc)
 	(label_ref (match_operand 0)))]
   "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
-  { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
+{
+  /* Use a branch for microMIPS.  The assembler will choose
+     a 16-bit branch, a 32-bit branch, or a 32-bit jump.  */
+  if (TARGET_MICROMIPS && !TARGET_ABICALLS_PIC2)
+    return "%*b\t%l0%/";
+  else
+    return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+}
   [(set_attr "type" "jump")])
 
 (define_insn "*jump_pic"
@@ -5829,7 +5870,12 @@
 (define_insn "indirect_jump_<mode>"
   [(set (pc) (match_operand:P 0 "register_operand" "d"))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -5873,7 +5919,12 @@
 	(match_operand:P 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -6094,7 +6145,12 @@
   [(any_return)
    (use (match_operand 0 "pmode_register_operand" ""))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type"	"jump")
    (set_attr "mode"	"none")])
 
@@ -6350,7 +6406,12 @@
   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
 	 (match_operand 1 "" ""))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 0, 1); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 0);
+  else
+    return MIPS_CALL ("j", operands, 0, 1);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6371,7 +6432,12 @@
         (call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
               (match_operand 2 "" "")))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 1);
+  else
+    return MIPS_CALL ("j", operands, 1, 2);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6383,7 +6449,12 @@
 	(call (mem:SI (match_dup 1))
 	      (match_dup 2)))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 1);
+  else
+    return MIPS_CALL ("j", operands, 1, 2);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6629,7 +6700,7 @@
 
 
 (define_insn "prefetch"
-  [(prefetch (match_operand:QI 0 "address_operand" "p")
+  [(prefetch (match_operand:QI 0 "address_operand" "ZD")
 	     (match_operand 1 "const_int_operand" "n")
 	     (match_operand 2 "const_int_operand" "n"))]
   "ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
@@ -6922,6 +6993,9 @@
 ; MIPS fixed-point instructions.
 (include "mips-fixed.md")
 
+; microMIPS patterns.
+(include "micromips.md")
+
 ; ST-Microelectronics Loongson-2E/2F-specific patterns.
 (include "loongson.md")
 
Index: config/mips/mips.opt
===================================================================
--- config/mips/mips.opt	(revision 195900)
+++ config/mips/mips.opt	(working copy)
@@ -217,9 +217,13 @@ mhard-float
 Target Report RejectNegative InverseMask(SOFT_FLOAT_ABI, HARD_FLOAT_ABI)
 Allow the use of hardware floating-point ABI and instructions
 
+minterlink-compressed
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+Generate code that is link-compatible with MIPS16 and microMIPS code.
+
 minterlink-mips16
-Target Report Var(TARGET_INTERLINK_MIPS16) Init(0)
-Generate code that can be safely linked with MIPS16 code.
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+An alias for minterlink-compressed provided for backward-compatibility.
 
 mips
 Target RejectNegative Joined ToLower Enum(mips_mips_opt_value) Var(mips_isa_option)
@@ -261,6 +265,10 @@ mmemcpy
 Target Report Mask(MEMCPY)
 Don't optimize block moves
 
+mmicromips
+Target Report Mask(MICROMIPS)
+Use microMIPS instructions
+
 mmt
 Target Report Var(TARGET_MT)
 Allow the use of MT instructions
Index: config/mips/sync.md
===================================================================
--- config/mips/sync.md	(revision 195900)
+++ config/mips/sync.md	(working copy)
@@ -59,7 +59,7 @@
 ;; Can be removed in favor of atomic_compare_and_swap below.
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
 			      (match_operand:GPR 3 "arith_operand" "I,d")]
@@ -89,7 +89,7 @@
 ;; Helper insn for mips_expand_atomic_qihi.
 (define_insn "compare_and_swap_12"
   [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-	(match_operand:SI 1 "memory_operand" "+R,R"))
+	(match_operand:SI 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
 			     (match_operand:SI 3 "register_operand" "d,d")
@@ -106,7 +106,7 @@
    (set_attr "sync_insn1_op2" "5")])
 
 (define_insn "sync_add<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 0)
 		     (match_operand:GPR 1 "arith_operand" "I,d"))]
@@ -134,7 +134,7 @@
 
 ;; Helper insn for sync_<optab><mode>
 (define_insn "sync_<optab>_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -174,7 +174,7 @@
 ;; Helper insn for sync_old_<optab><mode>
 (define_insn "sync_old_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -217,7 +217,7 @@
 (define_insn "sync_new_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
@@ -257,7 +257,7 @@
 
 ;; Helper insn for sync_nand<mode>
 (define_insn "sync_nand_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -296,7 +296,7 @@
 ;; Helper insn for sync_old_nand<mode>
 (define_insn "sync_old_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -337,7 +337,7 @@
 (define_insn "sync_new_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (match_operand:SI 4 "reg_or_0_operand" "dJ")]
@@ -360,7 +360,7 @@
    (set_attr "sync_insn1_op2" "4")])
 
 (define_insn "sync_sub<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR")
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 0)
 		      (match_operand:GPR 1 "register_operand" "d"))]
@@ -374,7 +374,7 @@
 ;; Can be removed in favor of atomic_fetch_add below.
 (define_insn "sync_old_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 1)
@@ -389,7 +389,7 @@
 
 (define_insn "sync_old_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-	(match_operand:GPR 1 "memory_operand" "+R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 1)
@@ -404,7 +404,7 @@
 
 (define_insn "sync_new_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-        (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+        (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZR,ZR")
 		  (match_operand:GPR 2 "arith_operand" "I,d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -420,7 +420,7 @@
 
 (define_insn "sync_new_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-        (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+        (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZR")
 		   (match_operand:GPR 2 "register_operand" "d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -435,7 +435,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_<optab><mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
 			      (match_dup 0))]
@@ -448,7 +448,7 @@
 
 (define_insn "sync_old_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -463,7 +463,7 @@
 
 (define_insn "sync_new_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -478,7 +478,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_nand<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
@@ -490,7 +490,7 @@
 
 (define_insn "sync_old_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
@@ -504,7 +504,7 @@
 
 (define_insn "sync_new_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_NEW_OP))]
@@ -519,7 +519,7 @@
 
 (define_insn "sync_lock_test_and_set<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
 	 UNSPEC_SYNC_EXCHANGE))]
@@ -546,7 +546,7 @@
 
 (define_insn "test_and_set_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
 			     (match_operand:SI 3 "register_operand" "d")
@@ -576,7 +576,7 @@
 	;; TODO: the obscuring unspec can be relaxed for permissive memory
 	;; models.
 	;; Same applies to other atomic_* patterns.
-	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+R,R")
+	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZR,ZR")
 			      (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
 	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
    (set (match_operand:GPR 1 "register_operand" "=&d,&d")
@@ -629,7 +629,7 @@
 
 (define_insn "atomic_exchange<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_EXCHANGE))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
@@ -684,7 +684,7 @@
 
 (define_insn "atomic_fetch_add<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_FETCH_OP))
    (set (match_dup 1)
 	(unspec_volatile:GPR
Index: config/mips/mips-cpus.def
===================================================================
--- config/mips/mips-cpus.def	(revision 195900)
+++ config/mips/mips-cpus.def	(working copy)
@@ -92,6 +92,8 @@ MIPS_CPU ("4ksc", PROCESSOR_4KC, 32, 0)
 
 /* MIPS32 Release 2 processors.  */
 MIPS_CPU ("m4k", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14kc", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14k", PROCESSOR_M4K, 33, 0)
 MIPS_CPU ("4kec", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kem", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kep", PROCESSOR_4KP, 33, 0)
Index: config/mips/mips-protos.h
===================================================================
--- config/mips/mips-protos.h	(revision 195900)
+++ config/mips/mips-protos.h	(working copy)
@@ -350,6 +350,12 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern const char *umips_output_save_restore (bool, rtx);
+extern bool umips_save_restore_pattern_p (bool, rtx);
+extern bool umips_load_store_pair_p (bool, rtx *);
+extern void umips_output_load_store_pair (bool, rtx *);
+extern bool umips_movep_target_p (rtx, rtx);
+extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 195900)
+++ config/mips/mips.c	(working copy)
@@ -77,6 +77,9 @@ along with GCC; see the file COPYING3.  If not see
    preserve the maximum stack alignment.  We therefore use a value
    of 0x7ff0 in this case.
 
+   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
+   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
+
    MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
    up to 0x7f8 bytes and can usually save or restore all the registers
    that we need to save or restore.  (Note that we can only use these
@@ -87,8 +90,8 @@ along with GCC; see the file COPYING3.  If not see
    to save and restore registers, and to allocate and deallocate the top
    part of the frame.  */
 #define MIPS_MAX_FIRST_STACK_STEP					\
-  (!TARGET_MIPS16 ? 0x7ff0						\
-   : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8				\
+  (!TARGET_COMPRESSION ? 0x7ff0						\
+   : TARGET_MICROMIPS || GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8		\
    : TARGET_64BIT ? 0x100 : 0x400)
 
 /* True if INSN is a mips.md pattern or asm statement.  */
@@ -560,8 +563,8 @@ static const struct mips_rtx_cost_data *mips_cost;
 /* The ambient target flags, excluding MASK_MIPS16.  */
 static int mips_base_target_flags;
 
-/* True if MIPS16 is the default mode.  */
-bool mips_base_mips16;
+/* The default compression mode.  */
+unsigned int mips_base_compression_flags;
 
 /* The ambient values of other global variables.  */
 static int mips_base_schedule_insns; /* flag_schedule_insns */
@@ -674,6 +677,9 @@ static const struct attribute_spec mips_attribute_
      code generation but don't carry other semantics.  */
   { "mips16", 	   0, 0, true,  false, false, NULL, false },
   { "nomips16",    0, 0, true,  false, false, NULL, false },
+  { "micromips",   0, 0, true,  false, false, NULL, false },
+  { "nomicromips", 0, 0, true,  false, false, NULL, false },
+  { "nocompression", 0, 0, true,  false, false, NULL, false },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 0, false, true,  true, NULL, false },
   { "use_shadow_register_set",	0, 0, false, true,  true, NULL, false },
@@ -1167,10 +1173,11 @@ mflip_mips16_use_mips16_p (tree decl)
   const char *name;
   hashval_t hash;
   void **slot;
+  bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) != 0;
 
   /* Use the opposite of the command-line setting for anonymous decls.  */
   if (!DECL_NAME (decl))
-    return !mips_base_mips16;
+    return !base_is_mips16;
 
   if (!mflip_mips16_htab)
     mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
@@ -1185,7 +1192,7 @@ mflip_mips16_use_mips16_p (tree decl)
       mips16_flipper = !mips16_flipper;
       entry = ggc_alloc_mflip_mips16_entry ();
       entry->name = name;
-      entry->mips16_p = mips16_flipper ? !mips_base_mips16 : mips_base_mips16;
+      entry->mips16_p = mips16_flipper ? !base_is_mips16 : base_is_mips16;
       *slot = entry;
     }
   return entry->mips16_p;
@@ -1207,20 +1214,7 @@ mips_far_type_p (const_tree type)
 	  || lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
 }
 
-/* Similar predicates for "mips16"/"nomips16" function attributes.  */
 
-static bool
-mips_mips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
-static bool
-mips_nomips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
 /* Check if the interrupt attribute is set for a function.  */
 
 static bool
@@ -1257,12 +1251,51 @@ mips_use_debug_exception_return_p (tree type)
 			   TYPE_ATTRIBUTES (type)) != NULL;
 }
 
-/* Return true if function DECL is a MIPS16 function.  Return the ambient
-   setting if DECL is null.  */
+/* Return the set of compression modes that are explicitly required
+   by DECL.  */
 
-static bool
-mips_use_mips16_mode_p (tree decl)
+static unsigned int
+mips_get_compress_on_flags (tree attributes)
 {
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("mips16", attributes) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("micromips", attributes) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the set of compression modes that are explicitly forbidden
+   by DECL.  */
+
+static unsigned int
+mips_get_compress_off_flags (tree attributes)
+{
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("nocompression", attributes) != NULL)
+    flags |= MASK_MIPS16 | MASK_MICROMIPS;
+
+  if (lookup_attribute ("nomips16", attributes) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("nomicromips", attributes) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the compression mode that should be used for function DECL.
+   Return the ambient setting if DECL is null.  */
+static unsigned int
+mips_get_compress_mode (tree decl)
+{
+  unsigned int flags, force_on;
+
+  flags = mips_base_compression_flags;
   if (decl)
     {
       /* Nested functions must use the same frame pointer as their
@@ -1270,14 +1303,38 @@ mips_use_debug_exception_return_p (tree type)
       tree parent = decl_function_context (decl);
       if (parent)
 	decl = parent;
-      if (mips_mips16_decl_p (decl))
-	return true;
-      if (mips_nomips16_decl_p (decl))
-	return false;
+      force_on = mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+      if (force_on)
+	return force_on;
+      flags &= ~mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
     }
-  return mips_base_mips16;
+  return flags;
 }
 
+/* Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_on_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "mips16";
+  return "micromips";
+}
+
+/* Return the attribute name that forbids MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_off_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "nomips16";
+  if (flags == MASK_MICROMIPS)
+    return "nomicromips";
+  return "nocompression";
+}
+
 /* Implement TARGET_COMP_TYPE_ATTRIBUTES.  */
 
 static int
@@ -1297,36 +1354,50 @@ static void
 mips_insert_attributes (tree decl, tree *attributes)
 {
   const char *name;
-  bool mips16_p, nomips16_p;
+  unsigned int compression_flags, nocompression_flags;
 
   /* Check for "mips16" and "nomips16" attributes.  */
-  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
-  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+  compression_flags = mips_get_compress_on_flags (*attributes);
+  nocompression_flags = mips_get_compress_off_flags (*attributes);
+
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
-      if (mips16_p)
-	error ("%qs attribute only applies to functions", "mips16");
-      if (nomips16_p)
-	error ("%qs attribute only applies to functions", "nomips16");
+      if (nocompression_flags)
+	error ("%qs attribute only applies to function",
+	       mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags)
+	error ("%qs attribute only applies to function",
+	       mips_get_compress_on_name (nocompression_flags));
     }
   else
     {
-      mips16_p |= mips_mips16_decl_p (decl);
-      nomips16_p |= mips_nomips16_decl_p (decl);
-      if (mips16_p || nomips16_p)
+      compression_flags |= mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+      nocompression_flags |=
+	mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
+
+      if (compression_flags && nocompression_flags)
+	error ("%qE cannot have both %qs and %qs attributes",
+	       DECL_NAME (decl), mips_get_compress_on_name (compression_flags),
+	       mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags & MASK_MIPS16
+          && compression_flags & MASK_MICROMIPS)
+	error ("%qE cannot have both %s and %s attributes",
+	       DECL_NAME (decl), "mips16", "micromips");
+
+      if (TARGET_FLIP_MIPS16
+	  && !DECL_ARTIFICIAL (decl)
+	  && compression_flags == 0
+	  && nocompression_flags == 0)
 	{
-	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
-	  if (mips16_p && nomips16_p)
-	    error ("%qE cannot have both %<mips16%> and "
-		   "%<nomips16%> attributes",
-		   DECL_NAME (decl));
-	}
-      else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
-	{
 	  /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
 	     "mips16" attribute, arbitrarily pick one.  We must pick the same
 	     setting for duplicate declarations of a function.  */
 	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
+	  name = "nomips16";
+ 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	  name = "nomicromips";
 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
 	}
     }
@@ -1337,14 +1408,24 @@ mips_insert_attributes (tree decl, tree *attribute
 static tree
 mips_merge_decl_attributes (tree olddecl, tree newdecl)
 {
-  /* The decls' "mips16" and "nomips16" attributes must match exactly.  */
-  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
+  unsigned int diff;
+
+  diff = (mips_get_compress_on_flags (DECL_ATTRIBUTES (olddecl))
+	  ^ mips_get_compress_on_flags (DECL_ATTRIBUTES (newdecl)));
+
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "mips16");
-  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
+	   DECL_NAME (newdecl), mips_get_compress_on_name (diff));
+
+
+  diff = (mips_get_compress_off_flags (DECL_ATTRIBUTES (olddecl))
+	  ^ mips_get_compress_off_flags (DECL_ATTRIBUTES (newdecl)));
+
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "nomips16");
+	   DECL_NAME (newdecl), mips_get_compress_off_name (diff));
 
+
   return merge_attributes (DECL_ATTRIBUTES (olddecl),
 			   DECL_ATTRIBUTES (newdecl));
 }
@@ -1550,7 +1631,7 @@ mips16_local_function_p (const_rtx x)
   return (GET_CODE (x) == SYMBOL_REF
 	  && SYMBOL_REF_LOCAL_P (x)
 	  && !SYMBOL_REF_EXTERNAL_P (x)
-	  && mips_use_mips16_mode_p (SYMBOL_REF_DECL (x)));
+	  && (mips_get_compress_mode (SYMBOL_REF_DECL (x)) & MASK_MIPS16));
 }
 
 /* Return true if SYMBOL_REF X binds locally.  */
@@ -2300,6 +2381,20 @@ mips_address_insns (rtx x, enum machine_mode mode,
   return 0;
 }
 
+/* Return true if X is a legitimate address with a 12-bit offset.
+   MODE is the mode of the value being accessed.  */
+
+bool
+umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && CONST_INT_P (addr.offset)
+	  && UMIPS_12BIT_OFFSET_P (INTVAL (addr.offset)));
+}
+
 /* Return the number of instructions needed to load constant X.
    Return 0 if X isn't a valid constant.  */
 
@@ -6097,6 +6192,13 @@ mips_start_function_definition (const char *name,
   else
     fprintf (asm_out_file, "\t.set\tnomips16\n");
 
+  if (TARGET_MICROMIPS)
+    fprintf (asm_out_file, "\t.set\tmicromips\n");
+#ifdef HAVE_GAS_MICROMIPS
+  else 
+    fprintf (asm_out_file, "\t.set\tnomicromips\n");
+#endif
+
   if (!flag_inhibit_size_directive)
     {
       fputs ("\t.ent\t", asm_out_file);
@@ -6903,11 +7005,46 @@ mips_split_call (rtx insn, rtx call_pattern)
     mips_restore_gp_from_cprestore_slot (gen_rtx_REG (Pmode, GP_ARG_FIRST + 2));
 }
 
+/* Return true if a call to DECL may need to use JALX.  */
+
+static bool
+mips_call_may_need_jalx_p (tree decl)
+{
+  /* If the current translation unit would use a different mode for DECL,
+     assume that the call needs JALX.  */
+  if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
+    return true;
+
+  /* mips_get_compress_mode is always accurate for locally-binding
+     functions in the current translation unit.  */
+  if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
+    return false;
+
+  /* When -minterlink-compressed is in effect, assume that functions
+     could use a different encoding mode unless an attribute explicitly
+     tells us otherwise.  */
+  if (TARGET_INTERLINK_COMPRESSED)
+    {
+      if (!TARGET_COMPRESSION
+	  && mips_get_compress_off_flags
+	       (TYPE_ATTRIBUTES (TREE_TYPE (decl))) ==0)
+	return true;
+      if (TARGET_COMPRESSION
+	  && mips_get_compress_on_flags
+	       (TYPE_ATTRIBUTES (TREE_TYPE (decl))) == 0)
+	return true;
+    }
+
+  return false;
+}
+
 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
 
 static bool
 mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
+
+  unsigned int compression_mode = mips_get_compress_mode (decl);
   if (!TARGET_SIBCALLS)
     return false;
 
@@ -6916,25 +7053,13 @@ mips_function_ok_for_sibcall (tree decl, tree exp
   if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
     return false;
 
-  /* We can't do a sibcall if the called function is a MIPS16 function
-     because there is no direct "jx" instruction equivalent to "jalx" to
-     switch the ISA mode.  We only care about cases where the sibling
-     and normal calls would both be direct.  */
+  /* Direct Js are only possible to functions that use the same ISA
+  encoding.  There is no JX counterpoart of JALX.  */
   if (decl
-      && mips_use_mips16_mode_p (decl)
-      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
+      && mips_call_may_need_jalx_p (decl))
     return false;
 
-  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
-     functions could be MIPS16 ones unless an attribute explicitly tells
-     us otherwise.  */
-  if (TARGET_INTERLINK_MIPS16
-      && decl
-      && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
-      && !mips_nomips16_decl_p (decl)
-      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
-    return false;
-
   /* Otherwise OK.  */
   return true;
 }
@@ -7798,6 +7923,9 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_s
    '^'	Print the name of the pic call-through register (t9 or $25).
    '+'	Print the name of the gp register (usually gp or $28).
    '$'	Print the name of the stack pointer register (sp or $29).
+   ':'  Print "c" to use the compact version if the delay slot is a nop.
+   '!'  Print "s" to use the short version if the delay slot contains a
+	16-bit instruction.
 
    See also mips_init_print_operand_pucnt.  */
 
@@ -7881,6 +8009,20 @@ mips_print_operand_punctuation (FILE *file, int ch
       fputs (reg_names[STACK_POINTER_REGNUM], file);
       break;
 
+    case ':':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+	 use the compact version for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('c', file);
+      break;
+
+    case '!':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+	 a 16-bit delay slot for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('s', file);
+      break;
+
     default:
       gcc_unreachable ();
       break;
@@ -7894,7 +8036,7 @@ mips_init_print_operand_punct (void)
 {
   const char *p;
 
-  for (p = "()[]<>*#/?~.@^+$"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$:!"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -10236,6 +10378,125 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset,
       }
 }
 
+/* Save register REG to MEM.  Make the instruction frame-related.  */
+
+static void
+mips_save_reg (rtx reg, rtx mem)
+{
+  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
+    {
+      rtx x1, x2;
+
+      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
+
+      x1 = mips_frame_set (mips_subword (mem, false),
+			   mips_subword (reg, false));
+      x2 = mips_frame_set (mips_subword (mem, true),
+			   mips_subword (reg, true));
+      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
+    }
+  else
+    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
+}
+
+/* Capture the register combinations that are allowed in a SWM or LWM
+   instruction.  The entries are ordered by number of registers set in
+   the mask.  We also ignore the single register encodings because a
+   normal SW/LW is preferred.  */
+   
+static const unsigned int umips_swm_mask[17] = {
+  0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
+  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,	
+  0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
+  0x000f0000, 0x80030000, 0x00070000, 0x80010000,
+  0x00030000 };
+
+static const unsigned int umips_swm_encoding[17] = {
+  25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2 };
+
+/* Try to use a microMIPS LWM or SWM instruction to save or restore
+   as many GPRs in *MASK as possible.  *OFFSET is the offset from the
+   stack pointer of the topmost save slot.
+
+   Remove from *MASK all registers that were handled using LWM and SWM.
+   Update *OFFSET so that it points to the first unused save slot.  */
+
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+			  unsigned *mask, HOST_WIDE_INT *offset)
+{
+  int i, nregs;
+  unsigned int j;
+  rtx pattern, set, reg, mem;
+  HOST_WIDE_INT this_offset;
+  rtx this_base;
+
+  /* Try matching $16 to $31 (s0 to ra).  */
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if ((*mask & 0xffff0000) == umips_swm_mask[i])
+      break;
+
+  if (i == ARRAY_SIZE (umips_swm_mask))
+    return false;
+
+  /* Adjust offset for output.  */
+  nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
+  this_offset = *offset - UNITS_PER_WORD * (nregs - 1);
+
+  /* LWM/SWM can only support offsets from -2048 to 2047.  */
+  if (!UMIPS_12BIT_OFFSET_P (this_offset))
+    return false;
+
+  /* Create the final PARALLEL.  */
+  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs));
+  this_base = stack_pointer_rtx;
+
+  /* For registers $16-$23 and $30.  */
+  for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
+    {
+      unsigned int regno;
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      regno = (j != 8) ? 16 + j : 30;
+      *mask &= ~(1 << regno);
+      reg = gen_rtx_REG (SImode, regno);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  /* For register $31.  */
+  if (umips_swm_encoding[i] >> 4)
+    {
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      *mask &= ~(1 << 31);
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      reg = gen_rtx_REG (SImode, 31);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  pattern = emit_insn (pattern);
+  if (fn == mips_save_reg)
+    RTX_FRAME_RELATED_P (pattern) = 1;  
+
+  /* Adjust the last offset.  */
+  *offset -= UNITS_PER_WORD * nregs;
+
+  return true;
+}
+
 /* Call FN for each register that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -10245,16 +10506,23 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
 				 mips_save_restore_fn fn)
 {
   enum machine_mode fpr_mode;
+  int regno;
+  const struct mips_frame_info *frame = &cfun->machine->frame;
   HOST_WIDE_INT offset;
-  int regno;
+  unsigned int mask;
 
   /* Save registers starting from high to low.  The debuggers prefer at least
      the return register be stored at func+4, and also it allows us not to
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
   offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+  mask = frame->mask;
+
+  if (TARGET_MICROMIPS)
+    umips_build_save_restore (fn, &mask, &offset);
+
   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
-    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+    if (BITSET_P (mask, regno - GP_REG_FIRST))
       {
 	/* Record the ra offset for use by mips_function_profiler.  */
 	if (regno == RETURN_ADDR_REGNUM)
@@ -10501,27 +10769,7 @@ mips_frame_barrier (void)
   emit_clobber (gen_frame_mem (BLKmode, stack_pointer_rtx));
 }
 
-/* Save register REG to MEM.  Make the instruction frame-related.  */
 
-static void
-mips_save_reg (rtx reg, rtx mem)
-{
-  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
-    {
-      rtx x1, x2;
-
-      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
-
-      x1 = mips_frame_set (mips_subword (mem, false),
-			   mips_subword (reg, false));
-      x2 = mips_frame_set (mips_subword (mem, true),
-			   mips_subword (reg, true));
-      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
-    }
-  else
-    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
-}
-
 /* The __gnu_local_gp symbol.  */
 
 static GTY(()) rtx mips_gnu_local_gp;
@@ -16211,17 +16459,19 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndec
   reload_completed = 0;
 }
 \f
-/* The last argument passed to mips_set_mips16_mode, or negative if the
-   function hasn't been called yet.  */
-static int was_mips16_p = -1;
 
-/* Set up the target-dependent global state so that it matches the
-   current function's ISA mode.  */
+/* The last argument passed to mips_set_compression_mode,
+   or negative if the function hasn't been called yet.  */
+static unsigned int old_compression_mode = -1;
 
+/* Set up the target-dependent global state for ISA mode COMPRESSION_MODE,
+   which is either MASK_MIPS16 or MASK_MICROMIPS.  */
+
 static void
-mips_set_mips16_mode (int mips16_p)
+mips_set_compression_mode (unsigned int compression_mode)
 {
-  if (mips16_p == was_mips16_p)
+
+  if (compression_mode == old_compression_mode)
     return;
 
   /* Restore base settings of various flags.  */
@@ -16232,8 +16482,10 @@ static void
   align_loops = mips_base_align_loops;
   align_jumps = mips_base_align_jumps;
   align_functions = mips_base_align_functions;
+  target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
+  target_flags |= compression_mode;
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       /* Switch to MIPS16 mode.  */
       target_flags |= MASK_MIPS16;
@@ -16287,9 +16539,12 @@ static void
     }
   else
     {
-      /* Switch to normal (non-MIPS16) mode.  */
-      target_flags &= ~MASK_MIPS16;
+      /* Switch to microMIPS or the standard encoding.  */
 
+      if (TARGET_MICROMIPS)
+	/* Avoid branch likely.  */
+	target_flags &= ~MASK_BRANCHLIKELY;
+
       /* Provide default values for align_* for 64-bit targets.  */
       if (TARGET_64BIT)
 	{
@@ -16310,7 +16565,7 @@ static void
   /* (Re)initialize MIPS target internals for new ISA.  */
   mips_init_relocs ();
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       if (!mips16_globals)
 	mips16_globals = save_target_globals ();
@@ -16320,16 +16575,17 @@ static void
   else
     restore_target_globals (&default_target_globals);
 
-  was_mips16_p = mips16_p;
+  old_compression_mode = compression_mode;
 }
 
 /* Implement TARGET_SET_CURRENT_FUNCTION.  Decide whether the current
-   function should use the MIPS16 ISA and switch modes accordingly.  */
+   function should use the MIPS16 or microMIPS ISA and switch modes
+   accordingly.  */
 
 static void
 mips_set_current_function (tree fndecl)
 {
-  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+  mips_set_compression_mode (mips_get_compress_mode (fndecl));
 }
 \f
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -16437,14 +16693,19 @@ mips_option_override (void)
   if (global_options_set.x_mips_isa_option)
     mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
 
-  /* Process flags as though we were generating non-MIPS16 code.  */
-  mips_base_mips16 = TARGET_MIPS16;
-  target_flags &= ~MASK_MIPS16;
-
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
+  /* MIPS16 and microMIPS cannot coexist  */
+  if (TARGET_MICROMIPS && TARGET_MIPS16)
+    error ("unsupported combination: %s", "-mips16 -mmicromips");
+
+  /* Save the base compression state and process flags as though we
+     are generating uncompressed code.  */
+  mips_base_compression_flags = TARGET_COMPRESSION;
+  target_flags &= ~TARGET_COMPRESSION;
+
   /* -mno-float overrides -mhard-float and -msoft-float.  */
   if (TARGET_NO_FLOAT)
     {
@@ -16453,7 +16714,7 @@ mips_option_override (void)
     }
 
   if (TARGET_FLIP_MIPS16)
-    TARGET_INTERLINK_MIPS16 = 1;
+    TARGET_INTERLINK_COMPRESSED = 1;
 
   /* Set the small data limit.  */
   mips_small_data_threshold = (global_options_set.x_g_switch_value
@@ -16826,9 +17087,9 @@ mips_option_override (void)
 
   /* Now select the ISA mode.
 
-     Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
-     MIPS16 mode afterwards if need be.  */
-  mips_set_mips16_mode (false);
+     Do all CPP-sensitive stuff in uncompressed mode;
+     We'll switch modes later if required.  */
+  mips_set_compression_mode (0);
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -17088,6 +17349,270 @@ mips_mulsidi3_gen_fn (enum rtx_code ext_code)
       return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
     }
 }
+
+/* Return true if PATTERN matches the kind of instruction generated by
+   umips_build_save_restore.  SAVE_P is true for store.  */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+  int n;
+  unsigned int i;
+  HOST_WIDE_INT first_offset = 0;
+  rtx first_base = 0;
+  unsigned int regmask = 0;
+
+  for (n = 0; n < XVECLEN (pattern, 0); n++)
+    {
+      rtx set, reg, mem, this_base;
+      HOST_WIDE_INT this_offset;
+      unsigned int this_regno;
+
+      /* Check that we have a SET.  */
+      set = XVECEXP (pattern, 0, n);
+      if (GET_CODE (set) != SET)
+	return false;
+
+      /* Check that the SET is a load (if restoring) or a store
+	 (if saving).  */
+      mem = save_p ? SET_DEST (set) : SET_SRC (set);
+      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
+	return false;
+
+      /* Check that the address is the sum of base and a possibly-zero
+	 constant offset.  Determine if the offset is in range.  */
+      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+      if (!REG_P (this_base))
+	return false;
+
+      if (n == 0)
+	{
+	  if (!UMIPS_12BIT_OFFSET_P (this_offset))
+	    return false;
+	  first_base = this_base;
+	  first_offset = this_offset;
+	}
+      else
+	{
+	  /* Check that the save slots are consecutive.  */
+	  if (REGNO (this_base) != REGNO (first_base)
+	      || this_offset != first_offset + UNITS_PER_WORD * n)
+	    return false;
+	}
+
+      /* Check that SET's other operand is a register.  */
+      reg = save_p ? SET_SRC (set) : SET_DEST (set);
+      if (!REG_P (reg))
+	return false;
+
+      regmask |= 1 << REGNO (reg);
+    }
+
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if (regmask == umips_swm_mask[i])
+      return true;
+
+  return false;
+}
+/* Return the assembly instruction for microMIPS lwm or swm.
+   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+  static char buffer[300];
+  char *s;
+  int n;
+  HOST_WIDE_INT offset;
+  rtx base, mem, set, reg, last_set, last_reg;
+
+  /* Parse the pattern.  */
+  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
+
+  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
+  s += strlen (s);
+  n = XVECLEN (pattern, 0);
+
+  set = XVECEXP (pattern, 0, 0);
+  reg = save_p ? SET_SRC (set) : SET_DEST (set);
+  mem = save_p ? SET_DEST (set) : SET_SRC (set);
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+
+  last_set = XVECEXP (pattern, 0, n - 1);
+  last_reg = save_p ? SET_SRC (last_set) : SET_DEST (last_set);
+
+  if (REGNO (last_reg) == 31)
+    n--;
+
+  gcc_assert (n <= 9);
+  if (n == 0)
+    ;
+  else if (n == 1)
+    s += sprintf (s, "%s,", reg_names[16]);
+  else if (n < 9)
+    s += sprintf (s, "%s-%s,", reg_names[16], reg_names[15 + n]);
+  else if (n == 9)
+    s += sprintf (s, "%s-%s,%s,", reg_names[16], reg_names[23],
+		  reg_names[30]);
+
+  if (REGNO (last_reg) == 31)
+    s += sprintf (s, "%s,", reg_names[31]);
+
+  s += sprintf (s, "%d(%s)", (int)offset, reg_names[REGNO (base)]);
+  return buffer;
+}
+
+/* Return true if MEM1 and MEM2 use the same base register, and the
+   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
+   register into (from) which the contents of MEM1 will be loaded
+   (stored), depending on the value of LOAD_P.
+   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
+
+static bool
+umips_load_store_pair_p_1 (bool load_p, rtx first_reg, rtx mem1, rtx mem2)
+{
+  rtx base1, base2;
+  HOST_WIDE_INT offset1, offset2;
+
+  if (!MEM_P (mem1) || !MEM_P (mem2))
+    return false;
+
+  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
+  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
+
+  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
+    return false;
+
+  /* Avoid invalid load pair instructions.  */
+  if (load_p && REGNO (first_reg) == REGNO (base1))
+    return false;
+
+  /* We must avoid this case for anti-dependence.
+     Ex:  lw $3, 4($3)
+          lw $2, 0($3)
+     first_reg is $2, but the base is $3.  */
+  if (load_p
+      && REGNO (first_reg) + 1 == REGNO (base1))
+    return false;
+
+  if (offset2 != offset1 + 4)
+    return false;
+
+  if (!UMIPS_12BIT_OFFSET_P (offset1))
+    return false;
+
+  return true;
+}
+
+/* Return true if operands can be used in an LWP or SWP instruction.  */
+
+bool
+umips_load_store_pair_p (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    return umips_load_store_pair_p_1 (load_p, reg1, mem1, mem2);
+
+  if (REGNO (reg1) == REGNO (reg2) + 1)
+    return umips_load_store_pair_p_1 (load_p, reg2, mem2, mem1);
+
+  return false;
+}
+
+/* Return the assembly instruction for microMIPS lwp or swp.
+   LOAD_P is true for load.  */
+
+static void
+umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
+{
+  rtx ops[] = {reg, mem};
+
+  if (load_p)
+    output_asm_insn ("lwp\t%0,%1", ops);
+  else
+    output_asm_insn ("swp\t%0,%1", ops);
+}
+
+void
+umips_output_load_store_pair (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+   
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    {
+      umips_output_load_store_pair_1 (load_p, reg1, mem1);
+      return;
+    }
+
+  gcc_assert (REGNO (reg1) == REGNO (reg2) + 1);
+  umips_output_load_store_pair_1 (load_p, reg2, mem2);
+}
+
+/* Return true if REG1 and REG2 match the criteria for a movep insn.  */
+
+bool
+umips_movep_target_p (rtx reg1, rtx reg2)
+{
+  int regno1, regno2, pair;
+  unsigned int i;
+  static const int match[8] = {
+    0x00000060,	/* 5, 6 */
+    0x000000a0,	/* 5, 7 */
+    0x000000c0,	/* 6, 7 */
+    0x00200010,	/* 4, 21 */
+    0x00400010,	/* 4, 22 */
+    0x00000030,	/* 4, 5 */
+    0x00000050, /* 4, 6 */
+    0x00000090  /* 4, 7 */
+  };
+
+  if (!REG_P (reg1) || !REG_P (reg2))
+    return false;
+
+  regno1 = REGNO (reg1);
+  regno2 = REGNO (reg2);
+
+  if (!GP_REG_P (regno1)  || !GP_REG_P (regno2))
+    return false;
+
+  pair = (1 << regno1) | (1 << regno2);
+
+  for (i = 0; i < ARRAY_SIZE (match); i++)
+    if (pair == match[i])
+      return true;
+
+  return false;
+}
 \f
 /* Return the size in bytes of the trampoline code, padded to
    TRAMPOLINE_ALIGNMENT bits.  The static chain pointer and target
@@ -17342,7 +17867,7 @@ mips_prepare_pch_save (void)
      It therefore seems best to switch back to non-MIPS16 mode at
      save time, and to ensure that mips16_globals remains null after
      a PCH load.  */
-  mips_set_mips16_mode (false);
+  mips_set_compression_mode (0);
   mips16_globals = 0;
 }
 \f
Index: config/mips/mips.h
===================================================================
--- config/mips/mips.h	(revision 195900)
+++ config/mips/mips.h	(working copy)
@@ -174,6 +174,9 @@ struct mips_cpu_info {
 #define ISA_HAS_DSP_MULT ISA_HAS_DSPR2
 #endif
 
+/* The ISA compression flags that are currently in effect.  */
+#define TARGET_COMPRESSION (target_flags & (MASK_MIPS16 | MASK_MICROMIPS))
+
 /* Generate mips16 code */
 #define TARGET_MIPS16		((target_flags & MASK_MIPS16) != 0)
 /* Generate mips16e code. Default 16bit ASE for mips32* and mips64* */
@@ -374,7 +377,7 @@ struct mips_cpu_info {
       else								\
 	builtin_define ("__mips_fpr=32");				\
 									\
-      if (mips_base_mips16)						\
+      if (mips_base_compression_flags & MASK_MIPS16)			\
 	builtin_define ("__mips16");					\
 									\
       if (TARGET_MIPS3D)						\
@@ -383,6 +386,9 @@ struct mips_cpu_info {
       if (TARGET_SMARTMIPS)						\
 	builtin_define ("__mips_smartmips");				\
 									\
+      if (mips_base_compression_flags & MASK_MICROMIPS)			\
+	builtin_define ("__mips_micromips");				\
+									\
       if (TARGET_MCU)							\
 	builtin_define ("__mips_mcu");					\
 									\
@@ -702,7 +708,7 @@ struct mips_cpu_info {
        |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
      %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
      %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
-       |march=34k*|march=74k*|march=1004k*: -mips32r2} \
+       |march=34k*|march=74k*|march=m14k*|march=1004k*: -mips32r2} \
      %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
        |march=xlr|march=loongson3a: -mips64} \
      %{march=mips64r2|march=octeon|march=xlp: -mips64r2} \
@@ -716,7 +722,7 @@ struct mips_cpu_info {
   "%{mhard-float|msoft-float|mno-float|march=mips*:; \
      march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
      |march=34kc|march=34kn|march=74kc|march=1004kc|march=5kc \
-     |march=octeon|march=xlr: -msoft-float;		  \
+     |march=m14k*|march=octeon|march=xlr: -msoft-float;		  \
      march=*: -mhard-float}"
 
 /* A spec condition that matches 32-bit options.  It only works if
@@ -989,7 +995,8 @@ struct mips_cpu_info {
 				     || ISA_MIPS64R2))
 
 /* ISA has lwxs instruction (load w/scaled index address.  */
-#define ISA_HAS_LWXS		(TARGET_SMARTMIPS && !TARGET_MIPS16)
+#define ISA_HAS_LWXS		((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
+				 && !TARGET_MIPS16)
 
 /* ISA has lbx, lbux, lhx, lhx, lhux, lwx, lwux, or ldx instruction. */
 #define ISA_HAS_LBX		(TARGET_OCTEON2)
@@ -1123,6 +1130,7 @@ struct mips_cpu_info {
 %{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
 %{mips32*} %{mips64*} \
 %{mips16} %{mno-mips16:-no-mips16} \
+%{mmicromips} %{mno-micromips} \
 %{mips3d} %{mno-mips3d:-no-mips3d} \
 %{mdmx} %{mno-mdmx:-no-mdmx} \
 %{mdsp} %{mno-dsp} \
@@ -1672,6 +1680,8 @@ struct mips_cpu_info {
   ((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define M16_REG_P(REGNO) \
   (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 16 || (REGNO) == 17)
+#define M16STORE_REG_P(REGNO) \
+  (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 0 || (REGNO) == 17)
 #define FP_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
 #define MD_REG_P(REGNO) \
@@ -2034,6 +2044,7 @@ enum reg_class
 #define SMALL_INT(X) SMALL_OPERAND (INTVAL (X))
 #define SMALL_INT_UNSIGNED(X) SMALL_OPERAND_UNSIGNED (INTVAL (X))
 #define LUI_INT(X) LUI_OPERAND (INTVAL (X))
+#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))
 
 /* The HI and LO registers can only be reloaded via the general
    registers.  Condition code registers can only be loaded to the
@@ -2452,17 +2463,32 @@ typedef struct mips_args {
    all calls should use assembly macros.  Otherwise, all indirect
    calls should use "jr" or "jalr"; we will arrange to restore $gp
    afterwards if necessary.  Finally, we can only generate direct
-   calls for -mabicalls by temporarily switching to non-PIC mode.  */
+   calls for -mabicalls by temporarily switching to non-PIC mode.
+
+   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+   instruction is in the delay slot of jal(r).  */
 #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
   (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
    ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
-   : (REG_P (OPERANDS[TARGET_OPNO])				\
-      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
-   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
-      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
    : REG_P (OPERANDS[TARGET_OPNO])				\
-   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"				\
+   ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)		\
+      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
+	 "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
+      : TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED	\
+      ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"			\
+      : "%*" INSN "r\t%" #TARGET_OPNO "%/")			\
    : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
+
+/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
+   "jrc" when nop is in the delay slot of "jr".  */
+
+#define MICROMIPS_J(INSN, OPERANDS, OPNO)			\
+  (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
+   ? "%*j\t%" #OPNO "%/"					\
+   : REG_P (OPERANDS[OPNO])					\
+   ? "%*jr%:\t%" #OPNO						\
+   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #OPNO "%/"))
+
 \f
 /* Control the assembler format that we output.  */
 
@@ -2877,7 +2903,7 @@ extern enum processor mips_tune;        /* which c
 extern int mips_isa;			/* architectural level */
 extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
-extern bool mips_base_mips16;
+extern unsigned int mips_base_compression_flags;
 extern GTY(()) struct target_globals *mips16_globals;
 #endif
 
Index: config/mips/t-sde
===================================================================
--- config/mips/t-sde	(revision 195900)
+++ config/mips/t-sde	(working copy)
@@ -16,8 +16,8 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16 msoft-float/mfp64 mcode-readable=no
-MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 sof f64 spram
+MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16/mmicromips msoft-float/mfp64 mcode-readable=no
+MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 micromips sof f64 spram
 MULTILIB_MATCHES = EL=mel EB=meb
 
 # The -mfp64 option is only valid in conjunction with -mips32r2.
@@ -33,3 +33,6 @@ MULTILIB_EXCLUSIONS += !mips32/!mips32r2/mips16
 else
 MULTILIB_EXCLUSIONS += mips64/mips16 mips64r2/mips16
 endif
+
+# The -mcode-readable=no is only in conjunction with -mips16.
+MULTILIB_EXCLUSIONS += mcode-readable=no/!mips16

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-19 16:31               ` Moore, Catherine
@ 2013-02-19 18:25                 ` Richard Sandiford
  2013-02-19 22:27                   ` Maciej W. Rozycki
  2013-02-21  2:28                   ` Moore, Catherine
  0 siblings, 2 replies; 41+ messages in thread
From: Richard Sandiford @ 2013-02-19 18:25 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

Thanks, this is looking much better now.

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> I'd also like to support -mno-jals for backward compatibility.  Are you
> okay with that?  If so, I'll submit as a separate patch.

Hmm, to be honest, I'd rather you kept it local to the Mentor toolchain.
The way the patch is written, we (rightly) use JALS even with
-minterlink-compressed in cases where we can prove that the call
is to another microMIPS function, so calling -mno-jals an alias of
-minterlink-compressed would be a bit confusing.

-mno-jals sounds like it ought to disable JALS in all situations,
which would need special code to handle.  I think doing that would be
extra baggage with little benefit.

> Index: gcc.target/mips/umips-constraints-1.c
> ===================================================================
> --- gcc.target/mips/umips-constraints-1.c	(revision 0)
> +++ gcc.target/mips/umips-constraints-1.c	(revision 0)
> @@ -0,0 +1,14 @@
> +/* { dg-options "(-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +MICROMIPS void
> +foo (int *x)
> +{
> +  asm volatile ("insn1\t%a0" :: "ZD" (&x[0]));
> +  asm volatile ("insn2\t%a0" :: "ZD" (&x[511]));
> +  asm volatile ("insn3\t%a0" :: "ZD" (&x[512]));
> +}
> +
> +/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
> +/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
> +/* { dg-final { scan-assembler "\tinsn3\t2048\\(" } } */

But the insn3 is wrong, isn't it?  I suggested scan-assembler-not for
that one because I thought it had to be a 12-bit signed offset on
microMIPS.  The patch has:

(define_address_constraint "ZD"
  "When compiling microMIPS code, this constraint matches an address operand
   that is formed from a base register and a 12-bit offset.  These operands
   can be used for microMIPS instructions such as @code{prefetch}.  When
   not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}."
   (ior (and (match_test "TARGET_MICROMIPS")
	     (match_test "umips_12bit_offset_address_p (op, mode)"))
	(match_test "mips_address_insns (op, mode, false)")))

but it looks like it ought to be:

   (if_then_else (match_test "TARGET_MICROMIPS")
	         (match_test "umips_12bit_offset_address_p (op, mode)")
	         (match_test "mips_address_insns (op, mode, false)"))

Same for ZC.

> @@ -1246,6 +1247,10 @@ proc mips-dg-options { args } {
>  	append extra_tool_flags " -DMIPS16=__attribute__((mips16))"
>      }
>  
> +    if { [mips_have_test_option_p options "-mmicromips"] } {
> +	append extra_tool_flags " -DMICROMIPS=__attribute__((micromips))"
> +    }
> +
>      # Use our version of gcc-dg-test for this test.
>      if { ![string equal [info procs "mips-gcc-dg-test"] ""] } {
>  	rename gcc-dg-test mips-old-gcc-dg-test
> @@ -1275,6 +1280,6 @@ proc mips-gcc-dg-test { prog do_what extra_tool_fl
>  dg-init
>  mips-dg-init
>  gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
> -    "-DNOMIPS16=__attribute__((nomips16))"
> +    "-DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression)) -DMICROMIPS=__attribute__((micromips))"
>  mips-dg-finish
>  dg-finish

Please drop the -DMICROMIPS in the second hunk.  The first hunk is the
right way to add it.  The idea is that we want a compilation failure if
the test uses MICROMIPS but forgets to add:

/* { dg-options "(-mmicromips)" } */

The -DNOMICROMIPS and -DNOCOMPRESSION in the second hunk are fine though.

> +/* { dg-options "(-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" } { "" } } */

Sorry, only just realised you were skipping -O1.  Please add a comment saying
why it fails at -O1 or (preferably) add whichever other option is needed for
the test to pass at -O1.  I assume it's -fpeephole2 in this case.

Same for all tests with this skip.

> Index: gcc.target/mips/umips-lwp-swp-2.c
> ===================================================================
> --- gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
> +++ gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
> @@ -0,0 +1,19 @@
> +/* { dg-options "-mgp32 (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" "-Os" } { "" } } */
> +int a[2];
> +
> +MICROMIPS f (b)
> +{
> +  unsigned int i;
> +  int *p;
> +  for (p = &a[b], i = b; --i < ~0; )
> +    *--p = i * 3 + (int)a;
> +
> +}
> +
> +MICROMIPS main ()
> +{
> +  a[0] = a[1] = 0;
> +  f (2);
> +}
> +/* { dg-final { scan-assembler "\tswp\t\\\$3,0\\(\\\$3\\)" } }*/

Is this a test of the swap_p case?  Thanks if so, but could you add a
comment saying where the SWP gets generated, and why the test needs
to be skipped at -O1 and -Os?

> Index: gcc.target/mips/umips-lwp-swp-volatile.c
> ===================================================================
> --- gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
> +++ gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
> @@ -0,0 +1,41 @@
> +/* { dg-do compile } */
> +
> +/* This test ensures that we do not generate microMIPS SWP or LWP
> +   instructions when any component of the accessed memory is volatile; 
> +   they are unsafe for such since they might cause replay of partial 
> +   accesses if interrupted by an exception.  */
> +
> +static void set_csr (volatile void *p, int v)
> +{
> +  *(volatile int *) (p) = v;
> +}
> +
> +static int get_csr (volatile void *p)
> +{
> +  return *(volatile int *) (p);
> +}
> +
> +int main ()
> +{
> +  int i, q = 0, p = 0, r = 0;
> +
> +  for (i = 0; i < 20; i++)
> +    {
> +      set_csr ((volatile void *) 0xbf0100a8, 0xffff0002);
> +      set_csr ((volatile void *) 0xbf0100a4, 0x80000008);
> +    }
> +
> +  for (i = 0; i < 20; i++)
> +    {
> +      register int k, j;
> +      k = get_csr ((volatile void *) 0xbf0100b8);
> +      p += k;
> +      j = get_csr ((volatile void *) 0xbf0100b4);
> +      r += j;
> +      q = j + k;
> +    }
> +  return q + r + p;
> +}
> +
> +/* { dg-final { scan-assembler-not "\tswp" } } */
> +/* { dg-final { scan-assembler-not "\tlwp" } } */

Please add:

  /* { dg-options "-mmicromips" } */

here.  ("-mmicromips" rather than "(-mmicromips)" because this is one
test where I think it makes more sense to force microMIPS mode throughout
the whole file.)

> Index: doc/md.texi
> ===================================================================
> --- doc/md.texi	(revision 195900)
> +++ doc/md.texi	(working copy)
> @@ -2916,6 +2916,19 @@ Floating-point zero.
>  
>  @item R
>  An address that can be used in a non-macro load or store.
> +
> +@item ZC
> +When compiling microMIPS code, this constraing matches a memory operand

Missing the s/contraing/constraint/ fix mentioned last time.  (You fixed
it in constraints.md though, thanks.)

> +(define_insn "*swp"
> +  [(parallel [(set (match_operand:SI 0 "non_volatile_mem_operand")
> +		   (match_operand:SI 1 "d_operand"))
> +	      (set (match_operand:SI 2 "non_volatile_mem_operand")
> +		   (match_operand:SI 3 "d_operand"))])]
> +
> +  "TARGET_MICROMIPS
> +   && umips_load_store_pair_p (false, operands)"
> +{
> +  umips_output_load_store_pair (false, operands);
> +  return "";
> +}
> +  [(set_attr "type" "store")
> +   (set_attr "mode" "SI")
> +   (set_attr "can_delay" "no")])

;; The behavior of the SWP insn is undefined if placed in a delay slot.

> @@ -5447,11 +5464,20 @@
>  	 (pc)))]
>    "!TARGET_MIPS16"
>  {
> +  /* For a simple BNEZ or BEQZ microMIPS branch.  */
> +  if (TARGET_MICROMIPS
> +      && operands[3] == const0_rtx
> +      && get_attr_length (insn) <= 8)
> +    return mips_output_conditional_branch (insn, operands,
> +					   "%*b%C1z%:\t%2,%0",
> +					   "%*b%N1z%:\t%2,%0");
> +    
>    return mips_output_conditional_branch (insn, operands,
>  					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
>  					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
>  }
> -  [(set_attr "type" "branch")])
> +  [(set_attr "type" "branch")
> +   (set_attr "mode" "none")])
>  

Minor, sorry, but please don't add the mode attribute.  (You didn't add
it to the inverted case, thanks.)

>    if (TREE_CODE (decl) != FUNCTION_DECL)
>      {
> -      if (mips16_p)
> -	error ("%qs attribute only applies to functions", "mips16");
> -      if (nomips16_p)
> -	error ("%qs attribute only applies to functions", "nomips16");
> +      if (nocompression_flags)
> +	error ("%qs attribute only applies to function",
> +	       mips_get_compress_off_name (nocompression_flags));
> +
> +      if (compression_flags)
> +	error ("%qs attribute only applies to function",
> +	       mips_get_compress_on_name (nocompression_flags));

Sorry, didn't notice this before, but we're losing the plural here.
The old error message (with "functions") was correct.

>      }
>    else
>      {
> -      mips16_p |= mips_mips16_decl_p (decl);
> -      nomips16_p |= mips_nomips16_decl_p (decl);
> -      if (mips16_p || nomips16_p)
> +      compression_flags |= mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
> +      nocompression_flags |=
> +	mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
> +
> +      if (compression_flags && nocompression_flags)
> +	error ("%qE cannot have both %qs and %qs attributes",
> +	       DECL_NAME (decl), mips_get_compress_on_name (compression_flags),
> +	       mips_get_compress_off_name (nocompression_flags));
> +
> +      if (compression_flags & MASK_MIPS16
> +          && compression_flags & MASK_MICROMIPS)
> +	error ("%qE cannot have both %s and %s attributes",
> +	       DECL_NAME (decl), "mips16", "micromips");

The first error message is right, but the second one should be the same
("%qs" instead of "%s", so that the name gets quoted).

> +
> +      if (TARGET_FLIP_MIPS16
> +	  && !DECL_ARTIFICIAL (decl)
> +	  && compression_flags == 0
> +	  && nocompression_flags == 0)
>  	{
> -	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
> -	  if (mips16_p && nomips16_p)
> -	    error ("%qE cannot have both %<mips16%> and "
> -		   "%<nomips16%> attributes",
> -		   DECL_NAME (decl));
> -	}
> -      else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
> -	{
>  	  /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
>  	     "mips16" attribute, arbitrarily pick one.  We must pick the same
>  	     setting for duplicate declarations of a function.  */
>  	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
> +	  name = "nomips16";
> + 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
> +	  name = "nomicromips";
>  	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);

As I mentioned last time, this unconditionally overrides the first "name"
assignment.  I think it should be correct with:

	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
	  name = "nomicromips";
	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);

> +/* Return true if a call to DECL may need to use JALX.  */
> +
> +static bool
> +mips_call_may_need_jalx_p (tree decl)
> +{
> +  /* If the current translation unit would use a different mode for DECL,
> +     assume that the call needs JALX.  */
> +  if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
> +    return true;
> +
> +  /* mips_get_compress_mode is always accurate for locally-binding
> +     functions in the current translation unit.  */
> +  if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
> +    return false;
> +
> +  /* When -minterlink-compressed is in effect, assume that functions
> +     could use a different encoding mode unless an attribute explicitly
> +     tells us otherwise.  */
> +  if (TARGET_INTERLINK_COMPRESSED)
> +    {
> +      if (!TARGET_COMPRESSION
> +	  && mips_get_compress_off_flags
> +	       (TYPE_ATTRIBUTES (TREE_TYPE (decl))) ==0)
> +	return true;
> +      if (TARGET_COMPRESSION
> +	  && mips_get_compress_on_flags
> +	       (TYPE_ATTRIBUTES (TREE_TYPE (decl))) == 0)

This should be DECL_ATTRIBUTES (decl) rather than TYPE_ATTRIBUTES (...):

      if (!TARGET_COMPRESSION
	  && mips_get_compress_off_flags (DECL_ATTRIBUTES (decl)) == 0)
	return true;
      if (TARGET_COMPRESSION
	  && mips_get_compress_on_flags (DECL_ATTRIBUTES (decl)) == 0)
	return true;

> +/* Capture the register combinations that are allowed in a SWM or LWM
> +   instruction.  The entries are ordered by number of registers set in
> +   the mask.  We also ignore the single register encodings because a
> +   normal SW/LW is preferred.  */
> +   
> +static const unsigned int umips_swm_mask[17] = {
> +  0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
> +  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,	
> +  0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
> +  0x000f0000, 0x80030000, 0x00070000, 0x80010000,
> +  0x00030000 };
> +
> +static const unsigned int umips_swm_encoding[17] = {
> +  25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2 };

You missed the bit from last time about "};" being on its own line:

static const unsigned int umips_swm_mask[17] = {
  0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,	
  0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
  0x000f0000, 0x80030000, 0x00070000, 0x80010000,
  0x00030000
};

static const unsigned int umips_swm_encoding[17] = {
  25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2
};

> @@ -16437,14 +16693,19 @@ mips_option_override (void)
>    if (global_options_set.x_mips_isa_option)
>      mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
>  
> -  /* Process flags as though we were generating non-MIPS16 code.  */
> -  mips_base_mips16 = TARGET_MIPS16;
> -  target_flags &= ~MASK_MIPS16;
> -
>  #ifdef SUBTARGET_OVERRIDE_OPTIONS
>    SUBTARGET_OVERRIDE_OPTIONS;
>  #endif
>  
> +  /* MIPS16 and microMIPS cannot coexist  */

Missing period ("/* MIPS16 and microMIPS cannot coexist.  */")

> +  if (TARGET_MICROMIPS && TARGET_MIPS16)
> +    error ("unsupported combination: %s", "-mips16 -mmicromips");
> +
> +  /* Save the base compression state and process flags as though we
> +     are generating uncompressed code.  */
> +  mips_base_compression_flags = TARGET_COMPRESSION;
> +  target_flags &= ~TARGET_COMPRESSION;
> +
>    /* -mno-float overrides -mhard-float and -msoft-float.  */
>    if (TARGET_NO_FLOAT)
>      {

s/as though we are/as though we were/ (as in the original comment).

> +/* Return true if MEM1 and MEM2 use the same base register, and the
> +   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
> +   register into (from) which the contents of MEM1 will be loaded
> +   (stored), depending on the value of LOAD_P.
> +   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
> +
> +static bool
> +umips_load_store_pair_p_1 (bool load_p, rtx first_reg, rtx mem1, rtx mem2)

We still need the swap_p paramter (which is still mentioned in the comment),
because we want to test it here:

> +  /* We must avoid this case for anti-dependence.
> +     Ex:  lw $3, 4($3)
> +          lw $2, 0($3)
> +     first_reg is $2, but the base is $3.  */
> +  if (load_p
> +      && REGNO (first_reg) + 1 == REGNO (base1))
> +    return false;

The old code was right about that, it was the offset stuff that seemed wrong.

Looks good otherwise, but please post an updated patch.  It's probably
stating the obvious, but the patch is too invasive for this late stage
of 4.8, so it'll need to wait until 4.9.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-19 18:25                 ` Richard Sandiford
@ 2013-02-19 22:27                   ` Maciej W. Rozycki
  2013-02-21  2:28                   ` Moore, Catherine
  1 sibling, 0 replies; 41+ messages in thread
From: Maciej W. Rozycki @ 2013-02-19 22:27 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Moore, Catherine, gcc-patches

On Tue, 19 Feb 2013, Richard Sandiford wrote:

> > Index: gcc.target/mips/umips-lwp-swp-2.c
> > ===================================================================
> > --- gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
> > +++ gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
> > @@ -0,0 +1,19 @@
> > +/* { dg-options "-mgp32 (-mmicromips)" } */
> > +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" "-Os" } { "" } } */
> > +int a[2];
> > +
> > +MICROMIPS f (b)
> > +{
> > +  unsigned int i;
> > +  int *p;
> > +  for (p = &a[b], i = b; --i < ~0; )
> > +    *--p = i * 3 + (int)a;
> > +
> > +}
> > +
> > +MICROMIPS main ()
> > +{
> > +  a[0] = a[1] = 0;
> > +  f (2);
> > +}
> > +/* { dg-final { scan-assembler "\tswp\t\\\$3,0\\(\\\$3\\)" } }*/
> 
> Is this a test of the swap_p case?  Thanks if so, but could you add a
> comment saying where the SWP gets generated, and why the test needs
> to be skipped at -O1 and -Os?

 TBH, it is -Os where size really matters, so IMHO it is the -Os 
optimisation level where LWP/SWP should be used where possible in the 
first place, even if it hurts performance for some reason (and where e.g. 
-O2 might decide to go for individual accesses instead).

 Not to be meant as a show-stopper for this initial implementation, but if 
the optimisation does not work for LWP/SWP at -Os for some reason, then I 
think there's something going seriously wrong somewhere (instruction 
lengths set wrong for example?) which looks to me worth investigating and 
acting upon accordingly as the next step.

 I saw cases with instruction lengths set too high with our trunk just 
about yesterday and MIPS16 code, e.g.:

	.file	1 "foo.c"
	.section .mdebug.abi32
	.previous
	.gnu_attribute 4, 1
	.abicalls
	.option	pic0
	.text
	.align	2
	.globl	foo
	.set	mips16
	.ent	foo
	.type	foo, @function
foo:
	.frame	$sp,32,$31		# vars= 0, regs= 1/0, args= 16, gp= 8
	.mask	0x80000000,-4
	.fmask	0x00000000,0
	save	32,$31	 # 11	*mips16e_save_restore	[length = 4]
	.set	noreorder
	.set	nomacro
	jal	bar	 # 22	call_split/2	[length = 8]
	li	$4,0	 # 5	*movsi_mips16/4	[length = 4]
	.set	macro
	.set	reorder

	restore	32,$31	 # 18	*mips16e_save_restore	[length = 4]
	j	$31	 # 20	simple_return_internal	[length = 2]
	.end	foo
	.size	foo, .-foo

-- it looks all wrong to me except for the final J.  Of course I realise 
where it originally comes from, but I think it would be good if the 
initial pessimistic estimates were actually adjusted as more is known 
about actual insns produced.

 I wonder if we may have similar issues with microMIPS instruction size 
calculation triggering here.

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-19 18:25                 ` Richard Sandiford
  2013-02-19 22:27                   ` Maciej W. Rozycki
@ 2013-02-21  2:28                   ` Moore, Catherine
  2013-02-21 21:20                     ` Richard Sandiford
  1 sibling, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-02-21  2:28 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej, Moore, Catherine

[-- Attachment #1: Type: text/plain, Size: 3469 bytes --]



> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Tuesday, February 19, 2013 1:25 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> Thanks, this is looking much better now.
> 
> 
> > Index: gcc.target/mips/umips-constraints-1.c
> >
> ==========================================================
> =========
> > --- gcc.target/mips/umips-constraints-1.c	(revision 0)
> > +++ gcc.target/mips/umips-constraints-1.c	(revision 0)
> > @@ -0,0 +1,14 @@
> > +/* { dg-options "(-mmicromips)" } */
> > +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> > +
> > +MICROMIPS void
> > +foo (int *x)
> > +{
> > +  asm volatile ("insn1\t%a0" :: "ZD" (&x[0]));
> > +  asm volatile ("insn2\t%a0" :: "ZD" (&x[511]));
> > +  asm volatile ("insn3\t%a0" :: "ZD" (&x[512])); }
> > +
> > +/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
> > +/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
> > +/* { dg-final { scan-assembler "\tinsn3\t2048\\(" } } */
> 
> But the insn3 is wrong, isn't it?  I suggested scan-assembler-not for that one
> because I thought it had to be a 12-bit signed offset on microMIPS.  The
> patch has:
> 
Yes, it was wrong.  Now fixed.

> 
> Sorry, only just realised you were skipping -O1.  Please add a comment saying
> why it fails at -O1 or (preferably) add whichever other option is needed for
> the test to pass at -O1.  I assume it's -fpeephole2 in this case.
> 
> Same for all tests with this skip.

-fpeephole2 did the trick.

> 
> > Index: gcc.target/mips/umips-lwp-swp-2.c
> >
> ==========================================================
> =========
> > --- gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
> > +++ gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
> > @@ -0,0 +1,19 @@
> > +/* { dg-options "-mgp32 (-mmicromips)" } */
> > +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" "-O1" "-Os" } {
> > +"" } } */ int a[2];
> > +
> > +MICROMIPS f (b)
> > +{
> > +  unsigned int i;
> > +  int *p;
> > +  for (p = &a[b], i = b; --i < ~0; )
> > +    *--p = i * 3 + (int)a;
> > +
> > +}
> > +
> > +MICROMIPS main ()
> > +{
> > +  a[0] = a[1] = 0;
> > +  f (2);
> > +}
> > +/* { dg-final { scan-assembler "\tswp\t\\\$3,0\\(\\\$3\\)" } }*/
> 
> Is this a test of the swap_p case?  Thanks if so, but could you add a comment
> saying where the SWP gets generated, and why the test needs to be skipped
> at -O1 and -Os?
> 
Yes,  this was the swap_p case.  But it turns out that umips-lpw-swp-1.c was also testing the swap_p case.  I've now dropped this test in favor of a different test that exercises the swap_p = false case.
You had mentioned testing for explicit registers.  This is turning out to be problematic.  The Linux and ELF tool chains don't always use the same register set.  In addition, -O3 seems to expose more opportunities for generating these instructions so the code generated isn't consistent among optimization options.  I've changed it back to just testing for swp, but I'm open to other suggestions.  

> 
> Looks good otherwise, but please post an updated patch.  It's probably
> stating the obvious, but the patch is too invasive for this late stage of 4.8, so
> it'll need to wait until 4.9.
> 

The updated patch is attached.  How's it looking this time?

Thanks,
Catherine

[-- Attachment #2: gcc.cl --]
[-- Type: application/octet-stream, Size: 5345 bytes --]

2013-02-12  Catherine Moore  <clm@codesourcery.com>
	    Maciej W. Rozycki  <macro@codesourcery.com>
	    Tom de Vries  <tom@codesourcery.com>
	    Nathan Sidwell <nathan@codesourcery.com>
	    Iain Sandoe  <iain@codesourcery.com>
	    Nathan Froyd  <froydnj@codesourcery.com>
	    Chao-ying Fu <fu@mips.com>

	* doc/extend.texi: (micromips, nomicromips, nocompression):
	Document new function attributes. 
	* doc/invoke.texi (minterlink-compressed, mmicromips,
	m14k, m14ke, m14kec): Document new options.
	(minterlink-mips16): Update documentation.
	* doc/md.texi (ZC, ZD): Document new constraints.
	* configure.ac (gcc_cv_as_micromips): Check if linker
	supports the .set micromips directive.
	* configure: Regenerate.
	* config.in: Regenerate.
	* config/mips/mips-tables.opt: Regenerate.
	* config/mips/micromips.md: New file.
	* constraints.md (ZC, AD): New constraints.
	* config/mips/predicates.md (movep_src_register): New predicate.
	(movep_src_operand): New predicate.
	(non_volatile_mem_operand): New predicate.
	* config/mips/mips.md (multimem): New type.
	(length): Differentiate between 17-bit and 18-bit branch offsets.
	(MOVEP1, MOVEP2): New mode iterator.
 	(mov_<load>l): Use ZC constraint.
	(mov_<load>r): Likewise.
	(mov_<store>l): Likewise.
	(mov_<store>r): Likewise.
	(*branch_equality<mode>_inverted): Add microMIPS support.
	(*branch_equality<mode>): Likewise.
	(*jump_absolute): Likewise.
	(indirect_jump_<mode>): Likewise.
	(tablejump_<mode>): Likewise.
	(<optab>_internal): Likewise.
	(sibcall_internal): Likewise.
	(sibcall_value_internal): Likewise.
	(prefetch): Use constraint ZD.
	* config/mips/mips.opt (minterlink-compressed): New option.
	(minterlink-mips16): Now an alias for minterlink-compressed.
	(mmicromips): New option.
	* config/mips/sync.md (sync_compare_and_swap<mode>): Use ZR constraint.
	(compare_and_swap_12): Likewise.
	(sync_add<mode>): Likewise.
	(sync_<optab>_12): Likewise.
	(sync_old_<optab>_12): Likewise.
	(sync_new_<optab>_12): Likewise.
	(sync_nand_12): Likewise.
	(sync_old_nand_12): Likewise.
	(sync_new_nand_12): Likewise.
	(sync_sub<mode>): Likewise.
	(sync_old_add<mode>): Likewise.
	(sync_old_sub<mode>): Likewise.
	(sync_new_add<mode>): Likewise.
	(sync_new_sub<mode>): Likewise.
	(sync_<optab><mode>): Likewise.
	(sync_old_<optab><mode>): Likewise.
	(sync_new_<optab><mode>): Likewise.
	(sync_nand<mode>): Likewise.
	(sync_old_nand<mode>): Likewise.
	(sync_new_nand<mode>): Likewise.
	(sync_lock_test_and_set<mode>): Likewise.
	(test_and_set_12): Likewise.
	(atomic_compare_and_swap<mode>): Likewise.
	(atomic_exchange<mode>_llsc): Likewise.
	(atomic_fetch_add<mode>_llsc): Likewise.
	* config/mips/mips-cpus.def (m14kc, m14k): New processors.
	* config/mips/mips-protos.h (umips_output_save_restore): New prototype.
	(umips_save_restore_pattern_p): Likewise.
	(umips_load_store_pair_p): Likewise.
	(umips_output_load_store_pair): Likewise.
	(umips_movep_target_p): Likewise.
	(umips_12bit_offset_address_p): Likewise.
	* config/mips/mips.c (MIPS_MAX_FIRST_STEP): Update for microMIPS.
	(mips_base_mips16): Rename this...
	(mips_base_compression_flags): ...to this. Update all uses.
	(mips_attribute_table): Add micromips, nomicromips and nocompression.
	(mips_mips16_decl_p): Delete.
	(mips_nomips16_decl_p): Delete.
 	(mips_get_compress_on_flags): New function.
	(mips_get_compress_off_flags): New function.
	(mips_get_compress_mode): New function.
	(mips_get_compress_on_name): New function.
	(mips_get_compress_off_name): New function.
	(mips_insert_attributes): Support multiple compression types.
	(mips_merge_decl_attributes): Likewise.
	(umips_12bit_offset_address_p): New function.
	(mips_start_function_definition): Emit .set micromips directive.
	(mips_call_may_need_jalx_p): New function.
	(mips_function_ok_for_sibcall): Add microMIPS support.
	(mips_print_operand_punctuation): Support short delay slots and
	compact jumps.
	(umips_swm_mask, umips_swm_encoding): New.
	(umips_build_save_restore): New function.
	(mips_for_each_saved_gpr_and_fpr): Add microMIPS support.
	(was_mips16_p): Remove.
	(old_compression_mode): New.
	(mips_set_compression_mode): New function.
	(mips_set_current_function): Add microMIPS support.
	(mips_option_override): Likewise.
	(umips_save_restore_pattern_p): New function.
	(umips_output_save_restore): New function.
	(umips_load_store_pair_p_1): New function.
	(umips_load_store_pair_p): New function.
	(umips_output_load_store_pair_1): New function.
	(umips_output_load_store_pair): New function.
	(umips_movep_target_p) New function.
	(mips_prepare_pch_save): Add microMIPS support.
	* config/mips/mips.h (TARGET_COMPRESSION): New.
	(TARGET_CPU_CPP_BUILTINS): Update macro
	to use new compression flags and to support microMIPS.
	(MIPS_ISA_LEVEL_SPEC): Add m14k processors.
	(MIPS_ARCH_FLOAT_SPEC): Likewise.
	(ISA_HAS_LWXS): Include TARGET_MICROMIPS.
	(ASM_SPEC): Support mmicromips and mno-micromips.
	(M16STORE_REG_P): New macro.
	(MIPS_CALL): Support TARGET_MICROMIPS.
	(MICROMIPS_J): New macro.
	(mips_base_mips16): Rename this...
	(mips_base_compression_flags): ...to this.
	(UMIPS_12BIT_OFFSET_P): New macro.
	* config/mips/t-sde: (MULTILIB_OPTIONS): Add microMIPS.
	(MULTILIB_DIRNAMES): Likewise.

[-- Attachment #3: gcc.patch --]
[-- Type: application/octet-stream, Size: 90162 bytes --]

Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 195900)
+++ doc/extend.texi	(working copy)
@@ -3053,6 +3053,25 @@ not that within individual functions.  Mixed MIPS1
 may interact badly with some GCC extensions such as @code{__builtin_apply}
 (@pxref{Constructing Calls}).
 
+@item micromips/nomicromips
+@cindex @code{micromips} attribute
+@cindex @code{nomicromips} attribute
+
+On MIPS targets, you can use the @code{micromips} and @code{nomicromips}
+function attributes to locally select or turn off microMIPS code generation.
+A function with the @code{micromips} attribute is emitted as microMIPS code,
+while microMIPS code generation is disabled for functions with the
+@code{nomicromips} attribute.  These attributes override the
+@option{-mmicromips} and @option{-mno-micromips} options on the command line
+(@pxref{MIPS Options}).
+
+When compiling files containing mixed microMIPS and non-microMIPS code, the
+preprocessor symbol @code{__mips_micromips} reflects the setting on the
+command line,
+not that within individual functions.  Mixed microMIPS and non-microMIPS code
+may interact badly with some GCC extensions such as @code{__builtin_apply}
+(@pxref{Constructing Calls}).
+
 @item model (@var{model-name})
 @cindex function addressability on the M32R/D
 @cindex variable addressability on the IA-64
@@ -3155,6 +3174,13 @@ is an NMI handler.  The compiler generates functio
 exit sequences suitable for use in an NMI handler when this
 attribute is present.
 
+@item nocompression
+@cindex @code{nocompression} attribute
+On MIPS targets, you can use the @code{nocompression} function attribute
+to locally turn off MIPS16 and microMIPS code generation.  This attribute
+overrides the @option{-mips16} and @option{-mmicromips} options on the
+command line (@pxref{MIPS Options}).
+
 @item no_instrument_function
 @cindex @code{no_instrument_function} function attribute
 @opindex finstrument-functions
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 195900)
+++ doc/invoke.texi	(working copy)
@@ -740,6 +740,7 @@ Objective-C and Objective-C++ Dialects}.
 -mips1  -mips2  -mips3  -mips4  -mips32  -mips32r2 @gol
 -mips64  -mips64r2 @gol
 -mips16  -mno-mips16  -mflip-mips16 @gol
+-minterlink-compressed -mno-interlink-compressed @gol
 -minterlink-mips16  -mno-interlink-mips16 @gol
 -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
@@ -747,6 +748,7 @@ Objective-C and Objective-C++ Dialects}.
 -mno-float -msingle-float  -mdouble-float  @gol
 -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -mmcu -mmno-mcu @gol
+-mmicromips -mno-micromips @gol
 -mfpu=@var{fpu-type} @gol
 -msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
@@ -15880,6 +15882,7 @@ The processor names are:
 @samp{1004kc}, @samp{1004kf2_1}, @samp{1004kf1_1},
 @samp{loongson2e}, @samp{loongson2f}, @samp{loongson3a},
 @samp{m4k},
+@samp{m14k}, @samp{m14ke}, @samp{m14kec},
 @samp{octeon}, @samp{octeon+}, @samp{octeon2},
 @samp{orion},
 @samp{r2000}, @samp{r3000}, @samp{r3900}, @samp{r4000}, @samp{r4400},
@@ -15993,18 +15996,26 @@ Generate MIPS16 code on alternating functions.  Th
 for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
 not intended for ordinary use in compiling user code.
 
+@item -minterlink-compressed
+@item -mno-interlink-compressed
+@opindex minterlink-compressed
+@opindex mno-interlink-compressed
+Require (do not require) that code using the standard (uncompressed) MIPS ISA
+be link-compatible with MIPS16 and microMIPS code, and vice versa.
+
+For example, code using the standard ISA encoding cannot jump directly
+to MIPS16 or microMIPS code; it must either use a call or an indirect jump.
+@option{-minterlink-compressed} therefore disables direct jumps unless GCC
+knows that the target of the jump is not compressed.
+
 @item -minterlink-mips16
 @itemx -mno-interlink-mips16
 @opindex minterlink-mips16
 @opindex mno-interlink-mips16
-Require (do not require) that non-MIPS16 code be link-compatible with
-MIPS16 code.
+Aliases of @option{-minterlink-compressed} and
+@option{-mno-interlink-compressed}.  These options predate the microMIPS ASE
+and are retained for backwards compatiblity.
 
-For example, non-MIPS16 code cannot jump directly to MIPS16 code;
-it must either use a call or an indirect jump.  @option{-minterlink-mips16}
-therefore disables direct jumps unless GCC knows that the target of the
-jump is not MIPS16.
-
 @item -mabi=32
 @itemx -mabi=o64
 @itemx -mabi=n32
@@ -16218,6 +16229,16 @@ hardware floating-point support to be enabled.
 Use (do not use) the MIPS-3D ASE@.  @xref{MIPS-3D Built-in Functions}.
 The option @option{-mips3d} implies @option{-mpaired-single}.
 
+@item -mmicromips
+@itemx -mno-micromips
+@opindex mmicromips
+@opindex mno-mmicromips
+Generate (do not generate) microMIPS code.
+
+MicroMIPS code generation can also be controlled on a per-function basis
+by means of @code{micromips} and @code{nomicromips} attributes.
+@xref{Function Attributes}, for more information.
+
 @item -mmt
 @itemx -mno-mt
 @opindex mmt
Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 195900)
+++ doc/md.texi	(working copy)
@@ -2916,6 +2916,19 @@ Floating-point zero.
 
 @item R
 An address that can be used in a non-macro load or store.
+
+@item ZC
+When compiling microMIPS code, this constraint matches a memory operand
+whose address is formed from a base register and a 12-bit offset.  These
+operands can be used for microMIPS instructions such as @code{ll} and
+@code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+equivalent to @code{R}.
+
+@item ZD
+When compiling microMIPS code, this constraint matches an address operand
+that is formed from a base register and a 12-bit offset.  These operands
+can be used for microMIPS instructions such as @code{prefetch}.  When
+not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}.
 @end table
 
 @item Motorola 680x0---@file{config/m68k/constraints.md}
Index: configure
===================================================================
--- configure	(revision 195900)
+++ configure	(working copy)
@@ -25708,6 +25708,37 @@ $as_echo "#define HAVE_AS_GNU_ATTRIBUTE 1" >>confd
 
 fi
 
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .micromips support" >&5
+$as_echo_n "checking assembler for .micromips support... " >&6; }
+if test "${gcc_cv_as_micromips_support+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_micromips_support=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '.set micromips' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_micromips_support=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_micromips_support" >&5
+$as_echo "$gcc_cv_as_micromips_support" >&6; }
+if test $gcc_cv_as_micromips_support = yes; then
+
+$as_echo "#define HAVE_GAS_MICROMIPS 1" >>confdefs.h
+
+fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .dtprelword support" >&5
 $as_echo_n "checking assembler for .dtprelword support... " >&6; }
 if test "${gcc_cv_as_mips_dtprelword+set}" = set; then :
Index: config.in
===================================================================
--- config.in	(revision 195900)
+++ config.in	(working copy)
@@ -1034,6 +1034,12 @@
 #endif
 
 
+/* Define if your assembler supports the .set micromips directive */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GAS_MICROMIPS
+#endif
+
+
 /* Define if your assembler supports .nsubspa comdat option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GAS_NSUBSPA_COMDAT
Index: configure.ac
===================================================================
--- configure.ac	(revision 195900)
+++ configure.ac	(working copy)
@@ -4036,6 +4036,12 @@ LCF0:
       [AC_DEFINE(HAVE_AS_GNU_ATTRIBUTE, 1,
 	  [Define if your assembler supports .gnu_attribute.])])
 
+    gcc_GAS_CHECK_FEATURE([.micromips support],
+      gcc_cv_as_micromips_support,,,
+      [.set micromips],,
+      [AC_DEFINE(HAVE_GAS_MICROMIPS, 1,
+          [Define if your assembler supports the .set micromips directive])])
+
     gcc_GAS_CHECK_FEATURE([.dtprelword support],
       gcc_cv_as_mips_dtprelword, [2,18,0],,
       [.section .tdata,"awT",@progbits
Index: config/mips/mips-tables.opt
===================================================================
--- config/mips/mips-tables.opt	(revision 195900)
+++ config/mips/mips-tables.opt	(working copy)
@@ -373,254 +373,260 @@ EnumValue
 Enum(mips_arch_opt_value) String(m4k) Value(39) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kec) Value(40) Canonical
+Enum(mips_arch_opt_value) String(m14kc) Value(40) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kec) Value(40)
+Enum(mips_arch_opt_value) String(m14k) Value(41) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kem) Value(41) Canonical
+Enum(mips_arch_opt_value) String(4kec) Value(42) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kem) Value(41)
+Enum(mips_arch_opt_value) String(r4kec) Value(42)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kep) Value(42) Canonical
+Enum(mips_arch_opt_value) String(4kem) Value(43) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kep) Value(42)
+Enum(mips_arch_opt_value) String(r4kem) Value(43)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4ksd) Value(43) Canonical
+Enum(mips_arch_opt_value) String(4kep) Value(44) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4ksd) Value(43)
+Enum(mips_arch_opt_value) String(r4kep) Value(44)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kc) Value(44) Canonical
+Enum(mips_arch_opt_value) String(4ksd) Value(45) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kc) Value(44)
+Enum(mips_arch_opt_value) String(r4ksd) Value(45)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf2_1) Value(45) Canonical
+Enum(mips_arch_opt_value) String(24kc) Value(46) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf2_1) Value(45)
+Enum(mips_arch_opt_value) String(r24kc) Value(46)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf) Value(46) Canonical
+Enum(mips_arch_opt_value) String(24kf2_1) Value(47) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf) Value(46)
+Enum(mips_arch_opt_value) String(r24kf2_1) Value(47)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf1_1) Value(47) Canonical
+Enum(mips_arch_opt_value) String(24kf) Value(48) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf1_1) Value(47)
+Enum(mips_arch_opt_value) String(r24kf) Value(48)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kfx) Value(48) Canonical
+Enum(mips_arch_opt_value) String(24kf1_1) Value(49) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kfx) Value(48)
+Enum(mips_arch_opt_value) String(r24kf1_1) Value(49)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kx) Value(49) Canonical
+Enum(mips_arch_opt_value) String(24kfx) Value(50) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kx) Value(49)
+Enum(mips_arch_opt_value) String(r24kfx) Value(50)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kec) Value(50) Canonical
+Enum(mips_arch_opt_value) String(24kx) Value(51) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kec) Value(50)
+Enum(mips_arch_opt_value) String(r24kx) Value(51)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef2_1) Value(51) Canonical
+Enum(mips_arch_opt_value) String(24kec) Value(52) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef2_1) Value(51)
+Enum(mips_arch_opt_value) String(r24kec) Value(52)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef) Value(52) Canonical
+Enum(mips_arch_opt_value) String(24kef2_1) Value(53) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef) Value(52)
+Enum(mips_arch_opt_value) String(r24kef2_1) Value(53)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef1_1) Value(53) Canonical
+Enum(mips_arch_opt_value) String(24kef) Value(54) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef1_1) Value(53)
+Enum(mips_arch_opt_value) String(r24kef) Value(54)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kefx) Value(54) Canonical
+Enum(mips_arch_opt_value) String(24kef1_1) Value(55) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kefx) Value(54)
+Enum(mips_arch_opt_value) String(r24kef1_1) Value(55)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kex) Value(55) Canonical
+Enum(mips_arch_opt_value) String(24kefx) Value(56) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kex) Value(55)
+Enum(mips_arch_opt_value) String(r24kefx) Value(56)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kc) Value(56) Canonical
+Enum(mips_arch_opt_value) String(24kex) Value(57) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kc) Value(56)
+Enum(mips_arch_opt_value) String(r24kex) Value(57)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf2_1) Value(57) Canonical
+Enum(mips_arch_opt_value) String(34kc) Value(58) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf2_1) Value(57)
+Enum(mips_arch_opt_value) String(r34kc) Value(58)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf) Value(58) Canonical
+Enum(mips_arch_opt_value) String(34kf2_1) Value(59) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf) Value(58)
+Enum(mips_arch_opt_value) String(r34kf2_1) Value(59)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf1_1) Value(59) Canonical
+Enum(mips_arch_opt_value) String(34kf) Value(60) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf1_1) Value(59)
+Enum(mips_arch_opt_value) String(r34kf) Value(60)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kfx) Value(60) Canonical
+Enum(mips_arch_opt_value) String(34kf1_1) Value(61) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kfx) Value(60)
+Enum(mips_arch_opt_value) String(r34kf1_1) Value(61)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kx) Value(61) Canonical
+Enum(mips_arch_opt_value) String(34kfx) Value(62) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kx) Value(61)
+Enum(mips_arch_opt_value) String(r34kfx) Value(62)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kn) Value(62) Canonical
+Enum(mips_arch_opt_value) String(34kx) Value(63) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kn) Value(62)
+Enum(mips_arch_opt_value) String(r34kx) Value(63)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kc) Value(63) Canonical
+Enum(mips_arch_opt_value) String(34kn) Value(64) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kc) Value(63)
+Enum(mips_arch_opt_value) String(r34kn) Value(64)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf2_1) Value(64) Canonical
+Enum(mips_arch_opt_value) String(74kc) Value(65) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf2_1) Value(64)
+Enum(mips_arch_opt_value) String(r74kc) Value(65)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf) Value(65) Canonical
+Enum(mips_arch_opt_value) String(74kf2_1) Value(66) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf) Value(65)
+Enum(mips_arch_opt_value) String(r74kf2_1) Value(66)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf1_1) Value(66) Canonical
+Enum(mips_arch_opt_value) String(74kf) Value(67) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf1_1) Value(66)
+Enum(mips_arch_opt_value) String(r74kf) Value(67)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kfx) Value(67) Canonical
+Enum(mips_arch_opt_value) String(74kf1_1) Value(68) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kfx) Value(67)
+Enum(mips_arch_opt_value) String(r74kf1_1) Value(68)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kx) Value(68) Canonical
+Enum(mips_arch_opt_value) String(74kfx) Value(69) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kx) Value(68)
+Enum(mips_arch_opt_value) String(r74kfx) Value(69)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf3_2) Value(69) Canonical
+Enum(mips_arch_opt_value) String(74kx) Value(70) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf3_2) Value(69)
+Enum(mips_arch_opt_value) String(r74kx) Value(70)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kc) Value(70) Canonical
+Enum(mips_arch_opt_value) String(74kf3_2) Value(71) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kc) Value(70)
+Enum(mips_arch_opt_value) String(r74kf3_2) Value(71)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf2_1) Value(71) Canonical
+Enum(mips_arch_opt_value) String(1004kc) Value(72) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf2_1) Value(71)
+Enum(mips_arch_opt_value) String(r1004kc) Value(72)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf) Value(72) Canonical
+Enum(mips_arch_opt_value) String(1004kf2_1) Value(73) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf) Value(72)
+Enum(mips_arch_opt_value) String(r1004kf2_1) Value(73)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf1_1) Value(73) Canonical
+Enum(mips_arch_opt_value) String(1004kf) Value(74) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf1_1) Value(73)
+Enum(mips_arch_opt_value) String(r1004kf) Value(74)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kc) Value(74) Canonical
+Enum(mips_arch_opt_value) String(1004kf1_1) Value(75) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kc) Value(74)
+Enum(mips_arch_opt_value) String(r1004kf1_1) Value(75)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kf) Value(75) Canonical
+Enum(mips_arch_opt_value) String(5kc) Value(76) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kf) Value(75)
+Enum(mips_arch_opt_value) String(r5kc) Value(76)
 
 EnumValue
-Enum(mips_arch_opt_value) String(20kc) Value(76) Canonical
+Enum(mips_arch_opt_value) String(5kf) Value(77) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r20kc) Value(76)
+Enum(mips_arch_opt_value) String(r5kf) Value(77)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1) Value(77) Canonical
+Enum(mips_arch_opt_value) String(20kc) Value(78) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1a) Value(78) Canonical
+Enum(mips_arch_opt_value) String(r20kc) Value(78)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71000) Value(79) Canonical
+Enum(mips_arch_opt_value) String(sb1) Value(79) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71k) Value(79)
+Enum(mips_arch_opt_value) String(sb1a) Value(80) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlr) Value(80) Canonical
+Enum(mips_arch_opt_value) String(sr71000) Value(81) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(loongson3a) Value(81) Canonical
+Enum(mips_arch_opt_value) String(sr71k) Value(81)
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon) Value(82) Canonical
+Enum(mips_arch_opt_value) String(xlr) Value(82) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon+) Value(83) Canonical
+Enum(mips_arch_opt_value) String(loongson3a) Value(83) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon2) Value(84) Canonical
+Enum(mips_arch_opt_value) String(octeon) Value(84) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlp) Value(85) Canonical
+Enum(mips_arch_opt_value) String(octeon+) Value(85) Canonical
 
+EnumValue
+Enum(mips_arch_opt_value) String(octeon2) Value(86) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(xlp) Value(87) Canonical
+
Index: config/mips/micromips.md
===================================================================
--- config/mips/micromips.md	(revision 0)
+++ config/mips/micromips.md	(revision 0)
@@ -0,0 +1,128 @@
+;; Copyright (C) 2013 Free Software Foundation, Inc.
+;;
+;; micromips.md   Machine Description for the microMIPS instruction set
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_insn "*store_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "memory_operand")
+	     (match_operand:SI 2 "register_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (true, operands[0])"
+  { return umips_output_save_restore (true, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+(define_insn "*load_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "register_operand")
+	     (match_operand:SI 2 "memory_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (false, operands[0])"
+  { return umips_output_save_restore (false, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For LWP.
+(define_peephole2
+  [(set (match_operand:SI 0 "d_operand" "")
+        (match_operand:SI 1 "non_volatile_mem_operand" ""))
+   (set (match_operand:SI 2 "d_operand" "")
+        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+;; The behavior of the LWP insn is undefined if placed in a delay slot.
+(define_insn "*lwp"
+  [(parallel [(set (match_operand:SI 0 "d_operand")
+		   (match_operand:SI 1 "non_volatile_mem_operand"))
+	      (set (match_operand:SI 2 "d_operand")
+		   (match_operand:SI 3 "non_volatile_mem_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+{
+  umips_output_load_store_pair (true, operands);
+  return "";
+}
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For SWP.
+(define_peephole2
+  [(set (match_operand:SI 0 "non_volatile_mem_operand" "")
+        (match_operand:SI 1 "d_operand" ""))
+   (set (match_operand:SI 2 "non_volatile_mem_operand" "")
+        (match_operand:SI 3 "d_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+;; The behavior of the SWP insn is undefined if placed in a delay slot.
+(define_insn "*swp"
+  [(parallel [(set (match_operand:SI 0 "non_volatile_mem_operand")
+		   (match_operand:SI 1 "d_operand"))
+	      (set (match_operand:SI 2 "non_volatile_mem_operand")
+		   (match_operand:SI 3 "d_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+{
+  umips_output_load_store_pair (false, operands);
+  return "";
+}
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For MOVEP.
+(define_peephole2
+  [(set (match_operand:MOVEP1 0 "register_operand" "")
+        (match_operand:MOVEP1 1 "movep_src_operand" ""))
+   (set (match_operand:MOVEP2 2 "register_operand" "")
+        (match_operand:MOVEP2 3 "movep_src_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])]
+)
+
+;; The behavior of the MOVEP insn is undefined if placed in a delay slot.
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+		   (match_operand:MOVEP1 1 "movep_src_operand"))
+	      (set (match_operand:MOVEP2 2 "register_operand")
+		   (match_operand:MOVEP2 3 "movep_src_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+{
+  if (REGNO (operands[0]) < REGNO (operands[2]))
+    return "movep\t%0,%2,%z1,%z3";
+  else
+    return "movep\t%2,%0,%z3,%z1";
+}
+  [(set_attr "type" "move")
+   (set_attr "mode" "<MODE>")
+   (set_attr "can_delay" "no")])
Index: config/mips/constraints.md
===================================================================
--- config/mips/constraints.md	(revision 195900)
+++ config/mips/constraints.md	(working copy)
@@ -232,6 +232,26 @@
    "@internal"
    (match_operand 0 "low_bitmask_operand"))
 
+(define_memory_constraint "ZC"
+  "When compiling microMIPS code, this constraint matches a memory operand
+   whose address is formed from a base register and a 12-bit offset.  These
+   operands can be used for microMIPS instructions such as @code{ll} and
+   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+   equivalent to @code{R}."
+  (and (match_code "mem")
+       (if_then_else (match_test "TARGET_MICROMIPS")
+		     (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)")
+		     (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "ZD"
+  "When compiling microMIPS code, this constraint matches an address operand
+   that is formed from a base register and a 12-bit offset.  These operands
+   can be used for microMIPS instructions such as @code{prefetch}.  When
+   not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}."
+   (if_then_else (match_test "TARGET_MICROMIPS")
+		 (match_test "umips_12bit_offset_address_p (op, mode)")
+		 (match_test "mips_address_insns (op, mode, false)")))
+
 (define_memory_constraint "ZR"
  "@internal
   An address valid for loading/storing register exclusive"
Index: config/mips/predicates.md
===================================================================
--- config/mips/predicates.md	(revision 195900)
+++ config/mips/predicates.md	(working copy)
@@ -122,6 +122,15 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "movep_src_register"
+  (and (match_code "reg")
+       (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
+	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
+
+(define_predicate "movep_src_operand"
+  (ior (match_operand 0 "const_0_operand")
+       (match_operand 0 "movep_src_register")))
+
 (define_predicate "lo_operand"
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
@@ -371,3 +380,8 @@
 (define_predicate "mem_noofs_operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
+
+;; Return 1 if the operand is in non-volatile memory.
+(define_predicate "non_volatile_mem_operand"
+  (and (match_operand 0 "memory_operand")
+       (not (match_test "MEM_VOLATILE_P (op)"))))
Index: config/mips/mips.md
===================================================================
--- config/mips/mips.md	(revision 195900)
+++ config/mips/mips.md	(working copy)
@@ -342,13 +342,14 @@
 ;; syncloop	memory atomic operation implemented as a sync loop
 ;; nop		no operation
 ;; ghost	an instruction that produces no real code
+;; multimem	microMIPS multiword load and store
 (define_attr "type"
   "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
    prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
    shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
    fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
    frsqrt,frsqrt1,frsqrt2,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat,
-   multi,atomic,syncloop,nop,ghost"
+   multi,atomic,syncloop,nop,ghost,multimem"
   (cond [(eq_attr "jal" "!unset") (const_string "call")
 	 (eq_attr "got" "load") (const_string "load")
 
@@ -413,9 +414,15 @@
 
 ;; Length of instruction in bytes.
 (define_attr "length" ""
-   (cond [;; Direct branch instructions have a range of [-0x20000,0x1fffc],
-	  ;; relative to the address of the delay slot.  If a branch is
-	  ;; outside this range, we have a choice of two sequences.
+   (cond [(and (eq_attr "extended_mips16" "yes")
+	       (match_test "TARGET_MIPS16"))
+	  (const_int 8)
+
+	  ;; Direct microMIPS branch instructions have a range of
+	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
+	  ;; If a branch is outside this range, we have a choice of two
+	  ;; sequences.
+	  ;;
 	  ;; For PIC, an out-of-range branch like:
 	  ;;
 	  ;;	bne	r1,r2,target
@@ -451,10 +458,17 @@
 	  ;; from the shorten_branches reference address.
 	  (and (eq_attr "type" "branch")
 	       (not (match_test "TARGET_MIPS16")))
-	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
-		      (le (minus (pc) (match_dup 0)) (const_int 131068)))
+	  (cond [;; Any variant can handle the 17-bit range.
+		 (and (le (minus (match_dup 0) (pc)) (const_int 65532))
+		      (le (minus (pc) (match_dup 0)) (const_int 65534)))
 		   (const_int 4)
 
+		 ;; The 18-bit range is OK other than for microMIPS.
+		 (and (not (match_test "TARGET_MICROMIPS"))
+		      (and (le (minus (match_dup 0) (pc)) (const_int 131064))
+		      	   (le (minus (pc) (match_dup 0)) (const_int 131068))))
+		   (const_int 4)
+
 		 ;; The non-PIC case: branch, first delay slot, and J.
 		 (match_test "TARGET_ABSOLUTE_JUMPS")
 		   (const_int 12)]
@@ -712,6 +726,9 @@
 ;; modes.
 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
 
+(define_mode_iterator MOVEP1 [SI SF])
+(define_mode_iterator MOVEP2 [SI SF])
+
 ;; This mode iterator allows :HILO to be used as the mode of the
 ;; concatenated HI and LO registers.
 (define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
@@ -3937,7 +3954,7 @@
 (define_insn "mov_<load>l"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_LOAD_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
   "<load>l\t%0,%2"
@@ -3947,7 +3964,7 @@
 (define_insn "mov_<load>r"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_operand:GPR 3 "register_operand" "0")]
 		    UNSPEC_LOAD_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
@@ -3958,7 +3975,7 @@
 (define_insn "mov_<store>l"
   [(set (match_operand:BLK 0 "memory_operand" "=m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_STORE_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
   "<store>l\t%z1,%2"
@@ -3968,7 +3985,7 @@
 (define_insn "mov_<store>r"
   [(set (match_operand:BLK 0 "memory_operand" "+m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_dup 0)]
 		    UNSPEC_STORE_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
@@ -5447,6 +5464,14 @@
 	 (pc)))]
   "!TARGET_MIPS16"
 {
+  /* For a simple BNEZ or BEQZ microMIPS branch.  */
+  if (TARGET_MICROMIPS
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%C1z%:\t%2,%0",
+					   "%*b%N1z%:\t%2,%0");
+    
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
@@ -5463,6 +5488,14 @@
 	 (label_ref (match_operand 0 "" ""))))]
   "!TARGET_MIPS16"
 {
+  /* For a simple BNEZ or BEQZ microMIPS branch.  */
+  if (TARGET_MICROMIPS
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%N0z%:\t%2,%1",
+					   "%*b%C0z%:\t%2,%1");
+
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
@@ -5766,7 +5799,14 @@
   [(set (pc)
 	(label_ref (match_operand 0)))]
   "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
-  { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
+{
+  /* Use a branch for microMIPS.  The assembler will choose
+     a 16-bit branch, a 32-bit branch, or a 32-bit jump.  */
+  if (TARGET_MICROMIPS && !TARGET_ABICALLS_PIC2)
+    return "%*b\t%l0%/";
+  else
+    return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+}
   [(set_attr "type" "jump")])
 
 (define_insn "*jump_pic"
@@ -5829,7 +5869,12 @@
 (define_insn "indirect_jump_<mode>"
   [(set (pc) (match_operand:P 0 "register_operand" "d"))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -5873,7 +5918,12 @@
 	(match_operand:P 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -6094,7 +6144,12 @@
   [(any_return)
    (use (match_operand 0 "pmode_register_operand" ""))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type"	"jump")
    (set_attr "mode"	"none")])
 
@@ -6350,7 +6405,12 @@
   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
 	 (match_operand 1 "" ""))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 0, 1); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 0);
+  else
+    return MIPS_CALL ("j", operands, 0, 1);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6371,7 +6431,12 @@
         (call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
               (match_operand 2 "" "")))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 1);
+  else
+    return MIPS_CALL ("j", operands, 1, 2);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6383,7 +6448,12 @@
 	(call (mem:SI (match_dup 1))
 	      (match_dup 2)))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 1);
+  else
+    return MIPS_CALL ("j", operands, 1, 2);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6629,7 +6699,7 @@
 
 
 (define_insn "prefetch"
-  [(prefetch (match_operand:QI 0 "address_operand" "p")
+  [(prefetch (match_operand:QI 0 "address_operand" "ZD")
 	     (match_operand 1 "const_int_operand" "n")
 	     (match_operand 2 "const_int_operand" "n"))]
   "ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
@@ -6922,6 +6992,9 @@
 ; MIPS fixed-point instructions.
 (include "mips-fixed.md")
 
+; microMIPS patterns.
+(include "micromips.md")
+
 ; ST-Microelectronics Loongson-2E/2F-specific patterns.
 (include "loongson.md")
 
Index: config/mips/mips.opt
===================================================================
--- config/mips/mips.opt	(revision 195900)
+++ config/mips/mips.opt	(working copy)
@@ -217,9 +217,13 @@ mhard-float
 Target Report RejectNegative InverseMask(SOFT_FLOAT_ABI, HARD_FLOAT_ABI)
 Allow the use of hardware floating-point ABI and instructions
 
+minterlink-compressed
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+Generate code that is link-compatible with MIPS16 and microMIPS code.
+
 minterlink-mips16
-Target Report Var(TARGET_INTERLINK_MIPS16) Init(0)
-Generate code that can be safely linked with MIPS16 code.
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+An alias for minterlink-compressed provided for backward-compatibility.
 
 mips
 Target RejectNegative Joined ToLower Enum(mips_mips_opt_value) Var(mips_isa_option)
@@ -261,6 +265,10 @@ mmemcpy
 Target Report Mask(MEMCPY)
 Don't optimize block moves
 
+mmicromips
+Target Report Mask(MICROMIPS)
+Use microMIPS instructions
+
 mmt
 Target Report Var(TARGET_MT)
 Allow the use of MT instructions
Index: config/mips/sync.md
===================================================================
--- config/mips/sync.md	(revision 195900)
+++ config/mips/sync.md	(working copy)
@@ -59,7 +59,7 @@
 ;; Can be removed in favor of atomic_compare_and_swap below.
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
 			      (match_operand:GPR 3 "arith_operand" "I,d")]
@@ -89,7 +89,7 @@
 ;; Helper insn for mips_expand_atomic_qihi.
 (define_insn "compare_and_swap_12"
   [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-	(match_operand:SI 1 "memory_operand" "+R,R"))
+	(match_operand:SI 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
 			     (match_operand:SI 3 "register_operand" "d,d")
@@ -106,7 +106,7 @@
    (set_attr "sync_insn1_op2" "5")])
 
 (define_insn "sync_add<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 0)
 		     (match_operand:GPR 1 "arith_operand" "I,d"))]
@@ -134,7 +134,7 @@
 
 ;; Helper insn for sync_<optab><mode>
 (define_insn "sync_<optab>_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -174,7 +174,7 @@
 ;; Helper insn for sync_old_<optab><mode>
 (define_insn "sync_old_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -217,7 +217,7 @@
 (define_insn "sync_new_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
@@ -257,7 +257,7 @@
 
 ;; Helper insn for sync_nand<mode>
 (define_insn "sync_nand_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -296,7 +296,7 @@
 ;; Helper insn for sync_old_nand<mode>
 (define_insn "sync_old_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -337,7 +337,7 @@
 (define_insn "sync_new_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (match_operand:SI 4 "reg_or_0_operand" "dJ")]
@@ -360,7 +360,7 @@
    (set_attr "sync_insn1_op2" "4")])
 
 (define_insn "sync_sub<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR")
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 0)
 		      (match_operand:GPR 1 "register_operand" "d"))]
@@ -374,7 +374,7 @@
 ;; Can be removed in favor of atomic_fetch_add below.
 (define_insn "sync_old_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 1)
@@ -389,7 +389,7 @@
 
 (define_insn "sync_old_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-	(match_operand:GPR 1 "memory_operand" "+R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 1)
@@ -404,7 +404,7 @@
 
 (define_insn "sync_new_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-        (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+        (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZR,ZR")
 		  (match_operand:GPR 2 "arith_operand" "I,d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -420,7 +420,7 @@
 
 (define_insn "sync_new_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-        (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+        (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZR")
 		   (match_operand:GPR 2 "register_operand" "d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -435,7 +435,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_<optab><mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
 			      (match_dup 0))]
@@ -448,7 +448,7 @@
 
 (define_insn "sync_old_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -463,7 +463,7 @@
 
 (define_insn "sync_new_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -478,7 +478,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_nand<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
@@ -490,7 +490,7 @@
 
 (define_insn "sync_old_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
@@ -504,7 +504,7 @@
 
 (define_insn "sync_new_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_NEW_OP))]
@@ -519,7 +519,7 @@
 
 (define_insn "sync_lock_test_and_set<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
 	 UNSPEC_SYNC_EXCHANGE))]
@@ -546,7 +546,7 @@
 
 (define_insn "test_and_set_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
 			     (match_operand:SI 3 "register_operand" "d")
@@ -576,7 +576,7 @@
 	;; TODO: the obscuring unspec can be relaxed for permissive memory
 	;; models.
 	;; Same applies to other atomic_* patterns.
-	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+R,R")
+	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZR,ZR")
 			      (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
 	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
    (set (match_operand:GPR 1 "register_operand" "=&d,&d")
@@ -629,7 +629,7 @@
 
 (define_insn "atomic_exchange<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_EXCHANGE))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
@@ -684,7 +684,7 @@
 
 (define_insn "atomic_fetch_add<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_FETCH_OP))
    (set (match_dup 1)
 	(unspec_volatile:GPR
Index: config/mips/mips-cpus.def
===================================================================
--- config/mips/mips-cpus.def	(revision 195900)
+++ config/mips/mips-cpus.def	(working copy)
@@ -92,6 +92,8 @@ MIPS_CPU ("4ksc", PROCESSOR_4KC, 32, 0)
 
 /* MIPS32 Release 2 processors.  */
 MIPS_CPU ("m4k", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14kc", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14k", PROCESSOR_M4K, 33, 0)
 MIPS_CPU ("4kec", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kem", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kep", PROCESSOR_4KP, 33, 0)
Index: config/mips/mips-protos.h
===================================================================
--- config/mips/mips-protos.h	(revision 195900)
+++ config/mips/mips-protos.h	(working copy)
@@ -350,6 +350,12 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern const char *umips_output_save_restore (bool, rtx);
+extern bool umips_save_restore_pattern_p (bool, rtx);
+extern bool umips_load_store_pair_p (bool, rtx *);
+extern void umips_output_load_store_pair (bool, rtx *);
+extern bool umips_movep_target_p (rtx, rtx);
+extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: config/mips/mips.c
===================================================================
--- config/mips/mips.c	(revision 195900)
+++ config/mips/mips.c	(working copy)
@@ -77,6 +77,9 @@ along with GCC; see the file COPYING3.  If not see
    preserve the maximum stack alignment.  We therefore use a value
    of 0x7ff0 in this case.
 
+   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
+   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
+
    MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
    up to 0x7f8 bytes and can usually save or restore all the registers
    that we need to save or restore.  (Note that we can only use these
@@ -87,8 +90,8 @@ along with GCC; see the file COPYING3.  If not see
    to save and restore registers, and to allocate and deallocate the top
    part of the frame.  */
 #define MIPS_MAX_FIRST_STACK_STEP					\
-  (!TARGET_MIPS16 ? 0x7ff0						\
-   : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8				\
+  (!TARGET_COMPRESSION ? 0x7ff0						\
+   : TARGET_MICROMIPS || GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8		\
    : TARGET_64BIT ? 0x100 : 0x400)
 
 /* True if INSN is a mips.md pattern or asm statement.  */
@@ -560,8 +563,8 @@ static const struct mips_rtx_cost_data *mips_cost;
 /* The ambient target flags, excluding MASK_MIPS16.  */
 static int mips_base_target_flags;
 
-/* True if MIPS16 is the default mode.  */
-bool mips_base_mips16;
+/* The default compression mode.  */
+unsigned int mips_base_compression_flags;
 
 /* The ambient values of other global variables.  */
 static int mips_base_schedule_insns; /* flag_schedule_insns */
@@ -674,6 +677,9 @@ static const struct attribute_spec mips_attribute_
      code generation but don't carry other semantics.  */
   { "mips16", 	   0, 0, true,  false, false, NULL, false },
   { "nomips16",    0, 0, true,  false, false, NULL, false },
+  { "micromips",   0, 0, true,  false, false, NULL, false },
+  { "nomicromips", 0, 0, true,  false, false, NULL, false },
+  { "nocompression", 0, 0, true,  false, false, NULL, false },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 0, false, true,  true, NULL, false },
   { "use_shadow_register_set",	0, 0, false, true,  true, NULL, false },
@@ -1167,10 +1173,11 @@ mflip_mips16_use_mips16_p (tree decl)
   const char *name;
   hashval_t hash;
   void **slot;
+  bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) != 0;
 
   /* Use the opposite of the command-line setting for anonymous decls.  */
   if (!DECL_NAME (decl))
-    return !mips_base_mips16;
+    return !base_is_mips16;
 
   if (!mflip_mips16_htab)
     mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
@@ -1185,7 +1192,7 @@ mflip_mips16_use_mips16_p (tree decl)
       mips16_flipper = !mips16_flipper;
       entry = ggc_alloc_mflip_mips16_entry ();
       entry->name = name;
-      entry->mips16_p = mips16_flipper ? !mips_base_mips16 : mips_base_mips16;
+      entry->mips16_p = mips16_flipper ? !base_is_mips16 : base_is_mips16;
       *slot = entry;
     }
   return entry->mips16_p;
@@ -1207,20 +1214,7 @@ mips_far_type_p (const_tree type)
 	  || lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
 }
 
-/* Similar predicates for "mips16"/"nomips16" function attributes.  */
 
-static bool
-mips_mips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
-static bool
-mips_nomips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
 /* Check if the interrupt attribute is set for a function.  */
 
 static bool
@@ -1257,12 +1251,51 @@ mips_use_debug_exception_return_p (tree type)
 			   TYPE_ATTRIBUTES (type)) != NULL;
 }
 
-/* Return true if function DECL is a MIPS16 function.  Return the ambient
-   setting if DECL is null.  */
+/* Return the set of compression modes that are explicitly required
+   by DECL.  */
 
-static bool
-mips_use_mips16_mode_p (tree decl)
+static unsigned int
+mips_get_compress_on_flags (tree attributes)
 {
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("mips16", attributes) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("micromips", attributes) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the set of compression modes that are explicitly forbidden
+   by DECL.  */
+
+static unsigned int
+mips_get_compress_off_flags (tree attributes)
+{
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("nocompression", attributes) != NULL)
+    flags |= MASK_MIPS16 | MASK_MICROMIPS;
+
+  if (lookup_attribute ("nomips16", attributes) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("nomicromips", attributes) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the compression mode that should be used for function DECL.
+   Return the ambient setting if DECL is null.  */
+static unsigned int
+mips_get_compress_mode (tree decl)
+{
+  unsigned int flags, force_on;
+
+  flags = mips_base_compression_flags;
   if (decl)
     {
       /* Nested functions must use the same frame pointer as their
@@ -1270,14 +1303,38 @@ mips_use_debug_exception_return_p (tree type)
       tree parent = decl_function_context (decl);
       if (parent)
 	decl = parent;
-      if (mips_mips16_decl_p (decl))
-	return true;
-      if (mips_nomips16_decl_p (decl))
-	return false;
+      force_on = mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+      if (force_on)
+	return force_on;
+      flags &= ~mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
     }
-  return mips_base_mips16;
+  return flags;
 }
 
+/* Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_on_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "mips16";
+  return "micromips";
+}
+
+/* Return the attribute name that forbids MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_off_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "nomips16";
+  if (flags == MASK_MICROMIPS)
+    return "nomicromips";
+  return "nocompression";
+}
+
 /* Implement TARGET_COMP_TYPE_ATTRIBUTES.  */
 
 static int
@@ -1297,37 +1354,50 @@ static void
 mips_insert_attributes (tree decl, tree *attributes)
 {
   const char *name;
-  bool mips16_p, nomips16_p;
+  unsigned int compression_flags, nocompression_flags;
 
   /* Check for "mips16" and "nomips16" attributes.  */
-  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
-  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+  compression_flags = mips_get_compress_on_flags (*attributes);
+  nocompression_flags = mips_get_compress_off_flags (*attributes);
+
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
-      if (mips16_p)
-	error ("%qs attribute only applies to functions", "mips16");
-      if (nomips16_p)
-	error ("%qs attribute only applies to functions", "nomips16");
+      if (nocompression_flags)
+	error ("%qs attribute only applies to functions",
+	       mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags)
+	error ("%qs attribute only applies to functions",
+	       mips_get_compress_on_name (nocompression_flags));
     }
   else
     {
-      mips16_p |= mips_mips16_decl_p (decl);
-      nomips16_p |= mips_nomips16_decl_p (decl);
-      if (mips16_p || nomips16_p)
+      compression_flags |= mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+      nocompression_flags |=
+	mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
+
+      if (compression_flags && nocompression_flags)
+	error ("%qE cannot have both %qs and %qs attributes",
+	       DECL_NAME (decl), mips_get_compress_on_name (compression_flags),
+	       mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags & MASK_MIPS16
+          && compression_flags & MASK_MICROMIPS)
+	error ("%qE cannot have both %qs and %qs attributes",
+	       DECL_NAME (decl), "mips16", "micromips");
+
+      if (TARGET_FLIP_MIPS16
+	  && !DECL_ARTIFICIAL (decl)
+	  && compression_flags == 0
+	  && nocompression_flags == 0)
 	{
-	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
-	  if (mips16_p && nomips16_p)
-	    error ("%qE cannot have both %<mips16%> and "
-		   "%<nomips16%> attributes",
-		   DECL_NAME (decl));
-	}
-      else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
-	{
 	  /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
 	     "mips16" attribute, arbitrarily pick one.  We must pick the same
 	     setting for duplicate declarations of a function.  */
 	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	  name = "nomicromips";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
 	}
     }
 }
@@ -1337,14 +1407,24 @@ mips_insert_attributes (tree decl, tree *attribute
 static tree
 mips_merge_decl_attributes (tree olddecl, tree newdecl)
 {
-  /* The decls' "mips16" and "nomips16" attributes must match exactly.  */
-  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
+  unsigned int diff;
+
+  diff = (mips_get_compress_on_flags (DECL_ATTRIBUTES (olddecl))
+	  ^ mips_get_compress_on_flags (DECL_ATTRIBUTES (newdecl)));
+
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "mips16");
-  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
+	   DECL_NAME (newdecl), mips_get_compress_on_name (diff));
+
+
+  diff = (mips_get_compress_off_flags (DECL_ATTRIBUTES (olddecl))
+	  ^ mips_get_compress_off_flags (DECL_ATTRIBUTES (newdecl)));
+
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "nomips16");
+	   DECL_NAME (newdecl), mips_get_compress_off_name (diff));
 
+
   return merge_attributes (DECL_ATTRIBUTES (olddecl),
 			   DECL_ATTRIBUTES (newdecl));
 }
@@ -1550,7 +1630,7 @@ mips16_local_function_p (const_rtx x)
   return (GET_CODE (x) == SYMBOL_REF
 	  && SYMBOL_REF_LOCAL_P (x)
 	  && !SYMBOL_REF_EXTERNAL_P (x)
-	  && mips_use_mips16_mode_p (SYMBOL_REF_DECL (x)));
+	  && (mips_get_compress_mode (SYMBOL_REF_DECL (x)) & MASK_MIPS16));
 }
 
 /* Return true if SYMBOL_REF X binds locally.  */
@@ -2300,6 +2380,20 @@ mips_address_insns (rtx x, enum machine_mode mode,
   return 0;
 }
 
+/* Return true if X is a legitimate address with a 12-bit offset.
+   MODE is the mode of the value being accessed.  */
+
+bool
+umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && CONST_INT_P (addr.offset)
+	  && UMIPS_12BIT_OFFSET_P (INTVAL (addr.offset)));
+}
+
 /* Return the number of instructions needed to load constant X.
    Return 0 if X isn't a valid constant.  */
 
@@ -6097,6 +6191,13 @@ mips_start_function_definition (const char *name,
   else
     fprintf (asm_out_file, "\t.set\tnomips16\n");
 
+  if (TARGET_MICROMIPS)
+    fprintf (asm_out_file, "\t.set\tmicromips\n");
+#ifdef HAVE_GAS_MICROMIPS
+  else 
+    fprintf (asm_out_file, "\t.set\tnomicromips\n");
+#endif
+
   if (!flag_inhibit_size_directive)
     {
       fputs ("\t.ent\t", asm_out_file);
@@ -6903,11 +7004,44 @@ mips_split_call (rtx insn, rtx call_pattern)
     mips_restore_gp_from_cprestore_slot (gen_rtx_REG (Pmode, GP_ARG_FIRST + 2));
 }
 
+/* Return true if a call to DECL may need to use JALX.  */
+
+static bool
+mips_call_may_need_jalx_p (tree decl)
+{
+  /* If the current translation unit would use a different mode for DECL,
+     assume that the call needs JALX.  */
+  if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
+    return true;
+
+  /* mips_get_compress_mode is always accurate for locally-binding
+     functions in the current translation unit.  */
+  if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
+    return false;
+
+  /* When -minterlink-compressed is in effect, assume that functions
+     could use a different encoding mode unless an attribute explicitly
+     tells us otherwise.  */
+  if (TARGET_INTERLINK_COMPRESSED)
+    {
+      if (!TARGET_COMPRESSION
+	  && mips_get_compress_off_flags (DECL_ATTRIBUTES (decl)) ==0)
+	return true;
+      if (TARGET_COMPRESSION
+	  && mips_get_compress_on_flags (DECL_ATTRIBUTES (decl)) == 0)
+	return true;
+    }
+
+  return false;
+}
+
 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
 
 static bool
 mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
+
+  unsigned int compression_mode = mips_get_compress_mode (decl);
   if (!TARGET_SIBCALLS)
     return false;
 
@@ -6916,25 +7050,13 @@ mips_function_ok_for_sibcall (tree decl, tree exp
   if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
     return false;
 
-  /* We can't do a sibcall if the called function is a MIPS16 function
-     because there is no direct "jx" instruction equivalent to "jalx" to
-     switch the ISA mode.  We only care about cases where the sibling
-     and normal calls would both be direct.  */
+  /* Direct Js are only possible to functions that use the same ISA
+  encoding.  There is no JX counterpoart of JALX.  */
   if (decl
-      && mips_use_mips16_mode_p (decl)
-      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
+      && mips_call_may_need_jalx_p (decl))
     return false;
 
-  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
-     functions could be MIPS16 ones unless an attribute explicitly tells
-     us otherwise.  */
-  if (TARGET_INTERLINK_MIPS16
-      && decl
-      && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
-      && !mips_nomips16_decl_p (decl)
-      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
-    return false;
-
   /* Otherwise OK.  */
   return true;
 }
@@ -7798,6 +7920,9 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_s
    '^'	Print the name of the pic call-through register (t9 or $25).
    '+'	Print the name of the gp register (usually gp or $28).
    '$'	Print the name of the stack pointer register (sp or $29).
+   ':'  Print "c" to use the compact version if the delay slot is a nop.
+   '!'  Print "s" to use the short version if the delay slot contains a
+	16-bit instruction.
 
    See also mips_init_print_operand_pucnt.  */
 
@@ -7881,6 +8006,20 @@ mips_print_operand_punctuation (FILE *file, int ch
       fputs (reg_names[STACK_POINTER_REGNUM], file);
       break;
 
+    case ':':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+	 use the compact version for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('c', file);
+      break;
+
+    case '!':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+	 a 16-bit delay slot for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('s', file);
+      break;
+
     default:
       gcc_unreachable ();
       break;
@@ -7894,7 +8033,7 @@ mips_init_print_operand_punct (void)
 {
   const char *p;
 
-  for (p = "()[]<>*#/?~.@^+$"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$:!"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -10236,6 +10375,127 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset,
       }
 }
 
+/* Save register REG to MEM.  Make the instruction frame-related.  */
+
+static void
+mips_save_reg (rtx reg, rtx mem)
+{
+  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
+    {
+      rtx x1, x2;
+
+      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
+
+      x1 = mips_frame_set (mips_subword (mem, false),
+			   mips_subword (reg, false));
+      x2 = mips_frame_set (mips_subword (mem, true),
+			   mips_subword (reg, true));
+      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
+    }
+  else
+    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
+}
+
+/* Capture the register combinations that are allowed in a SWM or LWM
+   instruction.  The entries are ordered by number of registers set in
+   the mask.  We also ignore the single register encodings because a
+   normal SW/LW is preferred.  */
+   
+static const unsigned int umips_swm_mask[17] = {
+  0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
+  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,	
+  0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
+  0x000f0000, 0x80030000, 0x00070000, 0x80010000,
+  0x00030000
+};
+
+static const unsigned int umips_swm_encoding[17] = {
+  25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2
+};
+
+/* Try to use a microMIPS LWM or SWM instruction to save or restore
+   as many GPRs in *MASK as possible.  *OFFSET is the offset from the
+   stack pointer of the topmost save slot.
+
+   Remove from *MASK all registers that were handled using LWM and SWM.
+   Update *OFFSET so that it points to the first unused save slot.  */
+
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+			  unsigned *mask, HOST_WIDE_INT *offset)
+{
+  int i, nregs;
+  unsigned int j;
+  rtx pattern, set, reg, mem;
+  HOST_WIDE_INT this_offset;
+  rtx this_base;
+
+  /* Try matching $16 to $31 (s0 to ra).  */
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if ((*mask & 0xffff0000) == umips_swm_mask[i])
+      break;
+
+  if (i == ARRAY_SIZE (umips_swm_mask))
+    return false;
+
+  /* Adjust offset for output.  */
+  nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
+  this_offset = *offset - UNITS_PER_WORD * (nregs - 1);
+
+  /* LWM/SWM can only support offsets from -2048 to 2047.  */
+  if (!UMIPS_12BIT_OFFSET_P (this_offset))
+    return false;
+
+  /* Create the final PARALLEL.  */
+  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs));
+  this_base = stack_pointer_rtx;
+
+  /* For registers $16-$23 and $30.  */
+  for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
+    {
+      unsigned int regno;
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      regno = (j != 8) ? 16 + j : 30;
+      *mask &= ~(1 << regno);
+      reg = gen_rtx_REG (SImode, regno);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  /* For register $31.  */
+  if (umips_swm_encoding[i] >> 4)
+    {
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      *mask &= ~(1 << 31);
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      reg = gen_rtx_REG (SImode, 31);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  pattern = emit_insn (pattern);
+  if (fn == mips_save_reg)
+    RTX_FRAME_RELATED_P (pattern) = 1;  
+
+  /* Adjust the last offset.  */
+  *offset -= UNITS_PER_WORD * nregs;
+
+  return true;
+}
+
 /* Call FN for each register that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -10245,16 +10505,23 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_
 				 mips_save_restore_fn fn)
 {
   enum machine_mode fpr_mode;
+  int regno;
+  const struct mips_frame_info *frame = &cfun->machine->frame;
   HOST_WIDE_INT offset;
-  int regno;
+  unsigned int mask;
 
   /* Save registers starting from high to low.  The debuggers prefer at least
      the return register be stored at func+4, and also it allows us not to
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
   offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+  mask = frame->mask;
+
+  if (TARGET_MICROMIPS)
+    umips_build_save_restore (fn, &mask, &offset);
+
   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
-    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+    if (BITSET_P (mask, regno - GP_REG_FIRST))
       {
 	/* Record the ra offset for use by mips_function_profiler.  */
 	if (regno == RETURN_ADDR_REGNUM)
@@ -10501,27 +10768,7 @@ mips_frame_barrier (void)
   emit_clobber (gen_frame_mem (BLKmode, stack_pointer_rtx));
 }
 
-/* Save register REG to MEM.  Make the instruction frame-related.  */
 
-static void
-mips_save_reg (rtx reg, rtx mem)
-{
-  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
-    {
-      rtx x1, x2;
-
-      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
-
-      x1 = mips_frame_set (mips_subword (mem, false),
-			   mips_subword (reg, false));
-      x2 = mips_frame_set (mips_subword (mem, true),
-			   mips_subword (reg, true));
-      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
-    }
-  else
-    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
-}
-
 /* The __gnu_local_gp symbol.  */
 
 static GTY(()) rtx mips_gnu_local_gp;
@@ -11239,7 +11486,7 @@ mips_expand_epilogue (bool sibcall_p)
 	  mips_emit_move (gen_rtx_REG (word_mode, K0_REG_NUM), mem);
 	  offset -= UNITS_PER_WORD;
 
-	  /* If we don't use shoadow register set, we need to update SP.  */
+	  /* If we don't use shadow register set, we need to update SP.  */
 	  if (!cfun->machine->use_shadow_register_set_p)
 	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
 	  else
@@ -11254,6 +11501,7 @@ mips_expand_epilogue (bool sibcall_p)
 	/* Deallocate the final bit of the frame.  */
 	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
     }
+
   gcc_assert (!mips_epilogue.cfa_restores);
 
   /* Add in the __builtin_eh_return stack adjustment.  We need to
@@ -16211,17 +16459,19 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndec
   reload_completed = 0;
 }
 \f
-/* The last argument passed to mips_set_mips16_mode, or negative if the
-   function hasn't been called yet.  */
-static int was_mips16_p = -1;
 
-/* Set up the target-dependent global state so that it matches the
-   current function's ISA mode.  */
+/* The last argument passed to mips_set_compression_mode,
+   or negative if the function hasn't been called yet.  */
+static unsigned int old_compression_mode = -1;
 
+/* Set up the target-dependent global state for ISA mode COMPRESSION_MODE,
+   which is either MASK_MIPS16 or MASK_MICROMIPS.  */
+
 static void
-mips_set_mips16_mode (int mips16_p)
+mips_set_compression_mode (unsigned int compression_mode)
 {
-  if (mips16_p == was_mips16_p)
+
+  if (compression_mode == old_compression_mode)
     return;
 
   /* Restore base settings of various flags.  */
@@ -16232,8 +16482,10 @@ static void
   align_loops = mips_base_align_loops;
   align_jumps = mips_base_align_jumps;
   align_functions = mips_base_align_functions;
+  target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
+  target_flags |= compression_mode;
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       /* Switch to MIPS16 mode.  */
       target_flags |= MASK_MIPS16;
@@ -16287,9 +16539,12 @@ static void
     }
   else
     {
-      /* Switch to normal (non-MIPS16) mode.  */
-      target_flags &= ~MASK_MIPS16;
+      /* Switch to microMIPS or the standard encoding.  */
 
+      if (TARGET_MICROMIPS)
+	/* Avoid branch likely.  */
+	target_flags &= ~MASK_BRANCHLIKELY;
+
       /* Provide default values for align_* for 64-bit targets.  */
       if (TARGET_64BIT)
 	{
@@ -16310,7 +16565,7 @@ static void
   /* (Re)initialize MIPS target internals for new ISA.  */
   mips_init_relocs ();
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       if (!mips16_globals)
 	mips16_globals = save_target_globals ();
@@ -16320,16 +16575,17 @@ static void
   else
     restore_target_globals (&default_target_globals);
 
-  was_mips16_p = mips16_p;
+  old_compression_mode = compression_mode;
 }
 
 /* Implement TARGET_SET_CURRENT_FUNCTION.  Decide whether the current
-   function should use the MIPS16 ISA and switch modes accordingly.  */
+   function should use the MIPS16 or microMIPS ISA and switch modes
+   accordingly.  */
 
 static void
 mips_set_current_function (tree fndecl)
 {
-  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+  mips_set_compression_mode (mips_get_compress_mode (fndecl));
 }
 \f
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -16437,14 +16693,19 @@ mips_option_override (void)
   if (global_options_set.x_mips_isa_option)
     mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
 
-  /* Process flags as though we were generating non-MIPS16 code.  */
-  mips_base_mips16 = TARGET_MIPS16;
-  target_flags &= ~MASK_MIPS16;
-
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
+  /* MIPS16 and microMIPS cannot coexist.  */
+  if (TARGET_MICROMIPS && TARGET_MIPS16)
+    error ("unsupported combination: %s", "-mips16 -mmicromips");
+
+  /* Save the base compression state and process flags as though we
+     were generating uncompressed code.  */
+  mips_base_compression_flags = TARGET_COMPRESSION;
+  target_flags &= ~TARGET_COMPRESSION;
+
   /* -mno-float overrides -mhard-float and -msoft-float.  */
   if (TARGET_NO_FLOAT)
     {
@@ -16453,7 +16714,7 @@ mips_option_override (void)
     }
 
   if (TARGET_FLIP_MIPS16)
-    TARGET_INTERLINK_MIPS16 = 1;
+    TARGET_INTERLINK_COMPRESSED = 1;
 
   /* Set the small data limit.  */
   mips_small_data_threshold = (global_options_set.x_g_switch_value
@@ -16826,9 +17087,9 @@ mips_option_override (void)
 
   /* Now select the ISA mode.
 
-     Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
-     MIPS16 mode afterwards if need be.  */
-  mips_set_mips16_mode (false);
+     Do all CPP-sensitive stuff in uncompressed mode;
+     We'll switch modes later if required.  */
+  mips_set_compression_mode (0);
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -17088,6 +17349,272 @@ mips_mulsidi3_gen_fn (enum rtx_code ext_code)
       return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
     }
 }
+
+/* Return true if PATTERN matches the kind of instruction generated by
+   umips_build_save_restore.  SAVE_P is true for store.  */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+  int n;
+  unsigned int i;
+  HOST_WIDE_INT first_offset = 0;
+  rtx first_base = 0;
+  unsigned int regmask = 0;
+
+  for (n = 0; n < XVECLEN (pattern, 0); n++)
+    {
+      rtx set, reg, mem, this_base;
+      HOST_WIDE_INT this_offset;
+      unsigned int this_regno;
+
+      /* Check that we have a SET.  */
+      set = XVECEXP (pattern, 0, n);
+      if (GET_CODE (set) != SET)
+	return false;
+
+      /* Check that the SET is a load (if restoring) or a store
+	 (if saving).  */
+      mem = save_p ? SET_DEST (set) : SET_SRC (set);
+      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
+	return false;
+
+      /* Check that the address is the sum of base and a possibly-zero
+	 constant offset.  Determine if the offset is in range.  */
+      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+      if (!REG_P (this_base))
+	return false;
+
+      if (n == 0)
+	{
+	  if (!UMIPS_12BIT_OFFSET_P (this_offset))
+	    return false;
+	  first_base = this_base;
+	  first_offset = this_offset;
+	}
+      else
+	{
+	  /* Check that the save slots are consecutive.  */
+	  if (REGNO (this_base) != REGNO (first_base)
+	      || this_offset != first_offset + UNITS_PER_WORD * n)
+	    return false;
+	}
+
+      /* Check that SET's other operand is a register.  */
+      reg = save_p ? SET_SRC (set) : SET_DEST (set);
+      if (!REG_P (reg))
+	return false;
+
+      regmask |= 1 << REGNO (reg);
+    }
+
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if (regmask == umips_swm_mask[i])
+      return true;
+
+  return false;
+}
+/* Return the assembly instruction for microMIPS lwm or swm.
+   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+  static char buffer[300];
+  char *s;
+  int n;
+  HOST_WIDE_INT offset;
+  rtx base, mem, set, reg, last_set, last_reg;
+
+  /* Parse the pattern.  */
+  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
+
+  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
+  s += strlen (s);
+  n = XVECLEN (pattern, 0);
+
+  set = XVECEXP (pattern, 0, 0);
+  reg = save_p ? SET_SRC (set) : SET_DEST (set);
+  mem = save_p ? SET_DEST (set) : SET_SRC (set);
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+
+  last_set = XVECEXP (pattern, 0, n - 1);
+  last_reg = save_p ? SET_SRC (last_set) : SET_DEST (last_set);
+
+  if (REGNO (last_reg) == 31)
+    n--;
+
+  gcc_assert (n <= 9);
+  if (n == 0)
+    ;
+  else if (n == 1)
+    s += sprintf (s, "%s,", reg_names[16]);
+  else if (n < 9)
+    s += sprintf (s, "%s-%s,", reg_names[16], reg_names[15 + n]);
+  else if (n == 9)
+    s += sprintf (s, "%s-%s,%s,", reg_names[16], reg_names[23],
+		  reg_names[30]);
+
+  if (REGNO (last_reg) == 31)
+    s += sprintf (s, "%s,", reg_names[31]);
+
+  s += sprintf (s, "%d(%s)", (int)offset, reg_names[REGNO (base)]);
+  return buffer;
+}
+
+/* Return true if MEM1 and MEM2 use the same base register, and the
+   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
+   register into (from) which the contents of MEM1 will be loaded
+   (stored), depending on the value of LOAD_P.
+   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
+
+static bool
+umips_load_store_pair_p_1 (bool load_p, bool swap_p,
+			   rtx first_reg, rtx mem1, rtx mem2)
+{
+  rtx base1, base2;
+  HOST_WIDE_INT offset1, offset2;
+
+  if (!MEM_P (mem1) || !MEM_P (mem2))
+    return false;
+
+  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
+  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
+
+  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
+    return false;
+
+  /* Avoid invalid load pair instructions.  */
+  if (load_p && REGNO (first_reg) == REGNO (base1))
+    return false;
+
+  /* We must avoid this case for anti-dependence.
+     Ex:  lw $3, 4($3)
+          lw $2, 0($3)
+     first_reg is $2, but the base is $3.  */
+  if (load_p
+      && swap_p
+      && REGNO (first_reg) + 1 == REGNO (base1))
+    return false;
+
+  if (offset2 != offset1 + 4)
+    return false;
+
+  if (!UMIPS_12BIT_OFFSET_P (offset1))
+    return false;
+
+  return true;
+}
+
+/* Return true if operands can be used in an LWP or SWP instruction.  */
+
+bool
+umips_load_store_pair_p (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    return umips_load_store_pair_p_1 (load_p, false, reg1, mem1, mem2);
+
+  if (REGNO (reg1) == REGNO (reg2) + 1)
+    return umips_load_store_pair_p_1 (load_p, true, reg2, mem2, mem1);
+
+  return false;
+}
+
+/* Return the assembly instruction for microMIPS lwp or swp.
+   LOAD_P is true for load.  */
+
+static void
+umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
+{
+  rtx ops[] = {reg, mem};
+
+  if (load_p)
+    output_asm_insn ("lwp\t%0,%1", ops);
+  else
+    output_asm_insn ("swp\t%0,%1", ops);
+}
+
+void
+umips_output_load_store_pair (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+   
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    {
+      umips_output_load_store_pair_1 (load_p, reg1, mem1);
+      return;
+    }
+
+  gcc_assert (REGNO (reg1) == REGNO (reg2) + 1);
+  umips_output_load_store_pair_1 (load_p, reg2, mem2);
+}
+
+/* Return true if REG1 and REG2 match the criteria for a movep insn.  */
+
+bool
+umips_movep_target_p (rtx reg1, rtx reg2)
+{
+  int regno1, regno2, pair;
+  unsigned int i;
+  static const int match[8] = {
+    0x00000060,	/* 5, 6 */
+    0x000000a0,	/* 5, 7 */
+    0x000000c0,	/* 6, 7 */
+    0x00200010,	/* 4, 21 */
+    0x00400010,	/* 4, 22 */
+    0x00000030,	/* 4, 5 */
+    0x00000050, /* 4, 6 */
+    0x00000090  /* 4, 7 */
+  };
+
+  if (!REG_P (reg1) || !REG_P (reg2))
+    return false;
+
+  regno1 = REGNO (reg1);
+  regno2 = REGNO (reg2);
+
+  if (!GP_REG_P (regno1)  || !GP_REG_P (regno2))
+    return false;
+
+  pair = (1 << regno1) | (1 << regno2);
+
+  for (i = 0; i < ARRAY_SIZE (match); i++)
+    if (pair == match[i])
+      return true;
+
+  return false;
+}
 \f
 /* Return the size in bytes of the trampoline code, padded to
    TRAMPOLINE_ALIGNMENT bits.  The static chain pointer and target
@@ -17342,7 +17869,7 @@ mips_prepare_pch_save (void)
      It therefore seems best to switch back to non-MIPS16 mode at
      save time, and to ensure that mips16_globals remains null after
      a PCH load.  */
-  mips_set_mips16_mode (false);
+  mips_set_compression_mode (0);
   mips16_globals = 0;
 }
 \f
Index: config/mips/mips.h
===================================================================
--- config/mips/mips.h	(revision 195900)
+++ config/mips/mips.h	(working copy)
@@ -174,6 +174,9 @@ struct mips_cpu_info {
 #define ISA_HAS_DSP_MULT ISA_HAS_DSPR2
 #endif
 
+/* The ISA compression flags that are currently in effect.  */
+#define TARGET_COMPRESSION (target_flags & (MASK_MIPS16 | MASK_MICROMIPS))
+
 /* Generate mips16 code */
 #define TARGET_MIPS16		((target_flags & MASK_MIPS16) != 0)
 /* Generate mips16e code. Default 16bit ASE for mips32* and mips64* */
@@ -374,7 +377,7 @@ struct mips_cpu_info {
       else								\
 	builtin_define ("__mips_fpr=32");				\
 									\
-      if (mips_base_mips16)						\
+      if (mips_base_compression_flags & MASK_MIPS16)			\
 	builtin_define ("__mips16");					\
 									\
       if (TARGET_MIPS3D)						\
@@ -383,6 +386,9 @@ struct mips_cpu_info {
       if (TARGET_SMARTMIPS)						\
 	builtin_define ("__mips_smartmips");				\
 									\
+      if (mips_base_compression_flags & MASK_MICROMIPS)			\
+	builtin_define ("__mips_micromips");				\
+									\
       if (TARGET_MCU)							\
 	builtin_define ("__mips_mcu");					\
 									\
@@ -702,7 +708,7 @@ struct mips_cpu_info {
        |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
      %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
      %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
-       |march=34k*|march=74k*|march=1004k*: -mips32r2} \
+       |march=34k*|march=74k*|march=m14k*|march=1004k*: -mips32r2} \
      %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
        |march=xlr|march=loongson3a: -mips64} \
      %{march=mips64r2|march=octeon|march=xlp: -mips64r2} \
@@ -716,7 +722,7 @@ struct mips_cpu_info {
   "%{mhard-float|msoft-float|mno-float|march=mips*:; \
      march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
      |march=34kc|march=34kn|march=74kc|march=1004kc|march=5kc \
-     |march=octeon|march=xlr: -msoft-float;		  \
+     |march=m14k*|march=octeon|march=xlr: -msoft-float;		  \
      march=*: -mhard-float}"
 
 /* A spec condition that matches 32-bit options.  It only works if
@@ -989,7 +995,8 @@ struct mips_cpu_info {
 				     || ISA_MIPS64R2))
 
 /* ISA has lwxs instruction (load w/scaled index address.  */
-#define ISA_HAS_LWXS		(TARGET_SMARTMIPS && !TARGET_MIPS16)
+#define ISA_HAS_LWXS		((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
+				 && !TARGET_MIPS16)
 
 /* ISA has lbx, lbux, lhx, lhx, lhux, lwx, lwux, or ldx instruction. */
 #define ISA_HAS_LBX		(TARGET_OCTEON2)
@@ -1123,6 +1130,7 @@ struct mips_cpu_info {
 %{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
 %{mips32*} %{mips64*} \
 %{mips16} %{mno-mips16:-no-mips16} \
+%{mmicromips} %{mno-micromips} \
 %{mips3d} %{mno-mips3d:-no-mips3d} \
 %{mdmx} %{mno-mdmx:-no-mdmx} \
 %{mdsp} %{mno-dsp} \
@@ -1672,6 +1680,8 @@ struct mips_cpu_info {
   ((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define M16_REG_P(REGNO) \
   (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 16 || (REGNO) == 17)
+#define M16STORE_REG_P(REGNO) \
+  (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 0 || (REGNO) == 17)
 #define FP_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
 #define MD_REG_P(REGNO) \
@@ -2034,6 +2044,7 @@ enum reg_class
 #define SMALL_INT(X) SMALL_OPERAND (INTVAL (X))
 #define SMALL_INT_UNSIGNED(X) SMALL_OPERAND_UNSIGNED (INTVAL (X))
 #define LUI_INT(X) LUI_OPERAND (INTVAL (X))
+#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))
 
 /* The HI and LO registers can only be reloaded via the general
    registers.  Condition code registers can only be loaded to the
@@ -2452,17 +2463,32 @@ typedef struct mips_args {
    all calls should use assembly macros.  Otherwise, all indirect
    calls should use "jr" or "jalr"; we will arrange to restore $gp
    afterwards if necessary.  Finally, we can only generate direct
-   calls for -mabicalls by temporarily switching to non-PIC mode.  */
+   calls for -mabicalls by temporarily switching to non-PIC mode.
+
+   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+   instruction is in the delay slot of jal(r).  */
 #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
   (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
    ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
-   : (REG_P (OPERANDS[TARGET_OPNO])				\
-      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
-   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
-      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
    : REG_P (OPERANDS[TARGET_OPNO])				\
-   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"				\
+   ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)		\
+      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
+	 "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
+      : TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED	\
+      ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"			\
+      : "%*" INSN "r\t%" #TARGET_OPNO "%/")			\
    : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
+
+/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
+   "jrc" when nop is in the delay slot of "jr".  */
+
+#define MICROMIPS_J(INSN, OPERANDS, OPNO)			\
+  (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
+   ? "%*j\t%" #OPNO "%/"					\
+   : REG_P (OPERANDS[OPNO])					\
+   ? "%*jr%:\t%" #OPNO						\
+   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #OPNO "%/"))
+
 \f
 /* Control the assembler format that we output.  */
 
@@ -2877,7 +2903,7 @@ extern enum processor mips_tune;        /* which c
 extern int mips_isa;			/* architectural level */
 extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
-extern bool mips_base_mips16;
+extern unsigned int mips_base_compression_flags;
 extern GTY(()) struct target_globals *mips16_globals;
 #endif
 
Index: config/mips/t-sde
===================================================================
--- config/mips/t-sde	(revision 195900)
+++ config/mips/t-sde	(working copy)
@@ -16,8 +16,8 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16 msoft-float/mfp64 mcode-readable=no
-MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 sof f64 spram
+MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16/mmicromips msoft-float/mfp64 mcode-readable=no
+MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 micromips sof f64 spram
 MULTILIB_MATCHES = EL=mel EB=meb
 
 # The -mfp64 option is only valid in conjunction with -mips32r2.
@@ -33,3 +33,6 @@ MULTILIB_EXCLUSIONS += !mips32/!mips32r2/mips16
 else
 MULTILIB_EXCLUSIONS += mips64/mips16 mips64r2/mips16
 endif
+
+# The -mcode-readable=no is only in conjunction with -mips16.
+MULTILIB_EXCLUSIONS += mcode-readable=no/!mips16

[-- Attachment #4: libgcc.cl --]
[-- Type: application/octet-stream, Size: 296 bytes --]

2013-02-18  Catherine Moore  <clm@codesourcery.com>
	    Joseph Myers  <joseph@codesourcery.com>
	    Chao-ying Fu  <fu@mips.com>

	* config/mips/mips16.S:  Don't build for microMIPS.
	* config/mips/linux-unwind.h: Handle microMIPS frame.
	* config/mips/crtn.S (fini, init): New labels.


[-- Attachment #5: libgcc.patch --]
[-- Type: application/octet-stream, Size: 2195 bytes --]

Index: ChangeLog
===================================================================
--- ChangeLog	(revision 195931)
+++ ChangeLog	(working copy)
@@ -1,3 +1,11 @@
+2013-02-18  Catherine Moore  <clm@codesourcery.com>
+	    Joseph Myers  <joseph@codesourcery.com>
+	    Chao-ying Fu  <fu@mips.com>
+
+	* config/mips/mips16.S:  Don't build for microMIPS.
+	* config/mips/linux-unwind.h: Handle microMIPS frame.
+	* config/mips/crtn.S (fini, init): New labels.
+
 2013-02-08  Georg-Johann Lay  <avr@gjlay.de>
 
 	PR target/54222
Index: config/mips/mips16.S
===================================================================
--- config/mips/mips16.S	(revision 195931)
+++ config/mips/mips16.S	(working copy)
@@ -21,6 +21,10 @@
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#ifdef __mips_micromips
+  /* DO NOTHING */
+#else
+
 /* This file contains mips16 floating point support functions.  These
    functions are called by mips16 code to handle floating point when
    -msoft-float is not used.  They accept the arguments and return
@@ -718,3 +722,4 @@
 #endif /* !__mips_single_float */
 
 #endif
+#endif /* __mips_micromips */
Index: config/mips/linux-unwind.h
===================================================================
--- config/mips/linux-unwind.h	(revision 195931)
+++ config/mips/linux-unwind.h	(working copy)
@@ -51,6 +51,11 @@
   _Unwind_Ptr new_cfa, reg_offset;
   int i;
 
+  /* A MIPS16 or microMIPS frame.  Signal frames always use the standard
+     ISA encoding.  */
+  if ((_Unwind_Ptr) pc & 3)
+    return _URC_END_OF_STACK;
+
   /* 24021061 li v0, 0x1061 (rt_sigreturn)*/
   /* 0000000c syscall    */
   /*    or */
Index: config/mips/crtn.S
===================================================================
--- config/mips/crtn.S	(revision 195931)
+++ config/mips/crtn.S	(working copy)
@@ -31,6 +31,7 @@
 #endif
 
 	.section .init,"ax",@progbits
+init:	
 #ifdef __mips64
 	ld      RA,40($sp)
 	daddu	$sp,$sp,48
@@ -41,6 +42,7 @@
 	j	RA
 
 	.section .fini,"ax",@progbits
+fini:	
 #ifdef	__mips64
 	ld	RA,40($sp)
 	daddu	$sp,$sp,48

[-- Attachment #6: gcc-testsuite.cl --]
[-- Type: application/octet-stream, Size: 620 bytes --]

2013-02-18  Catherine Moore  <clm@codesourcery.com>

	* gcc.target/mips/mips.exp: microMIPS support.
	* gcc.target/mips/umips-movep-2.c: New test.
	* gcc.target/mips/umips-constraints-1.c: New test.
	* gcc.target/mips/umips-lwp-swp-1.c: New test.
	* gcc.target/mips/umips-constraints-2.c: New test.
	* gcc.target/mips/umips-save-restore-1.c: New test.
	* gcc.target/mips/umips-lwp-swp-2.c: New test.
	* gcc.target/mips/umips-save-restore-2.c: New test.
	* gcc.target/mips/umips-lwp-swp-volatile.c: New test.
	* gcc.target/mips/umips-save-restore-3.c: New test.
	* gcc.target/mips/umips-movep-1.c: New test.

[-- Attachment #7: gcc-testsuite.patch --]
[-- Type: application/octet-stream, Size: 12793 bytes --]

Index: gcc.target/mips/umips-movep-2.c
===================================================================
--- gcc.target/mips/umips-movep-2.c	(revision 0)
+++ gcc.target/mips/umips-movep-2.c	(revision 0)
@@ -0,0 +1,12 @@
+/* Check that we can generate the MOVEP instruction.  */
+/* { dg-options "-fpeephole2 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+int bar (int, int);
+
+int
+foo (int n, int a)
+{
+  return bar (0, 0);
+}
+/* { dg-final { scan-assembler "\tmovep\t" } } */
Index: gcc.target/mips/umips-constraints-1.c
===================================================================
--- gcc.target/mips/umips-constraints-1.c	(revision 0)
+++ gcc.target/mips/umips-constraints-1.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *x)
+{
+  asm volatile ("insn1\t%a0" :: "ZD" (&x[0]));
+  asm volatile ("insn2\t%a0" :: "ZD" (&x[511]));
+  asm volatile ("insn3\t%a0" :: "ZD" (&x[512]));
+}
+
+/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
+/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
+/* { dg-final { scan-assembler-not "\tinsn3\t2048\\(" } } */
Index: gcc.target/mips/mips.exp
===================================================================
--- gcc.target/mips/mips.exp	(revision 195578)
+++ gcc.target/mips/mips.exp	(working copy)
@@ -238,6 +238,7 @@ set mips_option_groups {
     fp "-mfp(32|64)"
     gp "-mgp(32|64)"
     long "-mlong(32|64)"
+    micromips "-mmicromips|-mno-micromips"
     mips16 "-mips16|-mno-mips16|-mflip-mips16"
     mips3d "-mips3d|-mno-mips3d"
     pic "-f(no-|)(pic|PIC)"
@@ -1246,6 +1247,10 @@ proc mips-dg-options { args } {
 	append extra_tool_flags " -DMIPS16=__attribute__((mips16))"
     }
 
+    if { [mips_have_test_option_p options "-mmicromips"] } {
+	append extra_tool_flags " -DMICROMIPS=__attribute__((micromips))"
+    }
+
     # Use our version of gcc-dg-test for this test.
     if { ![string equal [info procs "mips-gcc-dg-test"] ""] } {
 	rename gcc-dg-test mips-old-gcc-dg-test
@@ -1275,6 +1280,6 @@ proc mips-gcc-dg-test { prog do_what extra_tool_fl
 dg-init
 mips-dg-init
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
-    "-DNOMIPS16=__attribute__((nomips16))"
+    "-DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression))"
 mips-dg-finish
 dg-finish
Index: gcc.target/mips/umips-lwp-swp-1.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-1.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-1.c	(revision 0)
@@ -0,0 +1,17 @@
+/* Test that an SWP can be generated when the instruction order is reversed:
+   
+   ie.  ST $3, mem+4
+	ST $2, mem
+*/
+   
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (long long l1, long long *l2)
+{
+  *l2 = l1;
+}
+/* { dg-final { scan-assembler "\tswp\t\\\$4,0\\(\\\$6\\)" } }*/
Index: gcc.target/mips/umips-constraints-2.c
===================================================================
--- gcc.target/mips/umips-constraints-2.c	(revision 0)
+++ gcc.target/mips/umips-constraints-2.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *x)
+{
+  asm volatile ("insn1\t%0" :: "ZC" (x[0]));
+  asm volatile ("insn2\t%0" :: "ZC" (x[511]));
+  asm volatile ("insn3\t%0" :: "ZC" (x[512]));
+}
+
+/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
+/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
+/* { dg-final { scan-assembler-not "\tinsn3\t2048\\(" } } */
Index: gcc.target/mips/umips-save-restore-1.c
===================================================================
--- gcc.target/mips/umips-save-restore-1.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-1.c	(revision 0)
@@ -0,0 +1,18 @@
+/* Check that we can use the swm/lwm instructions.  */
+/* { dg-options "-mabi=32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+int bar (int, int, int, int, int);
+
+MICROMIPS int
+foo (int n, int a, int b, int c, int d) 
+{
+  int i, j;
+
+  i = bar (n, a, b, c, d);
+  j = bar (n, a, b, c, d);
+  return i + j;
+}
+
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$2(0|1),\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$2(0|1),\\\$31" } } */
Index: gcc.target/mips/umips-lwp-swp-2.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-2.c	(revision 0)
@@ -0,0 +1,176 @@
+/* Test that an SWP can be generated when the instruction order is not reversed:
+   
+   ie.  ST $2, mem
+	ST $2, mem+4
+*/
+   
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+#include <stdarg.h>
+
+void MICROMIPS s(int, ...);
+void MICROMIPS z(int, ...);
+void MICROMIPS c(int, ...);
+
+typedef int l[500];
+
+void
+MICROMIPS f (int n)
+{
+  int i;
+  l a0, a1, a2, a3, a4, a5, a6, a7, a8, a9;
+  l a10, a11, a12, a13, a14, a15, a16, a17, a18, a19;
+  l a20, a21, a22, a23, a24, a25, a26, a27, a28, a29;
+  l a30, a31, a32, a33, a34, a35, a36, a37, a38, a39;
+  int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
+  int i10, i11, i12, i13, i14, i15, i16, i17, i18, i19;
+  int i20, i21, i22, i23, i24, i25, i26, i27, i28, i29;
+  int i30, i31, i32, i33, i34, i35, i36, i37, i38, i39;
+
+  for (i = 0; i < n; i++)
+    {
+      s (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
+	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
+         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
+         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
+      i0 = a0[0];
+      i1 = a1[0];
+      i2 = a2[0];
+      i3 = a3[0];
+      i4 = a4[0];
+      i5 = a5[0];
+      i6 = a6[0];
+      i7 = a7[0];
+      i8 = a8[0];
+      i9 = a9[0];
+      i10 = a10[0];
+      i11 = a11[0];
+      i12 = a12[0];
+      i13 = a13[0];
+      i14 = a14[0];
+      i15 = a15[0];
+      i16 = a16[0];
+      i17 = a17[0];
+      i18 = a18[0];
+      i19 = a19[0];
+      i20 = a20[0];
+      i21 = a21[0];
+      i22 = a22[0];
+      i23 = a23[0];
+      i24 = a24[0];
+      i25 = a25[0];
+      i26 = a26[0];
+      i27 = a27[0];
+      i28 = a28[0];
+      i29 = a29[0];
+      i30 = a30[0];
+      i31 = a31[0];
+      i32 = a32[0];
+      i33 = a33[0];
+      i34 = a34[0];
+      i35 = a35[0];
+      i36 = a36[0];
+      i37 = a37[0];
+      i38 = a38[0];
+      i39 = a39[0];
+      z (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
+	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
+         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
+         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
+      a0[i0] = i0;
+      a1[i1] = i1;
+      a2[i2] = i2;
+      a3[i3] = i3;
+      a4[i4] = i4;
+      a5[i5] = i5;
+      a6[i6] = i6;
+      a7[i7] = i7;
+      a8[i8] = i8;
+      a9[i9] = i9;
+      a10[i10] = i10;
+      a11[i11] = i11;
+      a12[i12] = i12;
+      a13[i13] = i13;
+      a14[i14] = i14;
+      a15[i15] = i15;
+      a16[i16] = i16;
+      a17[i17] = i17;
+      a18[i18] = i18;
+      a19[i19] = i19;
+      a20[i20] = i20;
+      a21[i21] = i21;
+      a22[i22] = i22;
+      a23[i23] = i23;
+      a24[i24] = i24;
+      a25[i25] = i25;
+      a26[i26] = i26;
+      a27[i27] = i27;
+      a28[i28] = i28;
+      a29[i29] = i29;
+      a30[i30] = i30;
+      a31[i31] = i31;
+      a32[i32] = i32;
+      a33[i33] = i33;
+      a34[i34] = i34;
+      a35[i35] = i35;
+      a36[i36] = i36;
+      a37[i37] = i37;
+      a38[i38] = i38;
+      a39[i39] = i39;
+      c (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
+	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
+         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
+         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
+    }
+}
+
+int
+MICROMIPS main ()
+{
+  f (1);
+}
+
+void
+MICROMIPS s (int n, ...)
+{
+  va_list list;
+
+  va_start (list, n);
+  while (n--)
+    {
+      int *a = va_arg (list, int *);
+      a[0] = n;
+    }
+  va_end (list);
+}
+
+void
+MICROMIPS z (int n, ...)
+{
+  va_list list;
+
+  va_start (list, n);
+  while (n--)
+    {
+      int *a = va_arg (list, int *);
+      __builtin_memset (a, 0, sizeof (l));
+    }
+  va_end (list);
+}
+
+void
+MICROMIPS c (int n, ...)
+{
+  va_list list;
+
+  va_start (list, n);
+  while (n--)
+    {
+      int *a = va_arg (list, int *);
+      if (a[n] != n)
+	;
+    }
+  va_end (list);
+}
+/* { dg-final { scan-assembler "\tswp" } } */
Index: gcc.target/mips/umips-save-restore-2.c
===================================================================
--- gcc.target/mips/umips-save-restore-2.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-2.c	(revision 0)
@@ -0,0 +1,16 @@
+/* Check that we can use the save instruction to save spilled arguments.  */
+/* { dg-options "-mabi=32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *a, int b, int c)
+{
+  asm volatile ("" ::: "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+		"$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16",
+		"$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24",
+		"$25", "$30", "memory");
+  a[b] = 1;
+  a[c] = 1;
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$23,\\\$fp" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$23,\\\$fp" } } */
Index: gcc.target/mips/umips-lwp-swp-volatile.c
===================================================================
--- gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
+++ gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-mmicromips" } */
+
+/* This test ensures that we do not generate microMIPS SWP or LWP
+   instructions when any component of the accessed memory is volatile; 
+   they are unsafe for such since they might cause replay of partial 
+   accesses if interrupted by an exception.  */
+
+static void set_csr (volatile void *p, int v)
+{
+  *(volatile int *) (p) = v;
+}
+
+static int get_csr (volatile void *p)
+{
+  return *(volatile int *) (p);
+}
+
+int main ()
+{
+  int i, q = 0, p = 0, r = 0;
+
+  for (i = 0; i < 20; i++)
+    {
+      set_csr ((volatile void *) 0xbf0100a8, 0xffff0002);
+      set_csr ((volatile void *) 0xbf0100a4, 0x80000008);
+    }
+
+  for (i = 0; i < 20; i++)
+    {
+      register int k, j;
+      k = get_csr ((volatile void *) 0xbf0100b8);
+      p += k;
+      j = get_csr ((volatile void *) 0xbf0100b4);
+      r += j;
+      q = j + k;
+    }
+  return q + r + p;
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } } */
+/* { dg-final { scan-assembler-not "\tlwp" } } */
Index: gcc.target/mips/umips-save-restore-3.c
===================================================================
--- gcc.target/mips/umips-save-restore-3.c	(revision 0)
+++ gcc.target/mips/umips-save-restore-3.c	(revision 0)
@@ -0,0 +1,14 @@
+/* Check that we can use the swm instruction to save $16, $17 and $31.  */
+/* { dg-options "-mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void bar (void);
+
+MICROMIPS void
+foo (void)
+{
+  bar ();
+  asm volatile ("" ::: "$16", "$17");
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$17,\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$17,\\\$31" } } */
Index: gcc.target/mips/umips-movep-1.c
===================================================================
--- gcc.target/mips/umips-movep-1.c	(revision 0)
+++ gcc.target/mips/umips-movep-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* Check that we can generate the MOVEP instruction.  */
+/* { dg-options "-mgp32 -fpeephole2 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+long long bar (long long, long long);
+
+MICROMIPS long long
+foo (long long n, long long a)
+{
+  long long i, j;
+
+  i = bar (n, a);
+  j = bar (n, a);
+  return i + j;
+}
+/* { dg-final { scan-assembler "\tmovep\t" } } */

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-21  2:28                   ` Moore, Catherine
@ 2013-02-21 21:20                     ` Richard Sandiford
  2013-02-24 23:52                       ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-02-21 21:20 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> Looks good otherwise, but please post an updated patch.  It's probably
>> stating the obvious, but the patch is too invasive for this late stage
>> of 4.8, so
>> it'll need to wait until 4.9.
>> 
>
> The updated patch is attached.  How's it looking this time?

Almost there. :-)

As I mentioned in an earlier reply, please always check for warnings.
If you're not bootstrapping on a MIPS host then instead configure the
cross compiler with --enable-werror-always, using a recent GCC as the
host compiler.  If the patch goes in with warnings, it'll break the
build for other people.

The warnings I could see are:

> +  for (n = 0; n < XVECLEN (pattern, 0); n++)
> +    {
> +      rtx set, reg, mem, this_base;
> +      HOST_WIDE_INT this_offset;
> +      unsigned int this_regno;

this_regno is an unused variable (thanks for making it unused though).

>  static bool
>  mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
>  {
> +
> +  unsigned int compression_mode = mips_get_compress_mode (decl);

compression_mode is unused.

> +static bool
> +umips_build_save_restore (mips_save_restore_fn fn,
> +			  unsigned *mask, HOST_WIDE_INT *offset)
> +{
> +  int i, nregs;
> +  unsigned int j;
> +  rtx pattern, set, reg, mem;
> +  HOST_WIDE_INT this_offset;
> +  rtx this_base;
> +
> +  /* Try matching $16 to $31 (s0 to ra).  */
> +  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
> +    if ((*mask & 0xffff0000) == umips_swm_mask[i])
> +      break;
> +
> +  if (i == ARRAY_SIZE (umips_swm_mask))
> +    return false;

"i" needs to be unsigned to avoid a "comparison between signed and unsigned"
warning.

> +/* Return the assembly instruction for microMIPS lwm or swm.
> +   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
> +
> +const char *
> +umips_output_save_restore (bool save_p, rtx pattern)
> +{
> +  static char buffer[300];
> +  char *s;
> +  int n;
> +  HOST_WIDE_INT offset;
> +  rtx base, mem, set, reg, last_set, last_reg;
> +
> +  /* Parse the pattern.  */
> +  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
> +
> +  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
> +  s += strlen (s);
> +  n = XVECLEN (pattern, 0);
> +
> +  set = XVECEXP (pattern, 0, 0);
> +  reg = save_p ? SET_SRC (set) : SET_DEST (set);

"reg" is unused and should be deleted.

In case it sounds otherwise, I didn't build the patch to try to catch you out.
I built it so that I could try to answer:

> > Is this a test of the swap_p case?  Thanks if so, but could you add a comment
> > saying where the SWP gets generated, and why the test needs to be skipped
> > at -O1 and -Os?
> > 
> Yes, this was the swap_p case.  But it turns out that umips-lpw-swp-1.c
> was also testing the swap_p case.  I've now dropped this test in favor
> of a different test that exercises the swap_p = false case.
> You had mentioned testing for explicit registers.  This is turning out
> to be problematic.  The Linux and ELF tool chains don't always use the
> same register set.  In addition, -O3 seems to expose more opportunities
> for generating these instructions so the code generated isn't consistent
> among optimization options.  I've changed it back to just testing for
> swp, but I'm open to other suggestions.

I've attached some tests below, both for LWP (which didn't seem to be
covered) and SWP.  They use things like multiplication to force a
particular load or store order in scheduled code, so that both swap_p
and !swap_p are covered (verified using both printfs and -fno-peephole2).
umips-lwp-7.c tests for:

  /* Avoid invalid load pair instructions.  */
  if (load_p && REGNO (first_reg) == REGNO (base1))
    return false;

  /* We must avoid this case for anti-dependence.
     Ex:  lw $3, 4($3)
          lw $2, 0($3)
     first_reg is $2, but the base is $3.  */
  if (load_p
      && swap_p
      && REGNO (first_reg) + 1 == REGNO (base1))
    return false;

while umips-lwp-8.c is an example of something that would be pessimised
by not having the swap_p test above.

I also noticed a couple of other things while testing:

- ISA_HAS_LOAD_DELAY should be false for microMIPS, otherwise we'll try
  to insert nops after LWP on targets that default to -mips1, and ICE
  when we see that we have a double SET.

- In the testsuite, a -mmicromips test option should override an ambient
  -mips16, and vice versa.

- umips-movep-2.c fails on n64 because there the moves are DImode rather
  than SImode.  Since the initial patch is just for 32-bit, I forced
  -mgp32 for now.  Also, the function needs a MICROMIPS attribute.

There were various other minor formatting and comment nits that were probably
easier for me to fix than describe.  There was also some trailing whitespace.

The patch is OK for 4.9 with this one applied on top of it, provided that
it works with your setup of course.  Thanks for your patience!

Richard


Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	2013-02-21 19:57:26.000000000 +0000
+++ gcc/config/mips/constraints.md	2013-02-21 20:24:30.909497318 +0000
@@ -239,9 +239,10 @@ (define_memory_constraint "ZC"
    @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
    equivalent to @code{R}."
   (and (match_code "mem")
-       (if_then_else (match_test "TARGET_MICROMIPS")
-		     (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)")
-		     (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+       (if_then_else
+	 (match_test "TARGET_MICROMIPS")
+	 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)")
+	 (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
 
 (define_address_constraint "ZD"
   "When compiling microMIPS code, this constraint matches an address operand
Index: gcc/config/mips/micromips.md
===================================================================
--- gcc/config/mips/micromips.md	2013-02-21 19:57:26.000000000 +0000
+++ gcc/config/mips/micromips.md	2013-02-21 20:29:35.840530555 +0000
@@ -48,8 +48,7 @@ (define_peephole2
   "TARGET_MICROMIPS
    && umips_load_store_pair_p (true, operands)"
   [(parallel [(set (match_dup 0) (match_dup 1))
-              (set (match_dup 2) (match_dup 3))])]
-)
+              (set (match_dup 2) (match_dup 3))])])
 
 ;; The behavior of the LWP insn is undefined if placed in a delay slot.
 (define_insn "*lwp"
@@ -77,8 +76,7 @@ (define_peephole2
   "TARGET_MICROMIPS
    && umips_load_store_pair_p (false, operands)"
   [(parallel [(set (match_dup 0) (match_dup 1))
-              (set (match_dup 2) (match_dup 3))])]
-)
+              (set (match_dup 2) (match_dup 3))])])
 
 ;; The behavior of the SWP insn is undefined if placed in a delay slot.
 (define_insn "*swp"
@@ -106,8 +104,7 @@ (define_peephole2
   "TARGET_MICROMIPS
    && umips_movep_target_p (operands[0], operands[2])"
   [(parallel [(set (match_dup 0) (match_dup 1))
-              (set (match_dup 2) (match_dup 3))])]
-)
+              (set (match_dup 2) (match_dup 3))])])
 
 ;; The behavior of the MOVEP insn is undefined if placed in a delay slot.
 (define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	2013-02-21 20:03:53.631341344 +0000
+++ gcc/config/mips/mips.c	2013-02-21 21:08:27.247096879 +0000
@@ -1252,7 +1252,7 @@ mips_use_debug_exception_return_p (tree
 }
 
 /* Return the set of compression modes that are explicitly required
-   by DECL.  */
+   by the attributes in ATTRIBUTES.  */
 
 static unsigned int
 mips_get_compress_on_flags (tree attributes)
@@ -1269,7 +1269,7 @@ mips_get_compress_on_flags (tree attribu
 }
 
 /* Return the set of compression modes that are explicitly forbidden
-   by DECL.  */
+   by the attributes in ATTRIBUTES.  */
 
 static unsigned int
 mips_get_compress_off_flags (tree attributes)
@@ -1290,6 +1290,7 @@ mips_get_compress_off_flags (tree attrib
 
 /* Return the compression mode that should be used for function DECL.
    Return the ambient setting if DECL is null.  */
+
 static unsigned int
 mips_get_compress_mode (tree decl)
 {
@@ -1411,20 +1412,16 @@ mips_merge_decl_attributes (tree olddecl
 
   diff = (mips_get_compress_on_flags (DECL_ATTRIBUTES (olddecl))
 	  ^ mips_get_compress_on_flags (DECL_ATTRIBUTES (newdecl)));
-
   if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
 	   DECL_NAME (newdecl), mips_get_compress_on_name (diff));
 
-
   diff = (mips_get_compress_off_flags (DECL_ATTRIBUTES (olddecl))
 	  ^ mips_get_compress_off_flags (DECL_ATTRIBUTES (newdecl)));
-
   if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
 	   DECL_NAME (newdecl), mips_get_compress_off_name (diff));
 
-
   return merge_attributes (DECL_ATTRIBUTES (olddecl),
 			   DECL_ATTRIBUTES (newdecl));
 }
@@ -6194,7 +6191,7 @@ mips_start_function_definition (const ch
   if (TARGET_MICROMIPS)
     fprintf (asm_out_file, "\t.set\tmicromips\n");
 #ifdef HAVE_GAS_MICROMIPS
-  else 
+  else
     fprintf (asm_out_file, "\t.set\tnomicromips\n");
 #endif
 
@@ -7040,8 +7037,6 @@ mips_call_may_need_jalx_p (tree decl)
 static bool
 mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
 {
-
-  unsigned int compression_mode = mips_get_compress_mode (decl);
   if (!TARGET_SIBCALLS)
     return false;
 
@@ -7050,8 +7045,8 @@ mips_function_ok_for_sibcall (tree decl,
   if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
     return false;
 
-  /* Direct Js are only possible to functions that use the same ISA
-  encoding.  There is no JX counterpoart of JALX.  */
+  /* Direct Js are only possible to functions that use the same ISA encoding.
+     There is no JX counterpoart of JALX.  */
   if (decl
       && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
       && mips_call_may_need_jalx_p (decl))
@@ -10400,10 +10395,10 @@ mips_save_reg (rtx reg, rtx mem)
    instruction.  The entries are ordered by number of registers set in
    the mask.  We also ignore the single register encodings because a
    normal SW/LW is preferred.  */
-   
+
 static const unsigned int umips_swm_mask[17] = {
   0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
-  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,	
+  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,
   0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
   0x000f0000, 0x80030000, 0x00070000, 0x80010000,
   0x00030000
@@ -10424,8 +10419,8 @@ static const unsigned int umips_swm_enco
 umips_build_save_restore (mips_save_restore_fn fn,
 			  unsigned *mask, HOST_WIDE_INT *offset)
 {
-  int i, nregs;
-  unsigned int j;
+  int nregs;
+  unsigned int i, j;
   rtx pattern, set, reg, mem;
   HOST_WIDE_INT this_offset;
   rtx this_base;
@@ -10438,7 +10433,7 @@ umips_build_save_restore (mips_save_rest
   if (i == ARRAY_SIZE (umips_swm_mask))
     return false;
 
-  /* Adjust offset for output.  */
+  /* Get the offset of the lowest save slot.  */
   nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
   this_offset = *offset - UNITS_PER_WORD * (nregs - 1);
 
@@ -10453,10 +10448,9 @@ umips_build_save_restore (mips_save_rest
   /* For registers $16-$23 and $30.  */
   for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
     {
-      unsigned int regno;
       HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
       mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
-      regno = (j != 8) ? 16 + j : 30;
+      unsigned int regno = (j != 8) ? 16 + j : 30;
       *mask &= ~(1 << regno);
       reg = gen_rtx_REG (SImode, regno);
       if (fn == mips_save_reg)
@@ -10488,7 +10482,7 @@ umips_build_save_restore (mips_save_rest
 
   pattern = emit_insn (pattern);
   if (fn == mips_save_reg)
-    RTX_FRAME_RELATED_P (pattern) = 1;  
+    RTX_FRAME_RELATED_P (pattern) = 1;
 
   /* Adjust the last offset.  */
   *offset -= UNITS_PER_WORD * nregs;
@@ -10514,7 +10508,7 @@ mips_for_each_saved_gpr_and_fpr (HOST_WI
      the return register be stored at func+4, and also it allows us not to
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
-  offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+  offset = frame->gp_sp_offset - sp_offset;
   mask = frame->mask;
 
   if (TARGET_MICROMIPS)
@@ -17087,8 +17081,8 @@ mips_option_override (void)
 
   /* Now select the ISA mode.
 
-     Do all CPP-sensitive stuff in uncompressed mode;
-     We'll switch modes later if required.  */
+     Do all CPP-sensitive stuff in uncompressed mode; we'll switch modes
+     later if required.  */
   mips_set_compression_mode (0);
 }
 
@@ -17366,7 +17360,6 @@ umips_save_restore_pattern_p (bool save_
     {
       rtx set, reg, mem, this_base;
       HOST_WIDE_INT this_offset;
-      unsigned int this_regno;
 
       /* Check that we have a SET.  */
       set = XVECEXP (pattern, 0, n);
@@ -17414,7 +17407,8 @@ umips_save_restore_pattern_p (bool save_
 
   return false;
 }
-/* Return the assembly instruction for microMIPS lwm or swm.
+
+/* Return the assembly instruction for microMIPS LWM or SWM.
    SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
 
 const char *
@@ -17424,7 +17418,7 @@ umips_output_save_restore (bool save_p,
   char *s;
   int n;
   HOST_WIDE_INT offset;
-  rtx base, mem, set, reg, last_set, last_reg;
+  rtx base, mem, set, last_set, last_reg;
 
   /* Parse the pattern.  */
   gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
@@ -17434,7 +17428,6 @@ umips_output_save_restore (bool save_p,
   n = XVECLEN (pattern, 0);
 
   set = XVECEXP (pattern, 0, 0);
-  reg = save_p ? SET_SRC (set) : SET_DEST (set);
   mem = save_p ? SET_DEST (set) : SET_SRC (set);
   mips_split_plus (XEXP (mem, 0), &base, &offset);
 
@@ -17506,7 +17499,9 @@ umips_load_store_pair_p_1 (bool load_p,
   return true;
 }
 
-/* Return true if operands can be used in an LWP or SWP instruction.  */
+/* OPERANDS describes the operands to a pair of SETs, in the order
+   dest1, src1, dest2, src2.  Return true if the operands can be used
+   in an LWP or SWP instruction; LOAD_P says which.  */
 
 bool
 umips_load_store_pair_p (bool load_p, rtx *operands)
@@ -17537,8 +17532,9 @@ umips_load_store_pair_p (bool load_p, rt
   return false;
 }
 
-/* Return the assembly instruction for microMIPS lwp or swp.
-   LOAD_P is true for load.  */
+/* Return the assembly instruction for a microMIPS LWP or SWP in which
+   the first register is REG and the first memory slot is MEM.
+   LOAD_P is true for LWP.  */
 
 static void
 umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
@@ -17551,6 +17547,9 @@ umips_output_load_store_pair_1 (bool loa
     output_asm_insn ("swp\t%0,%1", ops);
 }
 
+/* Output the assembly instruction for a microMIPS LWP or SWP instruction.
+   LOAD_P and OPERANDS are as for umips_load_store_pair_p.  */
+
 void
 umips_output_load_store_pair (bool load_p, rtx *operands)
 {
@@ -17569,7 +17568,7 @@ umips_output_load_store_pair (bool load_
       mem1 = operands[0];
       mem2 = operands[2];
     }
-   
+
   if (REGNO (reg2) == REGNO (reg1) + 1)
     {
       umips_output_load_store_pair_1 (load_p, reg1, mem1);
@@ -17588,12 +17587,12 @@ umips_movep_target_p (rtx reg1, rtx reg2
   int regno1, regno2, pair;
   unsigned int i;
   static const int match[8] = {
-    0x00000060,	/* 5, 6 */
-    0x000000a0,	/* 5, 7 */
-    0x000000c0,	/* 6, 7 */
-    0x00200010,	/* 4, 21 */
-    0x00400010,	/* 4, 22 */
-    0x00000030,	/* 4, 5 */
+    0x00000060, /* 5, 6 */
+    0x000000a0, /* 5, 7 */
+    0x000000c0, /* 6, 7 */
+    0x00200010, /* 4, 21 */
+    0x00400010, /* 4, 22 */
+    0x00000030, /* 4, 5 */
     0x00000050, /* 4, 6 */
     0x00000090  /* 4, 7 */
   };
@@ -17604,7 +17603,7 @@ umips_movep_target_p (rtx reg1, rtx reg2
   regno1 = REGNO (reg1);
   regno2 = REGNO (reg2);
 
-  if (!GP_REG_P (regno1)  || !GP_REG_P (regno2))
+  if (!GP_REG_P (regno1) || !GP_REG_P (regno2))
     return false;
 
   pair = (1 << regno1) | (1 << regno2);
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	2013-02-21 20:03:53.632341352 +0000
+++ gcc/config/mips/mips.h	2013-02-21 20:04:23.070542151 +0000
@@ -1019,7 +1019,8 @@ #define ISA_HAS_DSPR2		(TARGET_DSPR2 &&
    and "addiu $4,$4,1".  */
 #define ISA_HAS_LOAD_DELAY	(ISA_MIPS1				\
 				 && !TARGET_MIPS3900			\
-				 && !TARGET_MIPS16)
+				 && !TARGET_MIPS16			\
+				 && !TARGET_MICROMIPS)
 
 /* Likewise mtc1 and mfc1.  */
 #define ISA_HAS_XFER_DELAY	(mips_isa <= 3			\
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	2013-02-21 19:57:26.000000000 +0000
+++ gcc/config/mips/mips.md	2013-02-21 20:06:12.347267724 +0000
@@ -5471,7 +5471,7 @@ (define_insn "*branch_equality<mode>"
     return mips_output_conditional_branch (insn, operands,
 					   "%*b%C1z%:\t%2,%0",
 					   "%*b%N1z%:\t%2,%0");
-    
+
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
Index: gcc/testsuite/gcc.target/mips/mips.exp
===================================================================
--- gcc/testsuite/gcc.target/mips/mips.exp	2013-02-21 20:03:53.632341352 +0000
+++ gcc/testsuite/gcc.target/mips/mips.exp	2013-02-21 20:04:23.071542158 +0000
@@ -817,6 +817,8 @@ proc mips-dg-finish {} {
 #            |                           |
 #         -mips16/-mflip-mips16       -mno-mips16
 #            |                           |
+#         -micromips                  -mno-micromips
+#            |                           |
 #         -mips3d                     -mno-mips3d
 #            |                           |
 #         -mpaired-single             -mno-paired-single
@@ -905,6 +907,8 @@ proc mips-dg-options { args } {
 
     # Handle dependencies between options on the left of the
     # dependency diagram.
+    mips_option_dependency options "-mips16" "-mno-micromips"
+    mips_option_dependency options "-mmicromips" "-mno-mips16"
     mips_option_dependency options "-mips3d" "-mpaired-single"
     mips_option_dependency options "-mpaired-single" "-mfp64"
     mips_option_dependency options "-mfp64" "-mhard-float"
Index: gcc/testsuite/gcc.target/mips/umips-lwp-1.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-1.c	2013-02-21 20:33:17.980173008 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[0];
+  int r6 = r4[1];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,0\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-2.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-2.c	2013-02-21 20:36:21.709519202 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[0];
+  int r6 = r4[1];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,0\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-3.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-3.c	2013-02-21 20:36:29.710578763 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[511];
+  int r6 = r4[512];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,2044\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-4.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-4.c	2013-02-21 20:36:37.533637002 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[511];
+  int r6 = r4[512];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,2044\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-5.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-5.c	2013-02-21 20:36:46.255701936 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[512];
+  int r6 = r4[513];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-6.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-6.c	2013-02-21 20:36:53.911758937 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[512];
+  int r6 = r4[513];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-7.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-7.c	2013-02-21 20:04:23.074542181 +0000
@@ -0,0 +1,41 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+f1 (int *r4, int dummy, int *other)
+{
+  int r5 = r4[1];
+  int newr4 = r4[0];
+  other[0] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r4asm asm ("$4") = newr4;
+    asm ("#foo" : "=m" (other[1]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+void MICROMIPS
+f2 (int *r4, int dummy, int *other)
+{
+  int newr4 = r4[0];
+  int r5 = *(int *)(newr4 + 4);
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r4asm asm ("$4") = newr4;
+    asm ("#foo" : "=m" (other[0]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+void MICROMIPS
+f3 (int dummy, int *r5, int *other)
+{
+  int newr5 = r5[1];
+  int r4 = *(int *)newr5;
+  {
+    register int r5asm asm ("$4") = r4;
+    register int r4asm asm ("$5") = newr5;
+    asm ("#foo" : "=m" (other[0]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-8.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-8.c	2013-02-21 20:04:23.074542181 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+f1 (int dummy, int *r5, int *other)
+{
+  int r4 = r5[0];
+  int newr5 = r5[1];
+  other[0] = r4 * r4;
+  {
+    register int r5asm asm ("$4") = r4;
+    register int r4asm asm ("$5") = newr5;
+    asm ("#foo" : "=m" (other[1]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$4,0\\(\\\$5\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-swp-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-swp-1.c	2013-02-21 20:03:53.633341359 +0000
+++ /dev/null	2013-02-18 18:12:58.656083693 +0000
@@ -1,17 +0,0 @@
-/* Test that an SWP can be generated when the instruction order is reversed:
-   
-   ie.  ST $3, mem+4
-	ST $2, mem
-*/
-   
-/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
-/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
-/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
-/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
-
-void MICROMIPS
-foo (long long l1, long long *l2)
-{
-  *l2 = l1;
-}
-/* { dg-final { scan-assembler "\tswp\t\\\$4,0\\(\\\$6\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-swp-2.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-swp-2.c	2013-02-21 20:03:53.633341359 +0000
+++ /dev/null	2013-02-18 18:12:58.656083693 +0000
@@ -1,176 +0,0 @@
-/* Test that an SWP can be generated when the instruction order is not reversed:
-   
-   ie.  ST $2, mem
-	ST $2, mem+4
-*/
-   
-/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
-/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
-
-#include <stdarg.h>
-
-void MICROMIPS s(int, ...);
-void MICROMIPS z(int, ...);
-void MICROMIPS c(int, ...);
-
-typedef int l[500];
-
-void
-MICROMIPS f (int n)
-{
-  int i;
-  l a0, a1, a2, a3, a4, a5, a6, a7, a8, a9;
-  l a10, a11, a12, a13, a14, a15, a16, a17, a18, a19;
-  l a20, a21, a22, a23, a24, a25, a26, a27, a28, a29;
-  l a30, a31, a32, a33, a34, a35, a36, a37, a38, a39;
-  int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
-  int i10, i11, i12, i13, i14, i15, i16, i17, i18, i19;
-  int i20, i21, i22, i23, i24, i25, i26, i27, i28, i29;
-  int i30, i31, i32, i33, i34, i35, i36, i37, i38, i39;
-
-  for (i = 0; i < n; i++)
-    {
-      s (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
-	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
-         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
-         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
-      i0 = a0[0];
-      i1 = a1[0];
-      i2 = a2[0];
-      i3 = a3[0];
-      i4 = a4[0];
-      i5 = a5[0];
-      i6 = a6[0];
-      i7 = a7[0];
-      i8 = a8[0];
-      i9 = a9[0];
-      i10 = a10[0];
-      i11 = a11[0];
-      i12 = a12[0];
-      i13 = a13[0];
-      i14 = a14[0];
-      i15 = a15[0];
-      i16 = a16[0];
-      i17 = a17[0];
-      i18 = a18[0];
-      i19 = a19[0];
-      i20 = a20[0];
-      i21 = a21[0];
-      i22 = a22[0];
-      i23 = a23[0];
-      i24 = a24[0];
-      i25 = a25[0];
-      i26 = a26[0];
-      i27 = a27[0];
-      i28 = a28[0];
-      i29 = a29[0];
-      i30 = a30[0];
-      i31 = a31[0];
-      i32 = a32[0];
-      i33 = a33[0];
-      i34 = a34[0];
-      i35 = a35[0];
-      i36 = a36[0];
-      i37 = a37[0];
-      i38 = a38[0];
-      i39 = a39[0];
-      z (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
-	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
-         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
-         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
-      a0[i0] = i0;
-      a1[i1] = i1;
-      a2[i2] = i2;
-      a3[i3] = i3;
-      a4[i4] = i4;
-      a5[i5] = i5;
-      a6[i6] = i6;
-      a7[i7] = i7;
-      a8[i8] = i8;
-      a9[i9] = i9;
-      a10[i10] = i10;
-      a11[i11] = i11;
-      a12[i12] = i12;
-      a13[i13] = i13;
-      a14[i14] = i14;
-      a15[i15] = i15;
-      a16[i16] = i16;
-      a17[i17] = i17;
-      a18[i18] = i18;
-      a19[i19] = i19;
-      a20[i20] = i20;
-      a21[i21] = i21;
-      a22[i22] = i22;
-      a23[i23] = i23;
-      a24[i24] = i24;
-      a25[i25] = i25;
-      a26[i26] = i26;
-      a27[i27] = i27;
-      a28[i28] = i28;
-      a29[i29] = i29;
-      a30[i30] = i30;
-      a31[i31] = i31;
-      a32[i32] = i32;
-      a33[i33] = i33;
-      a34[i34] = i34;
-      a35[i35] = i35;
-      a36[i36] = i36;
-      a37[i37] = i37;
-      a38[i38] = i38;
-      a39[i39] = i39;
-      c (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
-	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
-         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
-         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
-    }
-}
-
-int
-MICROMIPS main ()
-{
-  f (1);
-}
-
-void
-MICROMIPS s (int n, ...)
-{
-  va_list list;
-
-  va_start (list, n);
-  while (n--)
-    {
-      int *a = va_arg (list, int *);
-      a[0] = n;
-    }
-  va_end (list);
-}
-
-void
-MICROMIPS z (int n, ...)
-{
-  va_list list;
-
-  va_start (list, n);
-  while (n--)
-    {
-      int *a = va_arg (list, int *);
-      __builtin_memset (a, 0, sizeof (l));
-    }
-  va_end (list);
-}
-
-void
-MICROMIPS c (int n, ...)
-{
-  va_list list;
-
-  va_start (list, n);
-  while (n--)
-    {
-      int *a = va_arg (list, int *);
-      if (a[n] != n)
-	;
-    }
-  va_end (list);
-}
-/* { dg-final { scan-assembler "\tswp" } } */
Index: gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c	2013-02-21 19:57:47.000000000 +0000
+++ gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c	2013-02-21 20:04:49.560724491 +0000
@@ -2,8 +2,8 @@
 /* { dg-options "-mmicromips" } */
 
 /* This test ensures that we do not generate microMIPS SWP or LWP
-   instructions when any component of the accessed memory is volatile; 
-   they are unsafe for such since they might cause replay of partial 
+   instructions when any component of the accessed memory is volatile;
+   they are unsafe for such since they might cause replay of partial
    accesses if interrupted by an exception.  */
 
 static void set_csr (volatile void *p, int v)
Index: gcc/testsuite/gcc.target/mips/umips-movep-2.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-movep-2.c	2013-02-21 20:03:53.632341352 +0000
+++ gcc/testsuite/gcc.target/mips/umips-movep-2.c	2013-02-21 20:42:40.247604192 +0000
@@ -1,12 +1,13 @@
 /* Check that we can generate the MOVEP instruction.  */
-/* { dg-options "-fpeephole2 (-mmicromips)" } */
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
 /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
 
 int bar (int, int);
 
-int
+int MICROMIPS
 foo (int n, int a)
 {
   return bar (0, 0);
 }
-/* { dg-final { scan-assembler "\tmovep\t" } } */
+
+/* { dg-final { scan-assembler "\tmovep\t\\\$4,\\\$5,\\\$0,\\\$0" } } */
Index: gcc/testsuite/gcc.target/mips/umips-save-restore-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-save-restore-1.c	2013-02-21 19:57:47.000000000 +0000
+++ gcc/testsuite/gcc.target/mips/umips-save-restore-1.c	2013-02-21 20:06:37.807422840 +0000
@@ -5,7 +5,7 @@
 int bar (int, int, int, int, int);
 
 MICROMIPS int
-foo (int n, int a, int b, int c, int d) 
+foo (int n, int a, int b, int c, int d)
 {
   int i, j;
 
Index: gcc/testsuite/gcc.target/mips/umips-swp-1.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-swp-1.c	2013-02-21 20:04:23.075542188 +0000
@@ -0,0 +1,10 @@
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (long long l1, long long *l2)
+{
+  *l2 = l1;
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$4,0\\(\\\$6\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-2.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-swp-2.c	2013-02-21 20:40:04.431076334 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[0] = r5;
+  r4[1] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,0\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-3.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-swp-3.c	2013-02-21 20:40:16.614164109 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[0] = r5;
+  r4[1] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,0\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-4.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-swp-4.c	2013-02-21 20:40:21.540184989 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[511] = r5;
+  r4[512] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,2044\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-5.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-swp-5.c	2013-02-21 20:40:28.131170677 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[511] = r5;
+  r4[512] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,2044\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-6.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-swp-6.c	2013-02-21 20:40:33.757163423 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[512] = r5;
+  r4[513] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-7.c
===================================================================
--- /dev/null	2013-02-18 18:12:58.656083693 +0000
+++ gcc/testsuite/gcc.target/mips/umips-swp-7.c	2013-02-21 20:40:38.486160549 +0000
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[512] = r5;
+  r4[513] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } }*/

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-21 21:20                     ` Richard Sandiford
@ 2013-02-24 23:52                       ` Moore, Catherine
  2013-02-25  9:41                         ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-02-24 23:52 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 40638 bytes --]

HI Richard, 
The base patch is now committed.  The final patch, including your final edits is attached.  I will be posting the optimization pieces later this week.
Thanks for working with me on this.
Catherine


> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Thursday, February 21, 2013 4:20 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> >> Looks good otherwise, but please post an updated patch.  It's
> >> probably stating the obvious, but the patch is too invasive for this
> >> late stage of 4.8, so it'll need to wait until 4.9.
> >>
> >
> > The updated patch is attached.  How's it looking this time?
> 
> Almost there. :-)
> 
> As I mentioned in an earlier reply, please always check for warnings.
> If you're not bootstrapping on a MIPS host then instead configure the cross
> compiler with --enable-werror-always, using a recent GCC as the host
> compiler.  If the patch goes in with warnings, it'll break the build for other
> people.
> 
> The warnings I could see are:
> 
> > +  for (n = 0; n < XVECLEN (pattern, 0); n++)
> > +    {
> > +      rtx set, reg, mem, this_base;
> > +      HOST_WIDE_INT this_offset;
> > +      unsigned int this_regno;
> 
> this_regno is an unused variable (thanks for making it unused though).
> 
> >  static bool
> >  mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
> > {
> > +
> > +  unsigned int compression_mode = mips_get_compress_mode (decl);
> 
> compression_mode is unused.
> 
> > +static bool
> > +umips_build_save_restore (mips_save_restore_fn fn,
> > +			  unsigned *mask, HOST_WIDE_INT *offset) {
> > +  int i, nregs;
> > +  unsigned int j;
> > +  rtx pattern, set, reg, mem;
> > +  HOST_WIDE_INT this_offset;
> > +  rtx this_base;
> > +
> > +  /* Try matching $16 to $31 (s0 to ra).  */  for (i = 0; i <
> > + ARRAY_SIZE (umips_swm_mask); i++)
> > +    if ((*mask & 0xffff0000) == umips_swm_mask[i])
> > +      break;
> > +
> > +  if (i == ARRAY_SIZE (umips_swm_mask))
> > +    return false;
> 
> "i" needs to be unsigned to avoid a "comparison between signed and
> unsigned"
> warning.
> 
> > +/* Return the assembly instruction for microMIPS lwm or swm.
> > +   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
> > +
> > +const char *
> > +umips_output_save_restore (bool save_p, rtx pattern) {
> > +  static char buffer[300];
> > +  char *s;
> > +  int n;
> > +  HOST_WIDE_INT offset;
> > +  rtx base, mem, set, reg, last_set, last_reg;
> > +
> > +  /* Parse the pattern.  */
> > +  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
> > +
> > +  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");  s += strlen (s);
> > + n = XVECLEN (pattern, 0);
> > +
> > +  set = XVECEXP (pattern, 0, 0);
> > +  reg = save_p ? SET_SRC (set) : SET_DEST (set);
> 
> "reg" is unused and should be deleted.
> 
> In case it sounds otherwise, I didn't build the patch to try to catch you out.
> I built it so that I could try to answer:
> 
> > > Is this a test of the swap_p case?  Thanks if so, but could you add
> > > a comment saying where the SWP gets generated, and why the test
> > > needs to be skipped at -O1 and -Os?
> > >
> > Yes, this was the swap_p case.  But it turns out that
> > umips-lpw-swp-1.c was also testing the swap_p case.  I've now dropped
> > this test in favor of a different test that exercises the swap_p = false case.
> > You had mentioned testing for explicit registers.  This is turning out
> > to be problematic.  The Linux and ELF tool chains don't always use the
> > same register set.  In addition, -O3 seems to expose more
> > opportunities for generating these instructions so the code generated
> > isn't consistent among optimization options.  I've changed it back to
> > just testing for swp, but I'm open to other suggestions.
> 
> I've attached some tests below, both for LWP (which didn't seem to be
> covered) and SWP.  They use things like multiplication to force a particular
> load or store order in scheduled code, so that both swap_p and !swap_p are
> covered (verified using both printfs and -fno-peephole2).
> umips-lwp-7.c tests for:
> 
>   /* Avoid invalid load pair instructions.  */
>   if (load_p && REGNO (first_reg) == REGNO (base1))
>     return false;
> 
>   /* We must avoid this case for anti-dependence.
>      Ex:  lw $3, 4($3)
>           lw $2, 0($3)
>      first_reg is $2, but the base is $3.  */
>   if (load_p
>       && swap_p
>       && REGNO (first_reg) + 1 == REGNO (base1))
>     return false;
> 
> while umips-lwp-8.c is an example of something that would be pessimised by
> not having the swap_p test above.
> 
> I also noticed a couple of other things while testing:
> 
> - ISA_HAS_LOAD_DELAY should be false for microMIPS, otherwise we'll try
>   to insert nops after LWP on targets that default to -mips1, and ICE
>   when we see that we have a double SET.
> 
> - In the testsuite, a -mmicromips test option should override an ambient
>   -mips16, and vice versa.
> 
> - umips-movep-2.c fails on n64 because there the moves are DImode rather
>   than SImode.  Since the initial patch is just for 32-bit, I forced
>   -mgp32 for now.  Also, the function needs a MICROMIPS attribute.
> 
> There were various other minor formatting and comment nits that were
> probably easier for me to fix than describe.  There was also some trailing
> whitespace.
> 
> The patch is OK for 4.9 with this one applied on top of it, provided that it
> works with your setup of course.  Thanks for your patience!
> 
> Richard
> 
> 
> Index: gcc/config/mips/constraints.md
> ==========================================================
> =========
> --- gcc/config/mips/constraints.md	2013-02-21 19:57:26.000000000 +0000
> +++ gcc/config/mips/constraints.md	2013-02-21 20:24:30.909497318 +0000
> @@ -239,9 +239,10 @@ (define_memory_constraint "ZC"
>     @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
>     equivalent to @code{R}."
>    (and (match_code "mem")
> -       (if_then_else (match_test "TARGET_MICROMIPS")
> -		     (match_test "umips_12bit_offset_address_p (XEXP (op,
> 0), mode)")
> -		     (match_test "mips_address_insns (XEXP (op, 0), mode,
> false)"))))
> +       (if_then_else
> +	 (match_test "TARGET_MICROMIPS")
> +	 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)")
> +	 (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
> 
>  (define_address_constraint "ZD"
>    "When compiling microMIPS code, this constraint matches an address
> operand
> Index: gcc/config/mips/micromips.md
> ==========================================================
> =========
> --- gcc/config/mips/micromips.md	2013-02-21 19:57:26.000000000 +0000
> +++ gcc/config/mips/micromips.md	2013-02-21 20:29:35.840530555 +0000
> @@ -48,8 +48,7 @@ (define_peephole2
>    "TARGET_MICROMIPS
>     && umips_load_store_pair_p (true, operands)"
>    [(parallel [(set (match_dup 0) (match_dup 1))
> -              (set (match_dup 2) (match_dup 3))])]
> -)
> +              (set (match_dup 2) (match_dup 3))])])
> 
>  ;; The behavior of the LWP insn is undefined if placed in a delay slot.
>  (define_insn "*lwp"
> @@ -77,8 +76,7 @@ (define_peephole2
>    "TARGET_MICROMIPS
>     && umips_load_store_pair_p (false, operands)"
>    [(parallel [(set (match_dup 0) (match_dup 1))
> -              (set (match_dup 2) (match_dup 3))])]
> -)
> +              (set (match_dup 2) (match_dup 3))])])
> 
>  ;; The behavior of the SWP insn is undefined if placed in a delay slot.
>  (define_insn "*swp"
> @@ -106,8 +104,7 @@ (define_peephole2
>    "TARGET_MICROMIPS
>     && umips_movep_target_p (operands[0], operands[2])"
>    [(parallel [(set (match_dup 0) (match_dup 1))
> -              (set (match_dup 2) (match_dup 3))])]
> -)
> +              (set (match_dup 2) (match_dup 3))])])
> 
>  ;; The behavior of the MOVEP insn is undefined if placed in a delay slot.
>  (define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
> Index: gcc/config/mips/mips.c
> ==========================================================
> =========
> --- gcc/config/mips/mips.c	2013-02-21 20:03:53.631341344 +0000
> +++ gcc/config/mips/mips.c	2013-02-21 21:08:27.247096879 +0000
> @@ -1252,7 +1252,7 @@ mips_use_debug_exception_return_p (tree  }
> 
>  /* Return the set of compression modes that are explicitly required
> -   by DECL.  */
> +   by the attributes in ATTRIBUTES.  */
> 
>  static unsigned int
>  mips_get_compress_on_flags (tree attributes) @@ -1269,7 +1269,7 @@
> mips_get_compress_on_flags (tree attribu  }
> 
>  /* Return the set of compression modes that are explicitly forbidden
> -   by DECL.  */
> +   by the attributes in ATTRIBUTES.  */
> 
>  static unsigned int
>  mips_get_compress_off_flags (tree attributes) @@ -1290,6 +1290,7 @@
> mips_get_compress_off_flags (tree attrib
> 
>  /* Return the compression mode that should be used for function DECL.
>     Return the ambient setting if DECL is null.  */
> +
>  static unsigned int
>  mips_get_compress_mode (tree decl)
>  {
> @@ -1411,20 +1412,16 @@ mips_merge_decl_attributes (tree olddecl
> 
>    diff = (mips_get_compress_on_flags (DECL_ATTRIBUTES (olddecl))
>  	  ^ mips_get_compress_on_flags (DECL_ATTRIBUTES (newdecl)));
> -
>    if (diff)
>      error ("%qE redeclared with conflicting %qs attributes",
>  	   DECL_NAME (newdecl), mips_get_compress_on_name (diff));
> 
> -
>    diff = (mips_get_compress_off_flags (DECL_ATTRIBUTES (olddecl))
>  	  ^ mips_get_compress_off_flags (DECL_ATTRIBUTES (newdecl)));
> -
>    if (diff)
>      error ("%qE redeclared with conflicting %qs attributes",
>  	   DECL_NAME (newdecl), mips_get_compress_off_name (diff));
> 
> -
>    return merge_attributes (DECL_ATTRIBUTES (olddecl),
>  			   DECL_ATTRIBUTES (newdecl));
>  }
> @@ -6194,7 +6191,7 @@ mips_start_function_definition (const ch
>    if (TARGET_MICROMIPS)
>      fprintf (asm_out_file, "\t.set\tmicromips\n");  #ifdef
> HAVE_GAS_MICROMIPS
> -  else
> +  else
>      fprintf (asm_out_file, "\t.set\tnomicromips\n");  #endif
> 
> @@ -7040,8 +7037,6 @@ mips_call_may_need_jalx_p (tree decl)  static bool
> mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)  {
> -
> -  unsigned int compression_mode = mips_get_compress_mode (decl);
>    if (!TARGET_SIBCALLS)
>      return false;
> 
> @@ -7050,8 +7045,8 @@ mips_function_ok_for_sibcall (tree decl,
>    if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
>      return false;
> 
> -  /* Direct Js are only possible to functions that use the same ISA
> -  encoding.  There is no JX counterpoart of JALX.  */
> +  /* Direct Js are only possible to functions that use the same ISA encoding.
> +     There is no JX counterpoart of JALX.  */
>    if (decl
>        && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
>        && mips_call_may_need_jalx_p (decl)) @@ -10400,10 +10395,10 @@
> mips_save_reg (rtx reg, rtx mem)
>     instruction.  The entries are ordered by number of registers set in
>     the mask.  We also ignore the single register encodings because a
>     normal SW/LW is preferred.  */
> -
> +
>  static const unsigned int umips_swm_mask[17] = {
>    0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
> -  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,
> +  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,
>    0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
>    0x000f0000, 0x80030000, 0x00070000, 0x80010000,
>    0x00030000
> @@ -10424,8 +10419,8 @@ static const unsigned int umips_swm_enco
> umips_build_save_restore (mips_save_restore_fn fn,
>  			  unsigned *mask, HOST_WIDE_INT *offset)  {
> -  int i, nregs;
> -  unsigned int j;
> +  int nregs;
> +  unsigned int i, j;
>    rtx pattern, set, reg, mem;
>    HOST_WIDE_INT this_offset;
>    rtx this_base;
> @@ -10438,7 +10433,7 @@ umips_build_save_restore (mips_save_rest
>    if (i == ARRAY_SIZE (umips_swm_mask))
>      return false;
> 
> -  /* Adjust offset for output.  */
> +  /* Get the offset of the lowest save slot.  */
>    nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
>    this_offset = *offset - UNITS_PER_WORD * (nregs - 1);
> 
> @@ -10453,10 +10448,9 @@ umips_build_save_restore (mips_save_rest
>    /* For registers $16-$23 and $30.  */
>    for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
>      {
> -      unsigned int regno;
>        HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
>        mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base,
> offset));
> -      regno = (j != 8) ? 16 + j : 30;
> +      unsigned int regno = (j != 8) ? 16 + j : 30;
>        *mask &= ~(1 << regno);
>        reg = gen_rtx_REG (SImode, regno);
>        if (fn == mips_save_reg)
> @@ -10488,7 +10482,7 @@ umips_build_save_restore (mips_save_rest
> 
>    pattern = emit_insn (pattern);
>    if (fn == mips_save_reg)
> -    RTX_FRAME_RELATED_P (pattern) = 1;
> +    RTX_FRAME_RELATED_P (pattern) = 1;
> 
>    /* Adjust the last offset.  */
>    *offset -= UNITS_PER_WORD * nregs;
> @@ -10514,7 +10508,7 @@ mips_for_each_saved_gpr_and_fpr (HOST_WI
>       the return register be stored at func+4, and also it allows us not to
>       need a nop in the epilogue if at least one register is reloaded in
>       addition to return address.  */
> -  offset = cfun->machine->frame.gp_sp_offset - sp_offset;
> +  offset = frame->gp_sp_offset - sp_offset;
>    mask = frame->mask;
> 
>    if (TARGET_MICROMIPS)
> @@ -17087,8 +17081,8 @@ mips_option_override (void)
> 
>    /* Now select the ISA mode.
> 
> -     Do all CPP-sensitive stuff in uncompressed mode;
> -     We'll switch modes later if required.  */
> +     Do all CPP-sensitive stuff in uncompressed mode; we'll switch modes
> +     later if required.  */
>    mips_set_compression_mode (0);
>  }
> 
> @@ -17366,7 +17360,6 @@ umips_save_restore_pattern_p (bool save_
>      {
>        rtx set, reg, mem, this_base;
>        HOST_WIDE_INT this_offset;
> -      unsigned int this_regno;
> 
>        /* Check that we have a SET.  */
>        set = XVECEXP (pattern, 0, n);
> @@ -17414,7 +17407,8 @@ umips_save_restore_pattern_p (bool save_
> 
>    return false;
>  }
> -/* Return the assembly instruction for microMIPS lwm or swm.
> +
> +/* Return the assembly instruction for microMIPS LWM or SWM.
>     SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
> 
>  const char *
> @@ -17424,7 +17418,7 @@ umips_output_save_restore (bool save_p,
>    char *s;
>    int n;
>    HOST_WIDE_INT offset;
> -  rtx base, mem, set, reg, last_set, last_reg;
> +  rtx base, mem, set, last_set, last_reg;
> 
>    /* Parse the pattern.  */
>    gcc_assert (umips_save_restore_pattern_p (save_p, pattern)); @@ -
> 17434,7 +17428,6 @@ umips_output_save_restore (bool save_p,
>    n = XVECLEN (pattern, 0);
> 
>    set = XVECEXP (pattern, 0, 0);
> -  reg = save_p ? SET_SRC (set) : SET_DEST (set);
>    mem = save_p ? SET_DEST (set) : SET_SRC (set);
>    mips_split_plus (XEXP (mem, 0), &base, &offset);
> 
> @@ -17506,7 +17499,9 @@ umips_load_store_pair_p_1 (bool load_p,
>    return true;
>  }
> 
> -/* Return true if operands can be used in an LWP or SWP instruction.  */
> +/* OPERANDS describes the operands to a pair of SETs, in the order
> +   dest1, src1, dest2, src2.  Return true if the operands can be used
> +   in an LWP or SWP instruction; LOAD_P says which.  */
> 
>  bool
>  umips_load_store_pair_p (bool load_p, rtx *operands) @@ -17537,8
> +17532,9 @@ umips_load_store_pair_p (bool load_p, rt
>    return false;
>  }
> 
> -/* Return the assembly instruction for microMIPS lwp or swp.
> -   LOAD_P is true for load.  */
> +/* Return the assembly instruction for a microMIPS LWP or SWP in which
> +   the first register is REG and the first memory slot is MEM.
> +   LOAD_P is true for LWP.  */
> 
>  static void
>  umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem) @@ -
> 17551,6 +17547,9 @@ umips_output_load_store_pair_1 (bool loa
>      output_asm_insn ("swp\t%0,%1", ops);  }
> 
> +/* Output the assembly instruction for a microMIPS LWP or SWP instruction.
> +   LOAD_P and OPERANDS are as for umips_load_store_pair_p.  */
> +
>  void
>  umips_output_load_store_pair (bool load_p, rtx *operands)  { @@ -17569,7
> +17568,7 @@ umips_output_load_store_pair (bool load_
>        mem1 = operands[0];
>        mem2 = operands[2];
>      }
> -
> +
>    if (REGNO (reg2) == REGNO (reg1) + 1)
>      {
>        umips_output_load_store_pair_1 (load_p, reg1, mem1); @@ -17588,12
> +17587,12 @@ umips_movep_target_p (rtx reg1, rtx reg2
>    int regno1, regno2, pair;
>    unsigned int i;
>    static const int match[8] = {
> -    0x00000060,	/* 5, 6 */
> -    0x000000a0,	/* 5, 7 */
> -    0x000000c0,	/* 6, 7 */
> -    0x00200010,	/* 4, 21 */
> -    0x00400010,	/* 4, 22 */
> -    0x00000030,	/* 4, 5 */
> +    0x00000060, /* 5, 6 */
> +    0x000000a0, /* 5, 7 */
> +    0x000000c0, /* 6, 7 */
> +    0x00200010, /* 4, 21 */
> +    0x00400010, /* 4, 22 */
> +    0x00000030, /* 4, 5 */
>      0x00000050, /* 4, 6 */
>      0x00000090  /* 4, 7 */
>    };
> @@ -17604,7 +17603,7 @@ umips_movep_target_p (rtx reg1, rtx reg2
>    regno1 = REGNO (reg1);
>    regno2 = REGNO (reg2);
> 
> -  if (!GP_REG_P (regno1)  || !GP_REG_P (regno2))
> +  if (!GP_REG_P (regno1) || !GP_REG_P (regno2))
>      return false;
> 
>    pair = (1 << regno1) | (1 << regno2);
> Index: gcc/config/mips/mips.h
> ==========================================================
> =========
> --- gcc/config/mips/mips.h	2013-02-21 20:03:53.632341352 +0000
> +++ gcc/config/mips/mips.h	2013-02-21 20:04:23.070542151 +0000
> @@ -1019,7 +1019,8 @@ #define ISA_HAS_DSPR2
> 	(TARGET_DSPR2 &&
>     and "addiu $4,$4,1".  */
>  #define ISA_HAS_LOAD_DELAY	(ISA_MIPS1
> 	\
>  				 && !TARGET_MIPS3900
> 	\
> -				 && !TARGET_MIPS16)
> +				 && !TARGET_MIPS16			\
> +				 && !TARGET_MICROMIPS)
> 
>  /* Likewise mtc1 and mfc1.  */
>  #define ISA_HAS_XFER_DELAY	(mips_isa <= 3			\
> Index: gcc/config/mips/mips.md
> ==========================================================
> =========
> --- gcc/config/mips/mips.md	2013-02-21 19:57:26.000000000 +0000
> +++ gcc/config/mips/mips.md	2013-02-21 20:06:12.347267724 +0000
> @@ -5471,7 +5471,7 @@ (define_insn "*branch_equality<mode>"
>      return mips_output_conditional_branch (insn, operands,
>  					   "%*b%C1z%:\t%2,%0",
>  					   "%*b%N1z%:\t%2,%0");
> -
> +
>    return mips_output_conditional_branch (insn, operands,
>  					 MIPS_BRANCH ("b%C1",
> "%2,%z3,%0"),
>  					 MIPS_BRANCH ("b%N1",
> "%2,%z3,%0"));
> Index: gcc/testsuite/gcc.target/mips/mips.exp
> ==========================================================
> =========
> --- gcc/testsuite/gcc.target/mips/mips.exp	2013-02-21
> 20:03:53.632341352 +0000
> +++ gcc/testsuite/gcc.target/mips/mips.exp	2013-02-21
> 20:04:23.071542158 +0000
> @@ -817,6 +817,8 @@ proc mips-dg-finish {} {
>  #            |                           |
>  #         -mips16/-mflip-mips16       -mno-mips16
>  #            |                           |
> +#         -micromips                  -mno-micromips
> +#            |                           |
>  #         -mips3d                     -mno-mips3d
>  #            |                           |
>  #         -mpaired-single             -mno-paired-single
> @@ -905,6 +907,8 @@ proc mips-dg-options { args } {
> 
>      # Handle dependencies between options on the left of the
>      # dependency diagram.
> +    mips_option_dependency options "-mips16" "-mno-micromips"
> +    mips_option_dependency options "-mmicromips" "-mno-mips16"
>      mips_option_dependency options "-mips3d" "-mpaired-single"
>      mips_option_dependency options "-mpaired-single" "-mfp64"
>      mips_option_dependency options "-mfp64" "-mhard-float"
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-1.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-1.c	2013-02-21
> 20:33:17.980173008 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4)
> +{
> +  int r5 = r4[0];
> +  int r6 = r4[1];
> +  r4[2] = r5 * r5;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tlwp\t\\\$5,0\\(\\\$4\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-2.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-2.c	2013-02-21
> 20:36:21.709519202 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4)
> +{
> +  int r5 = r4[0];
> +  int r6 = r4[1];
> +  r4[2] = r6 * r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tlwp\t\\\$5,0\\(\\\$4\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-3.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-3.c	2013-02-21
> 20:36:29.710578763 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4)
> +{
> +  int r5 = r4[511];
> +  int r6 = r4[512];
> +  r4[2] = r5 * r5;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tlwp\t\\\$5,2044\\(\\\$4\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-4.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-4.c	2013-02-21
> 20:36:37.533637002 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4)
> +{
> +  int r5 = r4[511];
> +  int r6 = r4[512];
> +  r4[2] = r6 * r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tlwp\t\\\$5,2044\\(\\\$4\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-5.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-5.c	2013-02-21
> 20:36:46.255701936 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4)
> +{
> +  int r5 = r4[512];
> +  int r6 = r4[513];
> +  r4[2] = r5 * r5;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler-not "\tlwp" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-6.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-6.c	2013-02-21
> 20:36:53.911758937 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4)
> +{
> +  int r5 = r4[512];
> +  int r6 = r4[513];
> +  r4[2] = r6 * r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler-not "\tlwp" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-7.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-7.c	2013-02-21
> 20:04:23.074542181 +0000
> @@ -0,0 +1,41 @@
> +/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +f1 (int *r4, int dummy, int *other)
> +{
> +  int r5 = r4[1];
> +  int newr4 = r4[0];
> +  other[0] = r5 * r5;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r4asm asm ("$4") = newr4;
> +    asm ("#foo" : "=m" (other[1]) : "d" (r4asm), "d" (r5asm));
> +  }
> +}
> +
> +void MICROMIPS
> +f2 (int *r4, int dummy, int *other)
> +{
> +  int newr4 = r4[0];
> +  int r5 = *(int *)(newr4 + 4);
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r4asm asm ("$4") = newr4;
> +    asm ("#foo" : "=m" (other[0]) : "d" (r4asm), "d" (r5asm));
> +  }
> +}
> +
> +void MICROMIPS
> +f3 (int dummy, int *r5, int *other)
> +{
> +  int newr5 = r5[1];
> +  int r4 = *(int *)newr5;
> +  {
> +    register int r5asm asm ("$4") = r4;
> +    register int r4asm asm ("$5") = newr5;
> +    asm ("#foo" : "=m" (other[0]) : "d" (r4asm), "d" (r5asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler-not "\tlwp" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-8.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-8.c	2013-02-21
> 20:04:23.074542181 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +f1 (int dummy, int *r5, int *other)
> +{
> +  int r4 = r5[0];
> +  int newr5 = r5[1];
> +  other[0] = r4 * r4;
> +  {
> +    register int r5asm asm ("$4") = r4;
> +    register int r4asm asm ("$5") = newr5;
> +    asm ("#foo" : "=m" (other[1]) : "d" (r4asm), "d" (r5asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tlwp\t\\\$4,0\\(\\\$5\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-swp-1.c
> ==========================================================
> =========
> --- gcc/testsuite/gcc.target/mips/umips-lwp-swp-1.c	2013-02-21
> 20:03:53.633341359 +0000
> +++ /dev/null	2013-02-18 18:12:58.656083693 +0000
> @@ -1,17 +0,0 @@
> -/* Test that an SWP can be generated when the instruction order is
> reversed:
> -
> -   ie.  ST $3, mem+4
> -	ST $2, mem
> -*/
> -
> -/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
> -/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> -/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
> -/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> -
> -void MICROMIPS
> -foo (long long l1, long long *l2)
> -{
> -  *l2 = l1;
> -}
> -/* { dg-final { scan-assembler "\tswp\t\\\$4,0\\(\\\$6\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-swp-2.c
> ==========================================================
> =========
> --- gcc/testsuite/gcc.target/mips/umips-lwp-swp-2.c	2013-02-21
> 20:03:53.633341359 +0000
> +++ /dev/null	2013-02-18 18:12:58.656083693 +0000
> @@ -1,176 +0,0 @@
> -/* Test that an SWP can be generated when the instruction order is not
> reversed:
> -
> -   ie.  ST $2, mem
> -	ST $2, mem+4
> -*/
> -
> -/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
> -/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> -
> -#include <stdarg.h>
> -
> -void MICROMIPS s(int, ...);
> -void MICROMIPS z(int, ...);
> -void MICROMIPS c(int, ...);
> -
> -typedef int l[500];
> -
> -void
> -MICROMIPS f (int n)
> -{
> -  int i;
> -  l a0, a1, a2, a3, a4, a5, a6, a7, a8, a9;
> -  l a10, a11, a12, a13, a14, a15, a16, a17, a18, a19;
> -  l a20, a21, a22, a23, a24, a25, a26, a27, a28, a29;
> -  l a30, a31, a32, a33, a34, a35, a36, a37, a38, a39;
> -  int i0, i1, i2, i3, i4, i5, i6, i7, i8, i9;
> -  int i10, i11, i12, i13, i14, i15, i16, i17, i18, i19;
> -  int i20, i21, i22, i23, i24, i25, i26, i27, i28, i29;
> -  int i30, i31, i32, i33, i34, i35, i36, i37, i38, i39;
> -
> -  for (i = 0; i < n; i++)
> -    {
> -      s (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
> -	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
> -         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
> -         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
> -      i0 = a0[0];
> -      i1 = a1[0];
> -      i2 = a2[0];
> -      i3 = a3[0];
> -      i4 = a4[0];
> -      i5 = a5[0];
> -      i6 = a6[0];
> -      i7 = a7[0];
> -      i8 = a8[0];
> -      i9 = a9[0];
> -      i10 = a10[0];
> -      i11 = a11[0];
> -      i12 = a12[0];
> -      i13 = a13[0];
> -      i14 = a14[0];
> -      i15 = a15[0];
> -      i16 = a16[0];
> -      i17 = a17[0];
> -      i18 = a18[0];
> -      i19 = a19[0];
> -      i20 = a20[0];
> -      i21 = a21[0];
> -      i22 = a22[0];
> -      i23 = a23[0];
> -      i24 = a24[0];
> -      i25 = a25[0];
> -      i26 = a26[0];
> -      i27 = a27[0];
> -      i28 = a28[0];
> -      i29 = a29[0];
> -      i30 = a30[0];
> -      i31 = a31[0];
> -      i32 = a32[0];
> -      i33 = a33[0];
> -      i34 = a34[0];
> -      i35 = a35[0];
> -      i36 = a36[0];
> -      i37 = a37[0];
> -      i38 = a38[0];
> -      i39 = a39[0];
> -      z (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
> -	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
> -         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
> -         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
> -      a0[i0] = i0;
> -      a1[i1] = i1;
> -      a2[i2] = i2;
> -      a3[i3] = i3;
> -      a4[i4] = i4;
> -      a5[i5] = i5;
> -      a6[i6] = i6;
> -      a7[i7] = i7;
> -      a8[i8] = i8;
> -      a9[i9] = i9;
> -      a10[i10] = i10;
> -      a11[i11] = i11;
> -      a12[i12] = i12;
> -      a13[i13] = i13;
> -      a14[i14] = i14;
> -      a15[i15] = i15;
> -      a16[i16] = i16;
> -      a17[i17] = i17;
> -      a18[i18] = i18;
> -      a19[i19] = i19;
> -      a20[i20] = i20;
> -      a21[i21] = i21;
> -      a22[i22] = i22;
> -      a23[i23] = i23;
> -      a24[i24] = i24;
> -      a25[i25] = i25;
> -      a26[i26] = i26;
> -      a27[i27] = i27;
> -      a28[i28] = i28;
> -      a29[i29] = i29;
> -      a30[i30] = i30;
> -      a31[i31] = i31;
> -      a32[i32] = i32;
> -      a33[i33] = i33;
> -      a34[i34] = i34;
> -      a35[i35] = i35;
> -      a36[i36] = i36;
> -      a37[i37] = i37;
> -      a38[i38] = i38;
> -      a39[i39] = i39;
> -      c (40, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9,
> -	 a10, a11, a12, a13, a14, a15, a16, a17, a18, a19,
> -         a20, a21, a22, a23, a24, a25, a26, a27, a28, a29,
> -         a30, a31, a32, a33, a34, a35, a36, a37, a38, a39);
> -    }
> -}
> -
> -int
> -MICROMIPS main ()
> -{
> -  f (1);
> -}
> -
> -void
> -MICROMIPS s (int n, ...)
> -{
> -  va_list list;
> -
> -  va_start (list, n);
> -  while (n--)
> -    {
> -      int *a = va_arg (list, int *);
> -      a[0] = n;
> -    }
> -  va_end (list);
> -}
> -
> -void
> -MICROMIPS z (int n, ...)
> -{
> -  va_list list;
> -
> -  va_start (list, n);
> -  while (n--)
> -    {
> -      int *a = va_arg (list, int *);
> -      __builtin_memset (a, 0, sizeof (l));
> -    }
> -  va_end (list);
> -}
> -
> -void
> -MICROMIPS c (int n, ...)
> -{
> -  va_list list;
> -
> -  va_start (list, n);
> -  while (n--)
> -    {
> -      int *a = va_arg (list, int *);
> -      if (a[n] != n)
> -	;
> -    }
> -  va_end (list);
> -}
> -/* { dg-final { scan-assembler "\tswp" } } */
> Index: gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c
> ==========================================================
> =========
> --- gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c	2013-02-21
> 19:57:47.000000000 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c	2013-02-21
> 20:04:49.560724491 +0000
> @@ -2,8 +2,8 @@
>  /* { dg-options "-mmicromips" } */
> 
>  /* This test ensures that we do not generate microMIPS SWP or LWP
> -   instructions when any component of the accessed memory is volatile;
> -   they are unsafe for such since they might cause replay of partial
> +   instructions when any component of the accessed memory is volatile;
> +   they are unsafe for such since they might cause replay of partial
>     accesses if interrupted by an exception.  */
> 
>  static void set_csr (volatile void *p, int v)
> Index: gcc/testsuite/gcc.target/mips/umips-movep-2.c
> ==========================================================
> =========
> --- gcc/testsuite/gcc.target/mips/umips-movep-2.c	2013-02-21
> 20:03:53.632341352 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-movep-2.c	2013-02-21
> 20:42:40.247604192 +0000
> @@ -1,12 +1,13 @@
>  /* Check that we can generate the MOVEP instruction.  */
> -/* { dg-options "-fpeephole2 (-mmicromips)" } */
> +/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
>  /* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> 
>  int bar (int, int);
> 
> -int
> +int MICROMIPS
>  foo (int n, int a)
>  {
>    return bar (0, 0);
>  }
> -/* { dg-final { scan-assembler "\tmovep\t" } } */
> +
> +/* { dg-final { scan-assembler "\tmovep\t\\\$4,\\\$5,\\\$0,\\\$0" } }
> +*/
> Index: gcc/testsuite/gcc.target/mips/umips-save-restore-1.c
> ==========================================================
> =========
> --- gcc/testsuite/gcc.target/mips/umips-save-restore-1.c	2013-02-21
> 19:57:47.000000000 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-save-restore-1.c	2013-02-21
> 20:06:37.807422840 +0000
> @@ -5,7 +5,7 @@
>  int bar (int, int, int, int, int);
> 
>  MICROMIPS int
> -foo (int n, int a, int b, int c, int d)
> +foo (int n, int a, int b, int c, int d)
>  {
>    int i, j;
> 
> Index: gcc/testsuite/gcc.target/mips/umips-swp-1.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-swp-1.c	2013-02-21
> 20:04:23.075542188 +0000
> @@ -0,0 +1,10 @@
> +/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (long long l1, long long *l2)
> +{
> +  *l2 = l1;
> +}
> +
> +/* { dg-final { scan-assembler "\tswp\t\\\$4,0\\(\\\$6\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-swp-2.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-swp-2.c	2013-02-21
> 20:40:04.431076334 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4, int r5, int r6)
> +{
> +  r6 *= r6;
> +  r4[0] = r5;
> +  r4[1] = r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tswp\t\\\$5,0\\(\\\$4\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-swp-3.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-swp-3.c	2013-02-21
> 20:40:16.614164109 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4, int r5, int r6)
> +{
> +  r5 *= r5;
> +  r4[0] = r5;
> +  r4[1] = r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tswp\t\\\$5,0\\(\\\$4\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-swp-4.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-swp-4.c	2013-02-21
> 20:40:21.540184989 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4, int r5, int r6)
> +{
> +  r6 *= r6;
> +  r4[511] = r5;
> +  r4[512] = r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tswp\t\\\$5,2044\\(\\\$4\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-swp-5.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-swp-5.c	2013-02-21
> 20:40:28.131170677 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4, int r5, int r6)
> +{
> +  r5 *= r5;
> +  r4[511] = r5;
> +  r4[512] = r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler "\tswp\t\\\$5,2044\\(\\\$4\\)" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-swp-6.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-swp-6.c	2013-02-21
> 20:40:33.757163423 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4, int r5, int r6)
> +{
> +  r6 *= r6;
> +  r4[512] = r5;
> +  r4[513] = r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler-not "\tswp" } }*/
> Index: gcc/testsuite/gcc.target/mips/umips-swp-7.c
> ==========================================================
> =========
> --- /dev/null	2013-02-18 18:12:58.656083693 +0000
> +++ gcc/testsuite/gcc.target/mips/umips-swp-7.c	2013-02-21
> 20:40:38.486160549 +0000
> @@ -0,0 +1,17 @@
> +/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
> +/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
> +
> +void MICROMIPS
> +foo (int *r4, int r5, int r6)
> +{
> +  r5 *= r5;
> +  r4[512] = r5;
> +  r4[513] = r6;
> +  {
> +    register int r5asm asm ("$5") = r5;
> +    register int r6asm asm ("$6") = r6;
> +    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
> +  }
> +}
> +
> +/* { dg-final { scan-assembler-not "\tswp" } }*/

[-- Attachment #2: micromips.patch --]
[-- Type: application/octet-stream, Size: 118365 bytes --]

Index: libgcc/ChangeLog
===================================================================
--- libgcc/ChangeLog	(revision 196245)
+++ libgcc/ChangeLog	(working copy)
@@ -1,3 +1,11 @@
+2013-02-24  Catherine Moore  <clm@codesourcery.com>
+	    Joseph Myers  <joseph@codesourcery.com>
+	    Chao-ying Fu  <fu@mips.com>
+
+	* config/mips/mips16.S:  Don't build for microMIPS.
+	* config/mips/linux-unwind.h: Handle microMIPS frame.
+	* config/mips/crtn.S (fini, init): New labels.
+
 2012-02-19  Edgar E. Iglesias  <edgar.iglesias@gmail.com>
 	* config/microblaze/modsi3.S (modsi3): Fix case with 0x80000000 
 	as dividend.
Index: libgcc/config/mips/mips16.S
===================================================================
--- libgcc/config/mips/mips16.S	(revision 196218)
+++ libgcc/config/mips/mips16.S	(working copy)
@@ -21,6 +21,10 @@
 see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 <http://www.gnu.org/licenses/>.  */
 
+#ifdef __mips_micromips
+  /* DO NOTHING */
+#else
+
 /* This file contains mips16 floating point support functions.  These
    functions are called by mips16 code to handle floating point when
    -msoft-float is not used.  They accept the arguments and return
@@ -718,3 +722,4 @@
 #endif /* !__mips_single_float */
 
 #endif
+#endif /* __mips_micromips */
Index: libgcc/config/mips/linux-unwind.h
===================================================================
--- libgcc/config/mips/linux-unwind.h	(revision 196218)
+++ libgcc/config/mips/linux-unwind.h	(working copy)
@@ -51,6 +51,11 @@
   _Unwind_Ptr new_cfa, reg_offset;
   int i;
 
+  /* A MIPS16 or microMIPS frame.  Signal frames always use the standard
+     ISA encoding.  */
+  if ((_Unwind_Ptr) pc & 3)
+    return _URC_END_OF_STACK;
+
   /* 24021061 li v0, 0x1061 (rt_sigreturn)*/
   /* 0000000c syscall    */
   /*    or */
Index: libgcc/config/mips/crtn.S
===================================================================
--- libgcc/config/mips/crtn.S	(revision 196218)
+++ libgcc/config/mips/crtn.S	(working copy)
@@ -31,6 +31,7 @@
 #endif
 
 	.section .init,"ax",@progbits
+init:	
 #ifdef __mips64
 	ld      RA,40($sp)
 	daddu	$sp,$sp,48
@@ -41,6 +42,7 @@
 	j	RA
 
 	.section .fini,"ax",@progbits
+fini:	
 #ifdef	__mips64
 	ld	RA,40($sp)
 	daddu	$sp,$sp,48
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 196218)
+++ gcc/doc/extend.texi	(working copy)
@@ -3053,6 +3053,25 @@
 may interact badly with some GCC extensions such as @code{__builtin_apply}
 (@pxref{Constructing Calls}).
 
+@item micromips/nomicromips
+@cindex @code{micromips} attribute
+@cindex @code{nomicromips} attribute
+
+On MIPS targets, you can use the @code{micromips} and @code{nomicromips}
+function attributes to locally select or turn off microMIPS code generation.
+A function with the @code{micromips} attribute is emitted as microMIPS code,
+while microMIPS code generation is disabled for functions with the
+@code{nomicromips} attribute.  These attributes override the
+@option{-mmicromips} and @option{-mno-micromips} options on the command line
+(@pxref{MIPS Options}).
+
+When compiling files containing mixed microMIPS and non-microMIPS code, the
+preprocessor symbol @code{__mips_micromips} reflects the setting on the
+command line,
+not that within individual functions.  Mixed microMIPS and non-microMIPS code
+may interact badly with some GCC extensions such as @code{__builtin_apply}
+(@pxref{Constructing Calls}).
+
 @item model (@var{model-name})
 @cindex function addressability on the M32R/D
 @cindex variable addressability on the IA-64
@@ -3155,6 +3174,13 @@
 exit sequences suitable for use in an NMI handler when this
 attribute is present.
 
+@item nocompression
+@cindex @code{nocompression} attribute
+On MIPS targets, you can use the @code{nocompression} function attribute
+to locally turn off MIPS16 and microMIPS code generation.  This attribute
+overrides the @option{-mips16} and @option{-mmicromips} options on the
+command line (@pxref{MIPS Options}).
+
 @item no_instrument_function
 @cindex @code{no_instrument_function} function attribute
 @opindex finstrument-functions
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 196218)
+++ gcc/doc/invoke.texi	(working copy)
@@ -740,6 +740,7 @@
 -mips1  -mips2  -mips3  -mips4  -mips32  -mips32r2 @gol
 -mips64  -mips64r2 @gol
 -mips16  -mno-mips16  -mflip-mips16 @gol
+-minterlink-compressed -mno-interlink-compressed @gol
 -minterlink-mips16  -mno-interlink-mips16 @gol
 -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
@@ -747,6 +748,7 @@
 -mno-float -msingle-float  -mdouble-float  @gol
 -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -mmcu -mmno-mcu @gol
+-mmicromips -mno-micromips @gol
 -mfpu=@var{fpu-type} @gol
 -msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
@@ -15880,6 +15882,7 @@
 @samp{1004kc}, @samp{1004kf2_1}, @samp{1004kf1_1},
 @samp{loongson2e}, @samp{loongson2f}, @samp{loongson3a},
 @samp{m4k},
+@samp{m14k}, @samp{m14ke}, @samp{m14kec},
 @samp{octeon}, @samp{octeon+}, @samp{octeon2},
 @samp{orion},
 @samp{r2000}, @samp{r3000}, @samp{r3900}, @samp{r4000}, @samp{r4400},
@@ -15993,18 +15996,26 @@
 for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
 not intended for ordinary use in compiling user code.
 
+@item -minterlink-compressed
+@item -mno-interlink-compressed
+@opindex minterlink-compressed
+@opindex mno-interlink-compressed
+Require (do not require) that code using the standard (uncompressed) MIPS ISA
+be link-compatible with MIPS16 and microMIPS code, and vice versa.
+
+For example, code using the standard ISA encoding cannot jump directly
+to MIPS16 or microMIPS code; it must either use a call or an indirect jump.
+@option{-minterlink-compressed} therefore disables direct jumps unless GCC
+knows that the target of the jump is not compressed.
+
 @item -minterlink-mips16
 @itemx -mno-interlink-mips16
 @opindex minterlink-mips16
 @opindex mno-interlink-mips16
-Require (do not require) that non-MIPS16 code be link-compatible with
-MIPS16 code.
+Aliases of @option{-minterlink-compressed} and
+@option{-mno-interlink-compressed}.  These options predate the microMIPS ASE
+and are retained for backwards compatiblity.
 
-For example, non-MIPS16 code cannot jump directly to MIPS16 code;
-it must either use a call or an indirect jump.  @option{-minterlink-mips16}
-therefore disables direct jumps unless GCC knows that the target of the
-jump is not MIPS16.
-
 @item -mabi=32
 @itemx -mabi=o64
 @itemx -mabi=n32
@@ -16218,6 +16229,16 @@
 Use (do not use) the MIPS-3D ASE@.  @xref{MIPS-3D Built-in Functions}.
 The option @option{-mips3d} implies @option{-mpaired-single}.
 
+@item -mmicromips
+@itemx -mno-micromips
+@opindex mmicromips
+@opindex mno-mmicromips
+Generate (do not generate) microMIPS code.
+
+MicroMIPS code generation can also be controlled on a per-function basis
+by means of @code{micromips} and @code{nomicromips} attributes.
+@xref{Function Attributes}, for more information.
+
 @item -mmt
 @itemx -mno-mt
 @opindex mmt
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(revision 196218)
+++ gcc/doc/md.texi	(working copy)
@@ -2916,6 +2916,19 @@
 
 @item R
 An address that can be used in a non-macro load or store.
+
+@item ZC
+When compiling microMIPS code, this constraint matches a memory operand
+whose address is formed from a base register and a 12-bit offset.  These
+operands can be used for microMIPS instructions such as @code{ll} and
+@code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+equivalent to @code{R}.
+
+@item ZD
+When compiling microMIPS code, this constraint matches an address operand
+that is formed from a base register and a 12-bit offset.  These operands
+can be used for microMIPS instructions such as @code{prefetch}.  When
+not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}.
 @end table
 
 @item Motorola 680x0---@file{config/m68k/constraints.md}
Index: gcc/configure
===================================================================
--- gcc/configure	(revision 196218)
+++ gcc/configure	(working copy)
@@ -25708,6 +25708,37 @@
 
 fi
 
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .micromips support" >&5
+$as_echo_n "checking assembler for .micromips support... " >&6; }
+if test "${gcc_cv_as_micromips_support+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  gcc_cv_as_micromips_support=no
+  if test x$gcc_cv_as != x; then
+    $as_echo '.set micromips' > conftest.s
+    if { ac_try='$gcc_cv_as $gcc_cv_as_flags  -o conftest.o conftest.s >&5'
+  { { eval echo "\"\$as_me\":${as_lineno-$LINENO}: \"$ac_try\""; } >&5
+  (eval $ac_try) 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }
+    then
+	gcc_cv_as_micromips_support=yes
+    else
+      echo "configure: failed program was" >&5
+      cat conftest.s >&5
+    fi
+    rm -f conftest.o conftest.s
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $gcc_cv_as_micromips_support" >&5
+$as_echo "$gcc_cv_as_micromips_support" >&6; }
+if test $gcc_cv_as_micromips_support = yes; then
+
+$as_echo "#define HAVE_GAS_MICROMIPS 1" >>confdefs.h
+
+fi
+
     { $as_echo "$as_me:${as_lineno-$LINENO}: checking assembler for .dtprelword support" >&5
 $as_echo_n "checking assembler for .dtprelword support... " >&6; }
 if test "${gcc_cv_as_mips_dtprelword+set}" = set; then :
Index: gcc/ChangeLog
===================================================================
--- gcc/ChangeLog	(revision 196245)
+++ gcc/ChangeLog	(working copy)
@@ -1,3 +1,130 @@
+2013-02-24  Catherine Moore  <clm@codesourcery.com>
+	    Maciej W. Rozycki  <macro@codesourcery.com>
+	    Tom de Vries  <tom@codesourcery.com>
+	    Nathan Sidwell <nathan@codesourcery.com>
+	    Iain Sandoe  <iain@codesourcery.com>
+	    Nathan Froyd  <froydnj@codesourcery.com>
+	    Chao-ying Fu <fu@mips.com>
+
+	* doc/extend.texi: (micromips, nomicromips, nocompression):
+	Document new function attributes. 
+	* doc/invoke.texi (minterlink-compressed, mmicromips,
+	m14k, m14ke, m14kec): Document new options.
+	(minterlink-mips16): Update documentation.
+	* doc/md.texi (ZC, ZD): Document new constraints.
+	* configure.ac (gcc_cv_as_micromips): Check if linker
+	supports the .set micromips directive.
+	* configure: Regenerate.
+	* config.in: Regenerate.
+	* config/mips/mips-tables.opt: Regenerate.
+	* config/mips/micromips.md: New file.
+	* constraints.md (ZC, AD): New constraints.
+	* config/mips/predicates.md (movep_src_register): New predicate.
+	(movep_src_operand): New predicate.
+	(non_volatile_mem_operand): New predicate.
+	* config/mips/mips.md (multimem): New type.
+	(length): Differentiate between 17-bit and 18-bit branch offsets.
+	(MOVEP1, MOVEP2): New mode iterator.
+ 	(mov_<load>l): Use ZC constraint.
+	(mov_<load>r): Likewise.
+	(mov_<store>l): Likewise.
+	(mov_<store>r): Likewise.
+	(*branch_equality<mode>_inverted): Add microMIPS support.
+	(*branch_equality<mode>): Likewise.
+	(*jump_absolute): Likewise.
+	(indirect_jump_<mode>): Likewise.
+	(tablejump_<mode>): Likewise.
+	(<optab>_internal): Likewise.
+	(sibcall_internal): Likewise.
+	(sibcall_value_internal): Likewise.
+	(prefetch): Use constraint ZD.
+	* config/mips/mips.opt (minterlink-compressed): New option.
+	(minterlink-mips16): Now an alias for minterlink-compressed.
+	(mmicromips): New option.
+	* config/mips/sync.md (sync_compare_and_swap<mode>): Use ZR constraint.
+	(compare_and_swap_12): Likewise.
+	(sync_add<mode>): Likewise.
+	(sync_<optab>_12): Likewise.
+	(sync_old_<optab>_12): Likewise.
+	(sync_new_<optab>_12): Likewise.
+	(sync_nand_12): Likewise.
+	(sync_old_nand_12): Likewise.
+	(sync_new_nand_12): Likewise.
+	(sync_sub<mode>): Likewise.
+	(sync_old_add<mode>): Likewise.
+	(sync_old_sub<mode>): Likewise.
+	(sync_new_add<mode>): Likewise.
+	(sync_new_sub<mode>): Likewise.
+	(sync_<optab><mode>): Likewise.
+	(sync_old_<optab><mode>): Likewise.
+	(sync_new_<optab><mode>): Likewise.
+	(sync_nand<mode>): Likewise.
+	(sync_old_nand<mode>): Likewise.
+	(sync_new_nand<mode>): Likewise.
+	(sync_lock_test_and_set<mode>): Likewise.
+	(test_and_set_12): Likewise.
+	(atomic_compare_and_swap<mode>): Likewise.
+	(atomic_exchange<mode>_llsc): Likewise.
+	(atomic_fetch_add<mode>_llsc): Likewise.
+	* config/mips/mips-cpus.def (m14kc, m14k): New processors.
+	* config/mips/mips-protos.h (umips_output_save_restore): New prototype.
+	(umips_save_restore_pattern_p): Likewise.
+	(umips_load_store_pair_p): Likewise.
+	(umips_output_load_store_pair): Likewise.
+	(umips_movep_target_p): Likewise.
+	(umips_12bit_offset_address_p): Likewise.
+	* config/mips/mips.c (MIPS_MAX_FIRST_STEP): Update for microMIPS.
+	(mips_base_mips16): Rename this...
+	(mips_base_compression_flags): ...to this. Update all uses.
+	(mips_attribute_table): Add micromips, nomicromips and nocompression.
+	(mips_mips16_decl_p): Delete.
+	(mips_nomips16_decl_p): Delete.
+ 	(mips_get_compress_on_flags): New function.
+	(mips_get_compress_off_flags): New function.
+	(mips_get_compress_mode): New function.
+	(mips_get_compress_on_name): New function.
+	(mips_get_compress_off_name): New function.
+	(mips_insert_attributes): Support multiple compression types.
+	(mips_merge_decl_attributes): Likewise.
+	(umips_12bit_offset_address_p): New function.
+	(mips_start_function_definition): Emit .set micromips directive.
+	(mips_call_may_need_jalx_p): New function.
+	(mips_function_ok_for_sibcall): Add microMIPS support.
+	(mips_print_operand_punctuation): Support short delay slots and
+	compact jumps.
+	(umips_swm_mask, umips_swm_encoding): New.
+	(umips_build_save_restore): New function.
+	(mips_for_each_saved_gpr_and_fpr): Add microMIPS support.
+	(was_mips16_p): Remove.
+	(old_compression_mode): New.
+	(mips_set_compression_mode): New function.
+	(mips_set_current_function): Add microMIPS support.
+	(mips_option_override): Likewise.
+	(umips_save_restore_pattern_p): New function.
+	(umips_output_save_restore): New function.
+	(umips_load_store_pair_p_1): New function.
+	(umips_load_store_pair_p): New function.
+	(umips_output_load_store_pair_1): New function.
+	(umips_output_load_store_pair): New function.
+	(umips_movep_target_p) New function.
+	(mips_prepare_pch_save): Add microMIPS support.
+	* config/mips/mips.h (TARGET_COMPRESSION): New.
+	(TARGET_CPU_CPP_BUILTINS): Update macro
+	to use new compression flags and to support microMIPS.
+	(MIPS_ISA_LEVEL_SPEC): Add m14k processors.
+	(MIPS_ARCH_FLOAT_SPEC): Likewise.
+	(ISA_HAS_LWXS): Include TARGET_MICROMIPS.
+	(ISA_HAS_LOAD_DELAY): Exclude TARGET_MICROMIPS.
+	(ASM_SPEC): Support mmicromips and mno-micromips.
+	(M16STORE_REG_P): New macro.
+	(MIPS_CALL): Support TARGET_MICROMIPS.
+	(MICROMIPS_J): New macro.
+	(mips_base_mips16): Rename this...
+	(mips_base_compression_flags): ...to this.
+	(UMIPS_12BIT_OFFSET_P): New macro.
+	* config/mips/t-sde: (MULTILIB_OPTIONS): Add microMIPS.
+	(MULTILIB_DIRNAMES): Likewise.
+
 2013-02-24  Jakub Jelinek  <jakub@redhat.com>
 
 	PR target/52555
Index: gcc/testsuite/gcc.target/mips/umips-movep-2.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-movep-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-movep-2.c	(revision 0)
@@ -0,0 +1,13 @@
+/* Check that we can generate the MOVEP instruction.  */
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+int bar (int, int);
+
+int MICROMIPS
+foo (int n, int a)
+{
+  return bar (0, 0);
+}
+
+/* { dg-final { scan-assembler "\tmovep\t\\\$4,\\\$5,\\\$0,\\\$0" } } */
Index: gcc/testsuite/gcc.target/mips/umips-lwp-2.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-2.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[0];
+  int r6 = r4[1];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,0\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-5.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-swp-5.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-swp-5.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[511] = r5;
+  r4[512] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,2044\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-constraints-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-constraints-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-constraints-1.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *x)
+{
+  asm volatile ("insn1\t%a0" :: "ZD" (&x[0]));
+  asm volatile ("insn2\t%a0" :: "ZD" (&x[511]));
+  asm volatile ("insn3\t%a0" :: "ZD" (&x[512]));
+}
+
+/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
+/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
+/* { dg-final { scan-assembler-not "\tinsn3\t2048\\(" } } */
Index: gcc/testsuite/gcc.target/mips/mips.exp
===================================================================
--- gcc/testsuite/gcc.target/mips/mips.exp	(revision 196218)
+++ gcc/testsuite/gcc.target/mips/mips.exp	(working copy)
@@ -238,6 +238,7 @@
     fp "-mfp(32|64)"
     gp "-mgp(32|64)"
     long "-mlong(32|64)"
+    micromips "-mmicromips|-mno-micromips"
     mips16 "-mips16|-mno-mips16|-mflip-mips16"
     mips3d "-mips3d|-mno-mips3d"
     pic "-f(no-|)(pic|PIC)"
@@ -816,6 +817,8 @@
 #            |                           |
 #         -mips16/-mflip-mips16       -mno-mips16
 #            |                           |
+#         -micromips                  -mno-micromips
+#            |                           |
 #         -mips3d                     -mno-mips3d
 #            |                           |
 #         -mpaired-single             -mno-paired-single
@@ -904,6 +907,8 @@
 
     # Handle dependencies between options on the left of the
     # dependency diagram.
+    mips_option_dependency options "-mips16" "-mno-micromips"
+    mips_option_dependency options "-mmicromips" "-mno-mips16"
     mips_option_dependency options "-mips3d" "-mpaired-single"
     mips_option_dependency options "-mpaired-single" "-mfp64"
     mips_option_dependency options "-mfp64" "-mhard-float"
@@ -1246,6 +1251,10 @@
 	append extra_tool_flags " -DMIPS16=__attribute__((mips16))"
     }
 
+    if { [mips_have_test_option_p options "-mmicromips"] } {
+	append extra_tool_flags " -DMICROMIPS=__attribute__((micromips))"
+    }
+
     # Use our version of gcc-dg-test for this test.
     if { ![string equal [info procs "mips-gcc-dg-test"] ""] } {
 	rename gcc-dg-test mips-old-gcc-dg-test
@@ -1275,6 +1284,6 @@
 dg-init
 mips-dg-init
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
-    "-DNOMIPS16=__attribute__((nomips16))"
+    "-DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression))"
 mips-dg-finish
 dg-finish
Index: gcc/testsuite/gcc.target/mips/umips-lwp-3.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-3.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[511];
+  int r6 = r4[512];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,2044\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-6.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-swp-6.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-swp-6.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[512] = r5;
+  r4[513] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-constraints-2.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-constraints-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-constraints-2.c	(revision 0)
@@ -0,0 +1,14 @@
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *x)
+{
+  asm volatile ("insn1\t%0" :: "ZC" (x[0]));
+  asm volatile ("insn2\t%0" :: "ZC" (x[511]));
+  asm volatile ("insn3\t%0" :: "ZC" (x[512]));
+}
+
+/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
+/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
+/* { dg-final { scan-assembler-not "\tinsn3\t2048\\(" } } */
Index: gcc/testsuite/gcc.target/mips/umips-save-restore-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-save-restore-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-save-restore-1.c	(revision 0)
@@ -0,0 +1,18 @@
+/* Check that we can use the swm/lwm instructions.  */
+/* { dg-options "-mabi=32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+int bar (int, int, int, int, int);
+
+MICROMIPS int
+foo (int n, int a, int b, int c, int d)
+{
+  int i, j;
+
+  i = bar (n, a, b, c, d);
+  j = bar (n, a, b, c, d);
+  return i + j;
+}
+
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$2(0|1),\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$2(0|1),\\\$31" } } */
Index: gcc/testsuite/gcc.target/mips/umips-lwp-4.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-4.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-4.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[511];
+  int r6 = r4[512];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,2044\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-7.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-swp-7.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-swp-7.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[512] = r5;
+  r4[513] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-save-restore-2.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-save-restore-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-save-restore-2.c	(revision 0)
@@ -0,0 +1,16 @@
+/* Check that we can use the save instruction to save spilled arguments.  */
+/* { dg-options "-mabi=32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *a, int b, int c)
+{
+  asm volatile ("" ::: "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+		"$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16",
+		"$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24",
+		"$25", "$30", "memory");
+  a[b] = 1;
+  a[c] = 1;
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$23,\\\$fp" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$23,\\\$fp" } } */
Index: gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c	(revision 0)
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-mmicromips" } */
+
+/* This test ensures that we do not generate microMIPS SWP or LWP
+   instructions when any component of the accessed memory is volatile;
+   they are unsafe for such since they might cause replay of partial
+   accesses if interrupted by an exception.  */
+
+static void set_csr (volatile void *p, int v)
+{
+  *(volatile int *) (p) = v;
+}
+
+static int get_csr (volatile void *p)
+{
+  return *(volatile int *) (p);
+}
+
+int main ()
+{
+  int i, q = 0, p = 0, r = 0;
+
+  for (i = 0; i < 20; i++)
+    {
+      set_csr ((volatile void *) 0xbf0100a8, 0xffff0002);
+      set_csr ((volatile void *) 0xbf0100a4, 0x80000008);
+    }
+
+  for (i = 0; i < 20; i++)
+    {
+      register int k, j;
+      k = get_csr ((volatile void *) 0xbf0100b8);
+      p += k;
+      j = get_csr ((volatile void *) 0xbf0100b4);
+      r += j;
+      q = j + k;
+    }
+  return q + r + p;
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } } */
+/* { dg-final { scan-assembler-not "\tlwp" } } */
Index: gcc/testsuite/gcc.target/mips/umips-lwp-5.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-5.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-5.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[512];
+  int r6 = r4[513];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-save-restore-3.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-save-restore-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-save-restore-3.c	(revision 0)
@@ -0,0 +1,14 @@
+/* Check that we can use the swm instruction to save $16, $17 and $31.  */
+/* { dg-options "-mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void bar (void);
+
+MICROMIPS void
+foo (void)
+{
+  bar ();
+  asm volatile ("" ::: "$16", "$17");
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$17,\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$17,\\\$31" } } */
Index: gcc/testsuite/gcc.target/mips/umips-lwp-6.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-6.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-6.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[512];
+  int r6 = r4[513];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-swp-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-swp-1.c	(revision 0)
@@ -0,0 +1,10 @@
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (long long l1, long long *l2)
+{
+  *l2 = l1;
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$4,0\\(\\\$6\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-7.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-7.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-7.c	(revision 0)
@@ -0,0 +1,41 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+f1 (int *r4, int dummy, int *other)
+{
+  int r5 = r4[1];
+  int newr4 = r4[0];
+  other[0] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r4asm asm ("$4") = newr4;
+    asm ("#foo" : "=m" (other[1]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+void MICROMIPS
+f2 (int *r4, int dummy, int *other)
+{
+  int newr4 = r4[0];
+  int r5 = *(int *)(newr4 + 4);
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r4asm asm ("$4") = newr4;
+    asm ("#foo" : "=m" (other[0]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+void MICROMIPS
+f3 (int dummy, int *r5, int *other)
+{
+  int newr5 = r5[1];
+  int r4 = *(int *)newr5;
+  {
+    register int r5asm asm ("$4") = r4;
+    register int r4asm asm ("$5") = newr5;
+    asm ("#foo" : "=m" (other[0]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-2.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-swp-2.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-swp-2.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[0] = r5;
+  r4[1] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,0\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-lwp-8.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-8.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-8.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+f1 (int dummy, int *r5, int *other)
+{
+  int r4 = r5[0];
+  int newr5 = r5[1];
+  other[0] = r4 * r4;
+  {
+    register int r5asm asm ("$4") = r4;
+    register int r4asm asm ("$5") = newr5;
+    asm ("#foo" : "=m" (other[1]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$4,0\\(\\\$5\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-3.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-swp-3.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-swp-3.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[0] = r5;
+  r4[1] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,0\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-movep-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-movep-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-movep-1.c	(revision 0)
@@ -0,0 +1,16 @@
+/* Check that we can generate the MOVEP instruction.  */
+/* { dg-options "-mgp32 -fpeephole2 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+long long bar (long long, long long);
+
+MICROMIPS long long
+foo (long long n, long long a)
+{
+  long long i, j;
+
+  i = bar (n, a);
+  j = bar (n, a);
+  return i + j;
+}
+/* { dg-final { scan-assembler "\tmovep\t" } } */
Index: gcc/testsuite/gcc.target/mips/umips-lwp-1.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-lwp-1.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-lwp-1.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[0];
+  int r6 = r4[1];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,0\\(\\\$4\\)" } }*/
Index: gcc/testsuite/gcc.target/mips/umips-swp-4.c
===================================================================
--- gcc/testsuite/gcc.target/mips/umips-swp-4.c	(revision 0)
+++ gcc/testsuite/gcc.target/mips/umips-swp-4.c	(revision 0)
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[511] = r5;
+  r4[512] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,2044\\(\\\$4\\)" } }*/
Index: gcc/testsuite/ChangeLog
===================================================================
--- gcc/testsuite/ChangeLog	(revision 196245)
+++ gcc/testsuite/ChangeLog	(working copy)
@@ -1,3 +1,31 @@
+2013-02-24  Catherine Moore  <clm@codesourcery.com>
+	    Richard Sandiford <rdsandiford@googlemail.com>
+
+	* gcc.target/mips/mips.exp: Add microMIPS support.
+	* gcc.target/mips/umips-movep-2.c: New test.
+	* gcc.target/mips/umips-lwp-2.c: New test.
+	* gcc.target/mips/umips-swp-5.c: New test.
+	* gcc.target/mips/umips-constraints-1.c: New test.
+	* gcc.target/mips/umips-lwp-3.c: New test.
+	* gcc.target/mips/umips-swp-6.c: New test.
+	* gcc.target/mips/umips-constraints-2.c: New test.
+	* gcc.target/mips/umips-save-restore-1.c: New test.
+	* gcc.target/mips/umips-lwp-4.c: New test.
+	* gcc.target/mips/umips-swp-7.c: New test.
+	* gcc.target/mips/umips-save-restore-2.c: New test.
+	* gcc.target/mips/umips-lwp-swp-volatile.c: New test.
+	* gcc.target/mips/umips-lwp-5.c: New test.
+	* gcc.target/mips/umips-save-restore-3.c: New test.
+	* gcc.target/mips/umips-lwp-6.c: New test.
+	* gcc.target/mips/umips-swp-1.c: New test.
+	* gcc.target/mips/umips-lwp-7.c: New test.
+	* gcc.target/mips/umips-swp-2.c: New test.
+	* gcc.target/mips/umips-lwp-8.c: New test.
+	* gcc.target/mips/umips-swp-3.c: New test.
+	* gcc.target/mips/umips-movep-1.c: New test.
+	* gcc.target/mips/umips-lwp-1.c: New test.
+	* gcc.target/mips/umips-swp-4.c: New test.
+
 2013-02-22  Jakub Jelinek  <jakub@redhat.com>
 
 	PR sanitizer/56393
Index: gcc/config.in
===================================================================
--- gcc/config.in	(revision 196218)
+++ gcc/config.in	(working copy)
@@ -1034,6 +1034,12 @@
 #endif
 
 
+/* Define if your assembler supports the .set micromips directive */
+#ifndef USED_FOR_TARGET
+#undef HAVE_GAS_MICROMIPS
+#endif
+
+
 /* Define if your assembler supports .nsubspa comdat option. */
 #ifndef USED_FOR_TARGET
 #undef HAVE_GAS_NSUBSPA_COMDAT
Index: gcc/configure.ac
===================================================================
--- gcc/configure.ac	(revision 196218)
+++ gcc/configure.ac	(working copy)
@@ -4036,6 +4036,12 @@
       [AC_DEFINE(HAVE_AS_GNU_ATTRIBUTE, 1,
 	  [Define if your assembler supports .gnu_attribute.])])
 
+    gcc_GAS_CHECK_FEATURE([.micromips support],
+      gcc_cv_as_micromips_support,,,
+      [.set micromips],,
+      [AC_DEFINE(HAVE_GAS_MICROMIPS, 1,
+          [Define if your assembler supports the .set micromips directive])])
+
     gcc_GAS_CHECK_FEATURE([.dtprelword support],
       gcc_cv_as_mips_dtprelword, [2,18,0],,
       [.section .tdata,"awT",@progbits
Index: gcc/config/mips/mips-tables.opt
===================================================================
--- gcc/config/mips/mips-tables.opt	(revision 196218)
+++ gcc/config/mips/mips-tables.opt	(working copy)
@@ -373,254 +373,260 @@
 Enum(mips_arch_opt_value) String(m4k) Value(39) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kec) Value(40) Canonical
+Enum(mips_arch_opt_value) String(m14kc) Value(40) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kec) Value(40)
+Enum(mips_arch_opt_value) String(m14k) Value(41) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kem) Value(41) Canonical
+Enum(mips_arch_opt_value) String(4kec) Value(42) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kem) Value(41)
+Enum(mips_arch_opt_value) String(r4kec) Value(42)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kep) Value(42) Canonical
+Enum(mips_arch_opt_value) String(4kem) Value(43) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kep) Value(42)
+Enum(mips_arch_opt_value) String(r4kem) Value(43)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4ksd) Value(43) Canonical
+Enum(mips_arch_opt_value) String(4kep) Value(44) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4ksd) Value(43)
+Enum(mips_arch_opt_value) String(r4kep) Value(44)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kc) Value(44) Canonical
+Enum(mips_arch_opt_value) String(4ksd) Value(45) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kc) Value(44)
+Enum(mips_arch_opt_value) String(r4ksd) Value(45)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf2_1) Value(45) Canonical
+Enum(mips_arch_opt_value) String(24kc) Value(46) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf2_1) Value(45)
+Enum(mips_arch_opt_value) String(r24kc) Value(46)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf) Value(46) Canonical
+Enum(mips_arch_opt_value) String(24kf2_1) Value(47) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf) Value(46)
+Enum(mips_arch_opt_value) String(r24kf2_1) Value(47)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf1_1) Value(47) Canonical
+Enum(mips_arch_opt_value) String(24kf) Value(48) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf1_1) Value(47)
+Enum(mips_arch_opt_value) String(r24kf) Value(48)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kfx) Value(48) Canonical
+Enum(mips_arch_opt_value) String(24kf1_1) Value(49) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kfx) Value(48)
+Enum(mips_arch_opt_value) String(r24kf1_1) Value(49)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kx) Value(49) Canonical
+Enum(mips_arch_opt_value) String(24kfx) Value(50) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kx) Value(49)
+Enum(mips_arch_opt_value) String(r24kfx) Value(50)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kec) Value(50) Canonical
+Enum(mips_arch_opt_value) String(24kx) Value(51) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kec) Value(50)
+Enum(mips_arch_opt_value) String(r24kx) Value(51)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef2_1) Value(51) Canonical
+Enum(mips_arch_opt_value) String(24kec) Value(52) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef2_1) Value(51)
+Enum(mips_arch_opt_value) String(r24kec) Value(52)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef) Value(52) Canonical
+Enum(mips_arch_opt_value) String(24kef2_1) Value(53) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef) Value(52)
+Enum(mips_arch_opt_value) String(r24kef2_1) Value(53)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef1_1) Value(53) Canonical
+Enum(mips_arch_opt_value) String(24kef) Value(54) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef1_1) Value(53)
+Enum(mips_arch_opt_value) String(r24kef) Value(54)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kefx) Value(54) Canonical
+Enum(mips_arch_opt_value) String(24kef1_1) Value(55) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kefx) Value(54)
+Enum(mips_arch_opt_value) String(r24kef1_1) Value(55)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kex) Value(55) Canonical
+Enum(mips_arch_opt_value) String(24kefx) Value(56) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kex) Value(55)
+Enum(mips_arch_opt_value) String(r24kefx) Value(56)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kc) Value(56) Canonical
+Enum(mips_arch_opt_value) String(24kex) Value(57) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kc) Value(56)
+Enum(mips_arch_opt_value) String(r24kex) Value(57)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf2_1) Value(57) Canonical
+Enum(mips_arch_opt_value) String(34kc) Value(58) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf2_1) Value(57)
+Enum(mips_arch_opt_value) String(r34kc) Value(58)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf) Value(58) Canonical
+Enum(mips_arch_opt_value) String(34kf2_1) Value(59) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf) Value(58)
+Enum(mips_arch_opt_value) String(r34kf2_1) Value(59)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf1_1) Value(59) Canonical
+Enum(mips_arch_opt_value) String(34kf) Value(60) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf1_1) Value(59)
+Enum(mips_arch_opt_value) String(r34kf) Value(60)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kfx) Value(60) Canonical
+Enum(mips_arch_opt_value) String(34kf1_1) Value(61) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kfx) Value(60)
+Enum(mips_arch_opt_value) String(r34kf1_1) Value(61)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kx) Value(61) Canonical
+Enum(mips_arch_opt_value) String(34kfx) Value(62) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kx) Value(61)
+Enum(mips_arch_opt_value) String(r34kfx) Value(62)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kn) Value(62) Canonical
+Enum(mips_arch_opt_value) String(34kx) Value(63) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kn) Value(62)
+Enum(mips_arch_opt_value) String(r34kx) Value(63)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kc) Value(63) Canonical
+Enum(mips_arch_opt_value) String(34kn) Value(64) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kc) Value(63)
+Enum(mips_arch_opt_value) String(r34kn) Value(64)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf2_1) Value(64) Canonical
+Enum(mips_arch_opt_value) String(74kc) Value(65) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf2_1) Value(64)
+Enum(mips_arch_opt_value) String(r74kc) Value(65)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf) Value(65) Canonical
+Enum(mips_arch_opt_value) String(74kf2_1) Value(66) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf) Value(65)
+Enum(mips_arch_opt_value) String(r74kf2_1) Value(66)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf1_1) Value(66) Canonical
+Enum(mips_arch_opt_value) String(74kf) Value(67) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf1_1) Value(66)
+Enum(mips_arch_opt_value) String(r74kf) Value(67)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kfx) Value(67) Canonical
+Enum(mips_arch_opt_value) String(74kf1_1) Value(68) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kfx) Value(67)
+Enum(mips_arch_opt_value) String(r74kf1_1) Value(68)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kx) Value(68) Canonical
+Enum(mips_arch_opt_value) String(74kfx) Value(69) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kx) Value(68)
+Enum(mips_arch_opt_value) String(r74kfx) Value(69)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf3_2) Value(69) Canonical
+Enum(mips_arch_opt_value) String(74kx) Value(70) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf3_2) Value(69)
+Enum(mips_arch_opt_value) String(r74kx) Value(70)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kc) Value(70) Canonical
+Enum(mips_arch_opt_value) String(74kf3_2) Value(71) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kc) Value(70)
+Enum(mips_arch_opt_value) String(r74kf3_2) Value(71)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf2_1) Value(71) Canonical
+Enum(mips_arch_opt_value) String(1004kc) Value(72) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf2_1) Value(71)
+Enum(mips_arch_opt_value) String(r1004kc) Value(72)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf) Value(72) Canonical
+Enum(mips_arch_opt_value) String(1004kf2_1) Value(73) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf) Value(72)
+Enum(mips_arch_opt_value) String(r1004kf2_1) Value(73)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf1_1) Value(73) Canonical
+Enum(mips_arch_opt_value) String(1004kf) Value(74) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf1_1) Value(73)
+Enum(mips_arch_opt_value) String(r1004kf) Value(74)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kc) Value(74) Canonical
+Enum(mips_arch_opt_value) String(1004kf1_1) Value(75) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kc) Value(74)
+Enum(mips_arch_opt_value) String(r1004kf1_1) Value(75)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kf) Value(75) Canonical
+Enum(mips_arch_opt_value) String(5kc) Value(76) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kf) Value(75)
+Enum(mips_arch_opt_value) String(r5kc) Value(76)
 
 EnumValue
-Enum(mips_arch_opt_value) String(20kc) Value(76) Canonical
+Enum(mips_arch_opt_value) String(5kf) Value(77) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r20kc) Value(76)
+Enum(mips_arch_opt_value) String(r5kf) Value(77)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1) Value(77) Canonical
+Enum(mips_arch_opt_value) String(20kc) Value(78) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1a) Value(78) Canonical
+Enum(mips_arch_opt_value) String(r20kc) Value(78)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71000) Value(79) Canonical
+Enum(mips_arch_opt_value) String(sb1) Value(79) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71k) Value(79)
+Enum(mips_arch_opt_value) String(sb1a) Value(80) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlr) Value(80) Canonical
+Enum(mips_arch_opt_value) String(sr71000) Value(81) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(loongson3a) Value(81) Canonical
+Enum(mips_arch_opt_value) String(sr71k) Value(81)
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon) Value(82) Canonical
+Enum(mips_arch_opt_value) String(xlr) Value(82) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon+) Value(83) Canonical
+Enum(mips_arch_opt_value) String(loongson3a) Value(83) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon2) Value(84) Canonical
+Enum(mips_arch_opt_value) String(octeon) Value(84) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlp) Value(85) Canonical
+Enum(mips_arch_opt_value) String(octeon+) Value(85) Canonical
 
+EnumValue
+Enum(mips_arch_opt_value) String(octeon2) Value(86) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(xlp) Value(87) Canonical
+
Index: gcc/config/mips/micromips.md
===================================================================
--- gcc/config/mips/micromips.md	(revision 0)
+++ gcc/config/mips/micromips.md	(revision 0)
@@ -0,0 +1,125 @@
+;; Copyright (C) 2013 Free Software Foundation, Inc.
+;;
+;; micromips.md   Machine Description for the microMIPS instruction set
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_insn "*store_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "memory_operand")
+	     (match_operand:SI 2 "register_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (true, operands[0])"
+  { return umips_output_save_restore (true, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+(define_insn "*load_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "register_operand")
+	     (match_operand:SI 2 "memory_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (false, operands[0])"
+  { return umips_output_save_restore (false, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For LWP.
+(define_peephole2
+  [(set (match_operand:SI 0 "d_operand" "")
+        (match_operand:SI 1 "non_volatile_mem_operand" ""))
+   (set (match_operand:SI 2 "d_operand" "")
+        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the LWP insn is undefined if placed in a delay slot.
+(define_insn "*lwp"
+  [(parallel [(set (match_operand:SI 0 "d_operand")
+		   (match_operand:SI 1 "non_volatile_mem_operand"))
+	      (set (match_operand:SI 2 "d_operand")
+		   (match_operand:SI 3 "non_volatile_mem_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+{
+  umips_output_load_store_pair (true, operands);
+  return "";
+}
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For SWP.
+(define_peephole2
+  [(set (match_operand:SI 0 "non_volatile_mem_operand" "")
+        (match_operand:SI 1 "d_operand" ""))
+   (set (match_operand:SI 2 "non_volatile_mem_operand" "")
+        (match_operand:SI 3 "d_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the SWP insn is undefined if placed in a delay slot.
+(define_insn "*swp"
+  [(parallel [(set (match_operand:SI 0 "non_volatile_mem_operand")
+		   (match_operand:SI 1 "d_operand"))
+	      (set (match_operand:SI 2 "non_volatile_mem_operand")
+		   (match_operand:SI 3 "d_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+{
+  umips_output_load_store_pair (false, operands);
+  return "";
+}
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For MOVEP.
+(define_peephole2
+  [(set (match_operand:MOVEP1 0 "register_operand" "")
+        (match_operand:MOVEP1 1 "movep_src_operand" ""))
+   (set (match_operand:MOVEP2 2 "register_operand" "")
+        (match_operand:MOVEP2 3 "movep_src_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the MOVEP insn is undefined if placed in a delay slot.
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+		   (match_operand:MOVEP1 1 "movep_src_operand"))
+	      (set (match_operand:MOVEP2 2 "register_operand")
+		   (match_operand:MOVEP2 3 "movep_src_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+{
+  if (REGNO (operands[0]) < REGNO (operands[2]))
+    return "movep\t%0,%2,%z1,%z3";
+  else
+    return "movep\t%2,%0,%z3,%z1";
+}
+  [(set_attr "type" "move")
+   (set_attr "mode" "<MODE>")
+   (set_attr "can_delay" "no")])
Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	(revision 196218)
+++ gcc/config/mips/constraints.md	(working copy)
@@ -232,6 +232,27 @@
    "@internal"
    (match_operand 0 "low_bitmask_operand"))
 
+(define_memory_constraint "ZC"
+  "When compiling microMIPS code, this constraint matches a memory operand
+   whose address is formed from a base register and a 12-bit offset.  These
+   operands can be used for microMIPS instructions such as @code{ll} and
+   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+   equivalent to @code{R}."
+  (and (match_code "mem")
+       (if_then_else
+	 (match_test "TARGET_MICROMIPS")
+	 (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)")
+	 (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "ZD"
+  "When compiling microMIPS code, this constraint matches an address operand
+   that is formed from a base register and a 12-bit offset.  These operands
+   can be used for microMIPS instructions such as @code{prefetch}.  When
+   not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}."
+   (if_then_else (match_test "TARGET_MICROMIPS")
+		 (match_test "umips_12bit_offset_address_p (op, mode)")
+		 (match_test "mips_address_insns (op, mode, false)")))
+
 (define_memory_constraint "ZR"
  "@internal
   An address valid for loading/storing register exclusive"
Index: gcc/config/mips/predicates.md
===================================================================
--- gcc/config/mips/predicates.md	(revision 196218)
+++ gcc/config/mips/predicates.md	(working copy)
@@ -122,6 +122,15 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "movep_src_register"
+  (and (match_code "reg")
+       (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
+	    (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
+
+(define_predicate "movep_src_operand"
+  (ior (match_operand 0 "const_0_operand")
+       (match_operand 0 "movep_src_register")))
+
 (define_predicate "lo_operand"
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
@@ -371,3 +380,8 @@
 (define_predicate "mem_noofs_operand"
   (and (match_code "mem")
        (match_code "reg" "0")))
+
+;; Return 1 if the operand is in non-volatile memory.
+(define_predicate "non_volatile_mem_operand"
+  (and (match_operand 0 "memory_operand")
+       (not (match_test "MEM_VOLATILE_P (op)"))))
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 196218)
+++ gcc/config/mips/mips.md	(working copy)
@@ -342,13 +342,14 @@
 ;; syncloop	memory atomic operation implemented as a sync loop
 ;; nop		no operation
 ;; ghost	an instruction that produces no real code
+;; multimem	microMIPS multiword load and store
 (define_attr "type"
   "unknown,branch,jump,call,load,fpload,fpidxload,store,fpstore,fpidxstore,
    prefetch,prefetchx,condmove,mtc,mfc,mthi,mtlo,mfhi,mflo,const,arith,logical,
    shift,slt,signext,clz,pop,trap,imul,imul3,imul3nc,imadd,idiv,idiv3,move,
    fmove,fadd,fmul,fmadd,fdiv,frdiv,frdiv1,frdiv2,fabs,fneg,fcmp,fcvt,fsqrt,
    frsqrt,frsqrt1,frsqrt2,dspmac,dspmacsat,accext,accmod,dspalu,dspalusat,
-   multi,atomic,syncloop,nop,ghost"
+   multi,atomic,syncloop,nop,ghost,multimem"
   (cond [(eq_attr "jal" "!unset") (const_string "call")
 	 (eq_attr "got" "load") (const_string "load")
 
@@ -413,9 +414,15 @@
 
 ;; Length of instruction in bytes.
 (define_attr "length" ""
-   (cond [;; Direct branch instructions have a range of [-0x20000,0x1fffc],
-	  ;; relative to the address of the delay slot.  If a branch is
-	  ;; outside this range, we have a choice of two sequences.
+   (cond [(and (eq_attr "extended_mips16" "yes")
+	       (match_test "TARGET_MIPS16"))
+	  (const_int 8)
+
+	  ;; Direct microMIPS branch instructions have a range of
+	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
+	  ;; If a branch is outside this range, we have a choice of two
+	  ;; sequences.
+	  ;;
 	  ;; For PIC, an out-of-range branch like:
 	  ;;
 	  ;;	bne	r1,r2,target
@@ -451,10 +458,17 @@
 	  ;; from the shorten_branches reference address.
 	  (and (eq_attr "type" "branch")
 	       (not (match_test "TARGET_MIPS16")))
-	  (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
-		      (le (minus (pc) (match_dup 0)) (const_int 131068)))
+	  (cond [;; Any variant can handle the 17-bit range.
+		 (and (le (minus (match_dup 0) (pc)) (const_int 65532))
+		      (le (minus (pc) (match_dup 0)) (const_int 65534)))
 		   (const_int 4)
 
+		 ;; The 18-bit range is OK other than for microMIPS.
+		 (and (not (match_test "TARGET_MICROMIPS"))
+		      (and (le (minus (match_dup 0) (pc)) (const_int 131064))
+		      	   (le (minus (pc) (match_dup 0)) (const_int 131068))))
+		   (const_int 4)
+
 		 ;; The non-PIC case: branch, first delay slot, and J.
 		 (match_test "TARGET_ABSOLUTE_JUMPS")
 		   (const_int 12)]
@@ -712,6 +726,9 @@
 ;; modes.
 (define_mode_iterator GPR2 [SI (DI "TARGET_64BIT")])
 
+(define_mode_iterator MOVEP1 [SI SF])
+(define_mode_iterator MOVEP2 [SI SF])
+
 ;; This mode iterator allows :HILO to be used as the mode of the
 ;; concatenated HI and LO registers.
 (define_mode_iterator HILO [(DI "!TARGET_64BIT") (TI "TARGET_64BIT")])
@@ -3937,7 +3954,7 @@
 (define_insn "mov_<load>l"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_LOAD_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
   "<load>l\t%0,%2"
@@ -3947,7 +3964,7 @@
 (define_insn "mov_<load>r"
   [(set (match_operand:GPR 0 "register_operand" "=d")
 	(unspec:GPR [(match_operand:BLK 1 "memory_operand" "m")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_operand:GPR 3 "register_operand" "0")]
 		    UNSPEC_LOAD_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[1])"
@@ -3958,7 +3975,7 @@
 (define_insn "mov_<store>l"
   [(set (match_operand:BLK 0 "memory_operand" "=m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")]
+		     (match_operand:QI 2 "memory_operand" "ZC")]
 		    UNSPEC_STORE_LEFT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
   "<store>l\t%z1,%2"
@@ -3968,7 +3985,7 @@
 (define_insn "mov_<store>r"
   [(set (match_operand:BLK 0 "memory_operand" "+m")
 	(unspec:BLK [(match_operand:GPR 1 "reg_or_0_operand" "dJ")
-		     (match_operand:QI 2 "memory_operand" "m")
+		     (match_operand:QI 2 "memory_operand" "ZC")
 		     (match_dup 0)]
 		    UNSPEC_STORE_RIGHT))]
   "!TARGET_MIPS16 && mips_mem_fits_mode_p (<MODE>mode, operands[0])"
@@ -5447,6 +5464,14 @@
 	 (pc)))]
   "!TARGET_MIPS16"
 {
+  /* For a simple BNEZ or BEQZ microMIPS branch.  */
+  if (TARGET_MICROMIPS
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%C1z%:\t%2,%0",
+					   "%*b%N1z%:\t%2,%0");
+
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
@@ -5463,6 +5488,14 @@
 	 (label_ref (match_operand 0 "" ""))))]
   "!TARGET_MIPS16"
 {
+  /* For a simple BNEZ or BEQZ microMIPS branch.  */
+  if (TARGET_MICROMIPS
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+					   "%*b%N0z%:\t%2,%1",
+					   "%*b%C0z%:\t%2,%1");
+
   return mips_output_conditional_branch (insn, operands,
 					 MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
 					 MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
@@ -5766,7 +5799,14 @@
   [(set (pc)
 	(label_ref (match_operand 0)))]
   "!TARGET_MIPS16 && TARGET_ABSOLUTE_JUMPS"
-  { return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/"); }
+{
+  /* Use a branch for microMIPS.  The assembler will choose
+     a 16-bit branch, a 32-bit branch, or a 32-bit jump.  */
+  if (TARGET_MICROMIPS && !TARGET_ABICALLS_PIC2)
+    return "%*b\t%l0%/";
+  else
+    return MIPS_ABSOLUTE_JUMP ("%*j\t%l0%/");
+}
   [(set_attr "type" "jump")])
 
 (define_insn "*jump_pic"
@@ -5829,7 +5869,12 @@
 (define_insn "indirect_jump_<mode>"
   [(set (pc) (match_operand:P 0 "register_operand" "d"))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -5873,7 +5918,12 @@
 	(match_operand:P 0 "register_operand" "d"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type" "jump")
    (set_attr "mode" "none")])
 
@@ -6094,7 +6144,12 @@
   [(any_return)
    (use (match_operand 0 "pmode_register_operand" ""))]
   ""
-  "%*j\t%0%/"
+{
+  if (TARGET_MICROMIPS)
+    return "%*jr%:\t%0";
+  else
+    return "%*j\t%0%/";
+}
   [(set_attr "type"	"jump")
    (set_attr "mode"	"none")])
 
@@ -6350,7 +6405,12 @@
   [(call (mem:SI (match_operand 0 "call_insn_operand" "j,S"))
 	 (match_operand 1 "" ""))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 0, 1); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 0);
+  else
+    return MIPS_CALL ("j", operands, 0, 1);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6371,7 +6431,12 @@
         (call (mem:SI (match_operand 1 "call_insn_operand" "j,S"))
               (match_operand 2 "" "")))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 1);
+  else
+    return MIPS_CALL ("j", operands, 1, 2);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6383,7 +6448,12 @@
 	(call (mem:SI (match_dup 1))
 	      (match_dup 2)))]
   "TARGET_SIBCALLS && SIBLING_CALL_P (insn)"
-  { return MIPS_CALL ("j", operands, 1, 2); }
+{
+  if (TARGET_MICROMIPS)
+    return MICROMIPS_J ("j", operands, 1);
+  else
+    return MIPS_CALL ("j", operands, 1, 2);
+}
   [(set_attr "jal" "indirect,direct")
    (set_attr "jal_macro" "no")])
 
@@ -6629,7 +6699,7 @@
 
 
 (define_insn "prefetch"
-  [(prefetch (match_operand:QI 0 "address_operand" "p")
+  [(prefetch (match_operand:QI 0 "address_operand" "ZD")
 	     (match_operand 1 "const_int_operand" "n")
 	     (match_operand 2 "const_int_operand" "n"))]
   "ISA_HAS_PREFETCH && TARGET_EXPLICIT_RELOCS"
@@ -6922,6 +6992,9 @@
 ; MIPS fixed-point instructions.
 (include "mips-fixed.md")
 
+; microMIPS patterns.
+(include "micromips.md")
+
 ; ST-Microelectronics Loongson-2E/2F-specific patterns.
 (include "loongson.md")
 
Index: gcc/config/mips/mips.opt
===================================================================
--- gcc/config/mips/mips.opt	(revision 196218)
+++ gcc/config/mips/mips.opt	(working copy)
@@ -217,9 +217,13 @@
 Target Report RejectNegative InverseMask(SOFT_FLOAT_ABI, HARD_FLOAT_ABI)
 Allow the use of hardware floating-point ABI and instructions
 
+minterlink-compressed
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+Generate code that is link-compatible with MIPS16 and microMIPS code.
+
 minterlink-mips16
-Target Report Var(TARGET_INTERLINK_MIPS16) Init(0)
-Generate code that can be safely linked with MIPS16 code.
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+An alias for minterlink-compressed provided for backward-compatibility.
 
 mips
 Target RejectNegative Joined ToLower Enum(mips_mips_opt_value) Var(mips_isa_option)
@@ -261,6 +265,10 @@
 Target Report Mask(MEMCPY)
 Don't optimize block moves
 
+mmicromips
+Target Report Mask(MICROMIPS)
+Use microMIPS instructions
+
 mmt
 Target Report Var(TARGET_MT)
 Allow the use of MT instructions
Index: gcc/config/mips/sync.md
===================================================================
--- gcc/config/mips/sync.md	(revision 196218)
+++ gcc/config/mips/sync.md	(working copy)
@@ -59,7 +59,7 @@
 ;; Can be removed in favor of atomic_compare_and_swap below.
 (define_insn "sync_compare_and_swap<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "reg_or_0_operand" "dJ,dJ")
 			      (match_operand:GPR 3 "arith_operand" "I,d")]
@@ -89,7 +89,7 @@
 ;; Helper insn for mips_expand_atomic_qihi.
 (define_insn "compare_and_swap_12"
   [(set (match_operand:SI 0 "register_operand" "=&d,&d")
-	(match_operand:SI 1 "memory_operand" "+R,R"))
+	(match_operand:SI 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d,d")
 			     (match_operand:SI 3 "register_operand" "d,d")
@@ -106,7 +106,7 @@
    (set_attr "sync_insn1_op2" "5")])
 
 (define_insn "sync_add<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 0)
 		     (match_operand:GPR 1 "arith_operand" "I,d"))]
@@ -134,7 +134,7 @@
 
 ;; Helper insn for sync_<optab><mode>
 (define_insn "sync_<optab>_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -174,7 +174,7 @@
 ;; Helper insn for sync_old_<optab><mode>
 (define_insn "sync_old_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -217,7 +217,7 @@
 (define_insn "sync_new_<optab>_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (atomic_hiqi_op:SI (match_dup 0)
@@ -257,7 +257,7 @@
 
 ;; Helper insn for sync_nand<mode>
 (define_insn "sync_nand_12"
-  [(set (match_operand:SI 0 "memory_operand" "+R")
+  [(set (match_operand:SI 0 "memory_operand" "+ZR")
 	(unspec_volatile:SI
           [(match_operand:SI 1 "register_operand" "d")
 	   (match_operand:SI 2 "register_operand" "d")
@@ -296,7 +296,7 @@
 ;; Helper insn for sync_old_nand<mode>
 (define_insn "sync_old_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI
           [(match_operand:SI 2 "register_operand" "d")
@@ -337,7 +337,7 @@
 (define_insn "sync_new_nand_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
 	(unspec_volatile:SI
-          [(match_operand:SI 1 "memory_operand" "+R")
+          [(match_operand:SI 1 "memory_operand" "+ZR")
 	   (match_operand:SI 2 "register_operand" "d")
 	   (match_operand:SI 3 "register_operand" "d")
 	   (match_operand:SI 4 "reg_or_0_operand" "dJ")]
@@ -360,7 +360,7 @@
    (set_attr "sync_insn1_op2" "4")])
 
 (define_insn "sync_sub<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR")
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 0)
 		      (match_operand:GPR 1 "register_operand" "d"))]
@@ -374,7 +374,7 @@
 ;; Can be removed in favor of atomic_fetch_add below.
 (define_insn "sync_old_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(plus:GPR (match_dup 1)
@@ -389,7 +389,7 @@
 
 (define_insn "sync_old_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-	(match_operand:GPR 1 "memory_operand" "+R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(minus:GPR (match_dup 1)
@@ -404,7 +404,7 @@
 
 (define_insn "sync_new_add<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-        (plus:GPR (match_operand:GPR 1 "memory_operand" "+R,R")
+        (plus:GPR (match_operand:GPR 1 "memory_operand" "+ZR,ZR")
 		  (match_operand:GPR 2 "arith_operand" "I,d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -420,7 +420,7 @@
 
 (define_insn "sync_new_sub<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d")
-        (minus:GPR (match_operand:GPR 1 "memory_operand" "+R")
+        (minus:GPR (match_operand:GPR 1 "memory_operand" "+ZR")
 		   (match_operand:GPR 2 "register_operand" "d")))
    (set (match_dup 1)
 	(unspec_volatile:GPR
@@ -435,7 +435,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_<optab><mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 1 "uns_arith_operand" "K,d")
 			      (match_dup 0))]
@@ -448,7 +448,7 @@
 
 (define_insn "sync_old_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -463,7 +463,7 @@
 
 (define_insn "sync_new_<optab><mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR
           [(fetchop_bit:GPR (match_operand:GPR 2 "uns_arith_operand" "K,d")
@@ -478,7 +478,7 @@
    (set_attr "sync_insn1_op2" "2")])
 
 (define_insn "sync_nand<mode>"
-  [(set (match_operand:GPR 0 "memory_operand" "+R,R")
+  [(set (match_operand:GPR 0 "memory_operand" "+ZR,ZR")
 	(unspec_volatile:GPR [(match_operand:GPR 1 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
   "GENERATE_LL_SC"
@@ -490,7 +490,7 @@
 
 (define_insn "sync_old_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
         (unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_OLD_OP))]
@@ -504,7 +504,7 @@
 
 (define_insn "sync_new_nand<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "uns_arith_operand" "K,d")]
 	 UNSPEC_SYNC_NEW_OP))]
@@ -519,7 +519,7 @@
 
 (define_insn "sync_lock_test_and_set<mode>"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(match_operand:GPR 1 "memory_operand" "+R,R"))
+	(match_operand:GPR 1 "memory_operand" "+ZR,ZR"))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
 	 UNSPEC_SYNC_EXCHANGE))]
@@ -546,7 +546,7 @@
 
 (define_insn "test_and_set_12"
   [(set (match_operand:SI 0 "register_operand" "=&d")
-	(match_operand:SI 1 "memory_operand" "+R"))
+	(match_operand:SI 1 "memory_operand" "+ZR"))
    (set (match_dup 1)
 	(unspec_volatile:SI [(match_operand:SI 2 "register_operand" "d")
 			     (match_operand:SI 3 "register_operand" "d")
@@ -576,7 +576,7 @@
 	;; TODO: the obscuring unspec can be relaxed for permissive memory
 	;; models.
 	;; Same applies to other atomic_* patterns.
-	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+R,R")
+	(unspec_volatile:GPR [(match_operand:GPR 2 "memory_operand" "+ZR,ZR")
 			      (match_operand:GPR 3 "reg_or_0_operand" "dJ,dJ")]
 	 UNSPEC_ATOMIC_COMPARE_AND_SWAP))
    (set (match_operand:GPR 1 "register_operand" "=&d,&d")
@@ -629,7 +629,7 @@
 
 (define_insn "atomic_exchange<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_EXCHANGE))
    (set (match_dup 1)
 	(unspec_volatile:GPR [(match_operand:GPR 2 "arith_operand" "I,d")]
@@ -684,7 +684,7 @@
 
 (define_insn "atomic_fetch_add<mode>_llsc"
   [(set (match_operand:GPR 0 "register_operand" "=&d,&d")
-	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+R,R")]
+	(unspec_volatile:GPR [(match_operand:GPR 1 "memory_operand" "+ZR,ZR")]
 	 UNSPEC_ATOMIC_FETCH_OP))
    (set (match_dup 1)
 	(unspec_volatile:GPR
Index: gcc/config/mips/mips-cpus.def
===================================================================
--- gcc/config/mips/mips-cpus.def	(revision 196245)
+++ gcc/config/mips/mips-cpus.def	(working copy)
@@ -92,6 +92,8 @@
 
 /* MIPS32 Release 2 processors.  */
 MIPS_CPU ("m4k", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14kc", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14k", PROCESSOR_M4K, 33, 0)
 MIPS_CPU ("4kec", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kem", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kep", PROCESSOR_4KP, 33, 0)
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 196218)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -350,6 +350,12 @@
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern const char *umips_output_save_restore (bool, rtx);
+extern bool umips_save_restore_pattern_p (bool, rtx);
+extern bool umips_load_store_pair_p (bool, rtx *);
+extern void umips_output_load_store_pair (bool, rtx *);
+extern bool umips_movep_target_p (rtx, rtx);
+extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 196218)
+++ gcc/config/mips/mips.c	(working copy)
@@ -77,6 +77,9 @@
    preserve the maximum stack alignment.  We therefore use a value
    of 0x7ff0 in this case.
 
+   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
+   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
+
    MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
    up to 0x7f8 bytes and can usually save or restore all the registers
    that we need to save or restore.  (Note that we can only use these
@@ -87,8 +90,8 @@
    to save and restore registers, and to allocate and deallocate the top
    part of the frame.  */
 #define MIPS_MAX_FIRST_STACK_STEP					\
-  (!TARGET_MIPS16 ? 0x7ff0						\
-   : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8				\
+  (!TARGET_COMPRESSION ? 0x7ff0						\
+   : TARGET_MICROMIPS || GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8		\
    : TARGET_64BIT ? 0x100 : 0x400)
 
 /* True if INSN is a mips.md pattern or asm statement.  */
@@ -560,8 +563,8 @@
 /* The ambient target flags, excluding MASK_MIPS16.  */
 static int mips_base_target_flags;
 
-/* True if MIPS16 is the default mode.  */
-bool mips_base_mips16;
+/* The default compression mode.  */
+unsigned int mips_base_compression_flags;
 
 /* The ambient values of other global variables.  */
 static int mips_base_schedule_insns; /* flag_schedule_insns */
@@ -674,6 +677,9 @@
      code generation but don't carry other semantics.  */
   { "mips16", 	   0, 0, true,  false, false, NULL, false },
   { "nomips16",    0, 0, true,  false, false, NULL, false },
+  { "micromips",   0, 0, true,  false, false, NULL, false },
+  { "nomicromips", 0, 0, true,  false, false, NULL, false },
+  { "nocompression", 0, 0, true,  false, false, NULL, false },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 0, false, true,  true, NULL, false },
   { "use_shadow_register_set",	0, 0, false, true,  true, NULL, false },
@@ -1167,10 +1173,11 @@
   const char *name;
   hashval_t hash;
   void **slot;
+  bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) != 0;
 
   /* Use the opposite of the command-line setting for anonymous decls.  */
   if (!DECL_NAME (decl))
-    return !mips_base_mips16;
+    return !base_is_mips16;
 
   if (!mflip_mips16_htab)
     mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
@@ -1185,7 +1192,7 @@
       mips16_flipper = !mips16_flipper;
       entry = ggc_alloc_mflip_mips16_entry ();
       entry->name = name;
-      entry->mips16_p = mips16_flipper ? !mips_base_mips16 : mips_base_mips16;
+      entry->mips16_p = mips16_flipper ? !base_is_mips16 : base_is_mips16;
       *slot = entry;
     }
   return entry->mips16_p;
@@ -1207,20 +1214,7 @@
 	  || lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
 }
 
-/* Similar predicates for "mips16"/"nomips16" function attributes.  */
 
-static bool
-mips_mips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
-static bool
-mips_nomips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
 /* Check if the interrupt attribute is set for a function.  */
 
 static bool
@@ -1257,12 +1251,52 @@
 			   TYPE_ATTRIBUTES (type)) != NULL;
 }
 
-/* Return true if function DECL is a MIPS16 function.  Return the ambient
-   setting if DECL is null.  */
+/* Return the set of compression modes that are explicitly required
+   by the attributes in ATTRIBUTES.  */
 
-static bool
-mips_use_mips16_mode_p (tree decl)
+static unsigned int
+mips_get_compress_on_flags (tree attributes)
 {
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("mips16", attributes) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("micromips", attributes) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the set of compression modes that are explicitly forbidden
+   by the attributes in ATTRIBUTES.  */
+
+static unsigned int
+mips_get_compress_off_flags (tree attributes)
+{
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("nocompression", attributes) != NULL)
+    flags |= MASK_MIPS16 | MASK_MICROMIPS;
+
+  if (lookup_attribute ("nomips16", attributes) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("nomicromips", attributes) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the compression mode that should be used for function DECL.
+   Return the ambient setting if DECL is null.  */
+
+static unsigned int
+mips_get_compress_mode (tree decl)
+{
+  unsigned int flags, force_on;
+
+  flags = mips_base_compression_flags;
   if (decl)
     {
       /* Nested functions must use the same frame pointer as their
@@ -1270,14 +1304,38 @@
       tree parent = decl_function_context (decl);
       if (parent)
 	decl = parent;
-      if (mips_mips16_decl_p (decl))
-	return true;
-      if (mips_nomips16_decl_p (decl))
-	return false;
+      force_on = mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+      if (force_on)
+	return force_on;
+      flags &= ~mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
     }
-  return mips_base_mips16;
+  return flags;
 }
 
+/* Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_on_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "mips16";
+  return "micromips";
+}
+
+/* Return the attribute name that forbids MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_off_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "nomips16";
+  if (flags == MASK_MICROMIPS)
+    return "nomicromips";
+  return "nocompression";
+}
+
 /* Implement TARGET_COMP_TYPE_ATTRIBUTES.  */
 
 static int
@@ -1297,37 +1355,50 @@
 mips_insert_attributes (tree decl, tree *attributes)
 {
   const char *name;
-  bool mips16_p, nomips16_p;
+  unsigned int compression_flags, nocompression_flags;
 
   /* Check for "mips16" and "nomips16" attributes.  */
-  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
-  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+  compression_flags = mips_get_compress_on_flags (*attributes);
+  nocompression_flags = mips_get_compress_off_flags (*attributes);
+
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
-      if (mips16_p)
-	error ("%qs attribute only applies to functions", "mips16");
-      if (nomips16_p)
-	error ("%qs attribute only applies to functions", "nomips16");
+      if (nocompression_flags)
+	error ("%qs attribute only applies to functions",
+	       mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags)
+	error ("%qs attribute only applies to functions",
+	       mips_get_compress_on_name (nocompression_flags));
     }
   else
     {
-      mips16_p |= mips_mips16_decl_p (decl);
-      nomips16_p |= mips_nomips16_decl_p (decl);
-      if (mips16_p || nomips16_p)
+      compression_flags |= mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+      nocompression_flags |=
+	mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
+
+      if (compression_flags && nocompression_flags)
+	error ("%qE cannot have both %qs and %qs attributes",
+	       DECL_NAME (decl), mips_get_compress_on_name (compression_flags),
+	       mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags & MASK_MIPS16
+          && compression_flags & MASK_MICROMIPS)
+	error ("%qE cannot have both %qs and %qs attributes",
+	       DECL_NAME (decl), "mips16", "micromips");
+
+      if (TARGET_FLIP_MIPS16
+	  && !DECL_ARTIFICIAL (decl)
+	  && compression_flags == 0
+	  && nocompression_flags == 0)
 	{
-	  /* DECL cannot be simultaneously "mips16" and "nomips16".  */
-	  if (mips16_p && nomips16_p)
-	    error ("%qE cannot have both %<mips16%> and "
-		   "%<nomips16%> attributes",
-		   DECL_NAME (decl));
-	}
-      else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
-	{
 	  /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
 	     "mips16" attribute, arbitrarily pick one.  We must pick the same
 	     setting for duplicate declarations of a function.  */
 	  name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
 	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+	  name = "nomicromips";
+	  *attributes = tree_cons (get_identifier (name), NULL, *attributes);
 	}
     }
 }
@@ -1337,13 +1408,19 @@
 static tree
 mips_merge_decl_attributes (tree olddecl, tree newdecl)
 {
-  /* The decls' "mips16" and "nomips16" attributes must match exactly.  */
-  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
+  unsigned int diff;
+
+  diff = (mips_get_compress_on_flags (DECL_ATTRIBUTES (olddecl))
+	  ^ mips_get_compress_on_flags (DECL_ATTRIBUTES (newdecl)));
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "mips16");
-  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
+	   DECL_NAME (newdecl), mips_get_compress_on_name (diff));
+
+  diff = (mips_get_compress_off_flags (DECL_ATTRIBUTES (olddecl))
+	  ^ mips_get_compress_off_flags (DECL_ATTRIBUTES (newdecl)));
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-	   DECL_NAME (newdecl), "nomips16");
+	   DECL_NAME (newdecl), mips_get_compress_off_name (diff));
 
   return merge_attributes (DECL_ATTRIBUTES (olddecl),
 			   DECL_ATTRIBUTES (newdecl));
@@ -1550,7 +1627,7 @@
   return (GET_CODE (x) == SYMBOL_REF
 	  && SYMBOL_REF_LOCAL_P (x)
 	  && !SYMBOL_REF_EXTERNAL_P (x)
-	  && mips_use_mips16_mode_p (SYMBOL_REF_DECL (x)));
+	  && (mips_get_compress_mode (SYMBOL_REF_DECL (x)) & MASK_MIPS16));
 }
 
 /* Return true if SYMBOL_REF X binds locally.  */
@@ -2300,6 +2377,20 @@
   return 0;
 }
 
+/* Return true if X is a legitimate address with a 12-bit offset.
+   MODE is the mode of the value being accessed.  */
+
+bool
+umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && CONST_INT_P (addr.offset)
+	  && UMIPS_12BIT_OFFSET_P (INTVAL (addr.offset)));
+}
+
 /* Return the number of instructions needed to load constant X.
    Return 0 if X isn't a valid constant.  */
 
@@ -6097,6 +6188,13 @@
   else
     fprintf (asm_out_file, "\t.set\tnomips16\n");
 
+  if (TARGET_MICROMIPS)
+    fprintf (asm_out_file, "\t.set\tmicromips\n");
+#ifdef HAVE_GAS_MICROMIPS
+  else
+    fprintf (asm_out_file, "\t.set\tnomicromips\n");
+#endif
+
   if (!flag_inhibit_size_directive)
     {
       fputs ("\t.ent\t", asm_out_file);
@@ -6903,6 +7001,37 @@
     mips_restore_gp_from_cprestore_slot (gen_rtx_REG (Pmode, GP_ARG_FIRST + 2));
 }
 
+/* Return true if a call to DECL may need to use JALX.  */
+
+static bool
+mips_call_may_need_jalx_p (tree decl)
+{
+  /* If the current translation unit would use a different mode for DECL,
+     assume that the call needs JALX.  */
+  if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
+    return true;
+
+  /* mips_get_compress_mode is always accurate for locally-binding
+     functions in the current translation unit.  */
+  if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
+    return false;
+
+  /* When -minterlink-compressed is in effect, assume that functions
+     could use a different encoding mode unless an attribute explicitly
+     tells us otherwise.  */
+  if (TARGET_INTERLINK_COMPRESSED)
+    {
+      if (!TARGET_COMPRESSION
+	  && mips_get_compress_off_flags (DECL_ATTRIBUTES (decl)) ==0)
+	return true;
+      if (TARGET_COMPRESSION
+	  && mips_get_compress_on_flags (DECL_ATTRIBUTES (decl)) == 0)
+	return true;
+    }
+
+  return false;
+}
+
 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
 
 static bool
@@ -6916,25 +7045,13 @@
   if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
     return false;
 
-  /* We can't do a sibcall if the called function is a MIPS16 function
-     because there is no direct "jx" instruction equivalent to "jalx" to
-     switch the ISA mode.  We only care about cases where the sibling
-     and normal calls would both be direct.  */
+  /* Direct Js are only possible to functions that use the same ISA encoding.
+     There is no JX counterpoart of JALX.  */
   if (decl
-      && mips_use_mips16_mode_p (decl)
-      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
+      && mips_call_may_need_jalx_p (decl))
     return false;
 
-  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
-     functions could be MIPS16 ones unless an attribute explicitly tells
-     us otherwise.  */
-  if (TARGET_INTERLINK_MIPS16
-      && decl
-      && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
-      && !mips_nomips16_decl_p (decl)
-      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
-    return false;
-
   /* Otherwise OK.  */
   return true;
 }
@@ -7798,6 +7915,9 @@
    '^'	Print the name of the pic call-through register (t9 or $25).
    '+'	Print the name of the gp register (usually gp or $28).
    '$'	Print the name of the stack pointer register (sp or $29).
+   ':'  Print "c" to use the compact version if the delay slot is a nop.
+   '!'  Print "s" to use the short version if the delay slot contains a
+	16-bit instruction.
 
    See also mips_init_print_operand_pucnt.  */
 
@@ -7881,6 +8001,20 @@
       fputs (reg_names[STACK_POINTER_REGNUM], file);
       break;
 
+    case ':':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+	 use the compact version for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('c', file);
+      break;
+
+    case '!':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+	 a 16-bit delay slot for microMIPS.  */
+      if (final_sequence == 0)
+	putc ('s', file);
+      break;
+
     default:
       gcc_unreachable ();
       break;
@@ -7894,7 +8028,7 @@
 {
   const char *p;
 
-  for (p = "()[]<>*#/?~.@^+$"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$:!"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -10236,6 +10370,126 @@
       }
 }
 
+/* Save register REG to MEM.  Make the instruction frame-related.  */
+
+static void
+mips_save_reg (rtx reg, rtx mem)
+{
+  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
+    {
+      rtx x1, x2;
+
+      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
+
+      x1 = mips_frame_set (mips_subword (mem, false),
+			   mips_subword (reg, false));
+      x2 = mips_frame_set (mips_subword (mem, true),
+			   mips_subword (reg, true));
+      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
+    }
+  else
+    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
+}
+
+/* Capture the register combinations that are allowed in a SWM or LWM
+   instruction.  The entries are ordered by number of registers set in
+   the mask.  We also ignore the single register encodings because a
+   normal SW/LW is preferred.  */
+
+static const unsigned int umips_swm_mask[17] = {
+  0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
+  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,
+  0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
+  0x000f0000, 0x80030000, 0x00070000, 0x80010000,
+  0x00030000
+};
+
+static const unsigned int umips_swm_encoding[17] = {
+  25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2
+};
+
+/* Try to use a microMIPS LWM or SWM instruction to save or restore
+   as many GPRs in *MASK as possible.  *OFFSET is the offset from the
+   stack pointer of the topmost save slot.
+
+   Remove from *MASK all registers that were handled using LWM and SWM.
+   Update *OFFSET so that it points to the first unused save slot.  */
+
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+			  unsigned *mask, HOST_WIDE_INT *offset)
+{
+  int nregs;
+  unsigned int i, j;
+  rtx pattern, set, reg, mem;
+  HOST_WIDE_INT this_offset;
+  rtx this_base;
+
+  /* Try matching $16 to $31 (s0 to ra).  */
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if ((*mask & 0xffff0000) == umips_swm_mask[i])
+      break;
+
+  if (i == ARRAY_SIZE (umips_swm_mask))
+    return false;
+
+  /* Get the offset of the lowest save slot.  */
+  nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
+  this_offset = *offset - UNITS_PER_WORD * (nregs - 1);
+
+  /* LWM/SWM can only support offsets from -2048 to 2047.  */
+  if (!UMIPS_12BIT_OFFSET_P (this_offset))
+    return false;
+
+  /* Create the final PARALLEL.  */
+  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs));
+  this_base = stack_pointer_rtx;
+
+  /* For registers $16-$23 and $30.  */
+  for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
+    {
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      unsigned int regno = (j != 8) ? 16 + j : 30;
+      *mask &= ~(1 << regno);
+      reg = gen_rtx_REG (SImode, regno);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  /* For register $31.  */
+  if (umips_swm_encoding[i] >> 4)
+    {
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      *mask &= ~(1 << 31);
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      reg = gen_rtx_REG (SImode, 31);
+      if (fn == mips_save_reg)
+	set = mips_frame_set (mem, reg);
+      else
+	{
+	  set = gen_rtx_SET (VOIDmode, reg, mem);
+	  mips_add_cfa_restore (reg);
+	}
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  pattern = emit_insn (pattern);
+  if (fn == mips_save_reg)
+    RTX_FRAME_RELATED_P (pattern) = 1;
+
+  /* Adjust the last offset.  */
+  *offset -= UNITS_PER_WORD * nregs;
+
+  return true;
+}
+
 /* Call FN for each register that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -10245,16 +10499,23 @@
 				 mips_save_restore_fn fn)
 {
   enum machine_mode fpr_mode;
+  int regno;
+  const struct mips_frame_info *frame = &cfun->machine->frame;
   HOST_WIDE_INT offset;
-  int regno;
+  unsigned int mask;
 
   /* Save registers starting from high to low.  The debuggers prefer at least
      the return register be stored at func+4, and also it allows us not to
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
-  offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+  offset = frame->gp_sp_offset - sp_offset;
+  mask = frame->mask;
+
+  if (TARGET_MICROMIPS)
+    umips_build_save_restore (fn, &mask, &offset);
+
   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
-    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+    if (BITSET_P (mask, regno - GP_REG_FIRST))
       {
 	/* Record the ra offset for use by mips_function_profiler.  */
 	if (regno == RETURN_ADDR_REGNUM)
@@ -10501,27 +10762,7 @@
   emit_clobber (gen_frame_mem (BLKmode, stack_pointer_rtx));
 }
 
-/* Save register REG to MEM.  Make the instruction frame-related.  */
 
-static void
-mips_save_reg (rtx reg, rtx mem)
-{
-  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
-    {
-      rtx x1, x2;
-
-      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
-
-      x1 = mips_frame_set (mips_subword (mem, false),
-			   mips_subword (reg, false));
-      x2 = mips_frame_set (mips_subword (mem, true),
-			   mips_subword (reg, true));
-      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
-    }
-  else
-    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
-}
-
 /* The __gnu_local_gp symbol.  */
 
 static GTY(()) rtx mips_gnu_local_gp;
@@ -11239,7 +11480,7 @@
 	  mips_emit_move (gen_rtx_REG (word_mode, K0_REG_NUM), mem);
 	  offset -= UNITS_PER_WORD;
 
-	  /* If we don't use shoadow register set, we need to update SP.  */
+	  /* If we don't use shadow register set, we need to update SP.  */
 	  if (!cfun->machine->use_shadow_register_set_p)
 	    mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
 	  else
@@ -11254,6 +11495,7 @@
 	/* Deallocate the final bit of the frame.  */
 	mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
     }
+
   gcc_assert (!mips_epilogue.cfa_restores);
 
   /* Add in the __builtin_eh_return stack adjustment.  We need to
@@ -16211,17 +16453,19 @@
   reload_completed = 0;
 }
 \f
-/* The last argument passed to mips_set_mips16_mode, or negative if the
-   function hasn't been called yet.  */
-static int was_mips16_p = -1;
 
-/* Set up the target-dependent global state so that it matches the
-   current function's ISA mode.  */
+/* The last argument passed to mips_set_compression_mode,
+   or negative if the function hasn't been called yet.  */
+static unsigned int old_compression_mode = -1;
 
+/* Set up the target-dependent global state for ISA mode COMPRESSION_MODE,
+   which is either MASK_MIPS16 or MASK_MICROMIPS.  */
+
 static void
-mips_set_mips16_mode (int mips16_p)
+mips_set_compression_mode (unsigned int compression_mode)
 {
-  if (mips16_p == was_mips16_p)
+
+  if (compression_mode == old_compression_mode)
     return;
 
   /* Restore base settings of various flags.  */
@@ -16232,8 +16476,10 @@
   align_loops = mips_base_align_loops;
   align_jumps = mips_base_align_jumps;
   align_functions = mips_base_align_functions;
+  target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
+  target_flags |= compression_mode;
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       /* Switch to MIPS16 mode.  */
       target_flags |= MASK_MIPS16;
@@ -16287,9 +16533,12 @@
     }
   else
     {
-      /* Switch to normal (non-MIPS16) mode.  */
-      target_flags &= ~MASK_MIPS16;
+      /* Switch to microMIPS or the standard encoding.  */
 
+      if (TARGET_MICROMIPS)
+	/* Avoid branch likely.  */
+	target_flags &= ~MASK_BRANCHLIKELY;
+
       /* Provide default values for align_* for 64-bit targets.  */
       if (TARGET_64BIT)
 	{
@@ -16310,7 +16559,7 @@
   /* (Re)initialize MIPS target internals for new ISA.  */
   mips_init_relocs ();
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       if (!mips16_globals)
 	mips16_globals = save_target_globals_default_opts ();
@@ -16320,16 +16569,17 @@
   else
     restore_target_globals (&default_target_globals);
 
-  was_mips16_p = mips16_p;
+  old_compression_mode = compression_mode;
 }
 
 /* Implement TARGET_SET_CURRENT_FUNCTION.  Decide whether the current
-   function should use the MIPS16 ISA and switch modes accordingly.  */
+   function should use the MIPS16 or microMIPS ISA and switch modes
+   accordingly.  */
 
 static void
 mips_set_current_function (tree fndecl)
 {
-  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+  mips_set_compression_mode (mips_get_compress_mode (fndecl));
 }
 \f
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -16437,14 +16687,19 @@
   if (global_options_set.x_mips_isa_option)
     mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
 
-  /* Process flags as though we were generating non-MIPS16 code.  */
-  mips_base_mips16 = TARGET_MIPS16;
-  target_flags &= ~MASK_MIPS16;
-
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
+  /* MIPS16 and microMIPS cannot coexist.  */
+  if (TARGET_MICROMIPS && TARGET_MIPS16)
+    error ("unsupported combination: %s", "-mips16 -mmicromips");
+
+  /* Save the base compression state and process flags as though we
+     were generating uncompressed code.  */
+  mips_base_compression_flags = TARGET_COMPRESSION;
+  target_flags &= ~TARGET_COMPRESSION;
+
   /* -mno-float overrides -mhard-float and -msoft-float.  */
   if (TARGET_NO_FLOAT)
     {
@@ -16453,7 +16708,7 @@
     }
 
   if (TARGET_FLIP_MIPS16)
-    TARGET_INTERLINK_MIPS16 = 1;
+    TARGET_INTERLINK_COMPRESSED = 1;
 
   /* Set the small data limit.  */
   mips_small_data_threshold = (global_options_set.x_g_switch_value
@@ -16826,9 +17081,9 @@
 
   /* Now select the ISA mode.
 
-     Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
-     MIPS16 mode afterwards if need be.  */
-  mips_set_mips16_mode (false);
+     Do all CPP-sensitive stuff in uncompressed mode; we'll switch modes
+     later if required.  */
+  mips_set_compression_mode (0);
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -17088,6 +17343,277 @@
       return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
     }
 }
+
+/* Return true if PATTERN matches the kind of instruction generated by
+   umips_build_save_restore.  SAVE_P is true for store.  */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+  int n;
+  unsigned int i;
+  HOST_WIDE_INT first_offset = 0;
+  rtx first_base = 0;
+  unsigned int regmask = 0;
+
+  for (n = 0; n < XVECLEN (pattern, 0); n++)
+    {
+      rtx set, reg, mem, this_base;
+      HOST_WIDE_INT this_offset;
+
+      /* Check that we have a SET.  */
+      set = XVECEXP (pattern, 0, n);
+      if (GET_CODE (set) != SET)
+	return false;
+
+      /* Check that the SET is a load (if restoring) or a store
+	 (if saving).  */
+      mem = save_p ? SET_DEST (set) : SET_SRC (set);
+      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
+	return false;
+
+      /* Check that the address is the sum of base and a possibly-zero
+	 constant offset.  Determine if the offset is in range.  */
+      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+      if (!REG_P (this_base))
+	return false;
+
+      if (n == 0)
+	{
+	  if (!UMIPS_12BIT_OFFSET_P (this_offset))
+	    return false;
+	  first_base = this_base;
+	  first_offset = this_offset;
+	}
+      else
+	{
+	  /* Check that the save slots are consecutive.  */
+	  if (REGNO (this_base) != REGNO (first_base)
+	      || this_offset != first_offset + UNITS_PER_WORD * n)
+	    return false;
+	}
+
+      /* Check that SET's other operand is a register.  */
+      reg = save_p ? SET_SRC (set) : SET_DEST (set);
+      if (!REG_P (reg))
+	return false;
+
+      regmask |= 1 << REGNO (reg);
+    }
+
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if (regmask == umips_swm_mask[i])
+      return true;
+
+  return false;
+}
+
+/* Return the assembly instruction for microMIPS LWM or SWM.
+   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+  static char buffer[300];
+  char *s;
+  int n;
+  HOST_WIDE_INT offset;
+  rtx base, mem, set, last_set, last_reg;
+
+  /* Parse the pattern.  */
+  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
+
+  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
+  s += strlen (s);
+  n = XVECLEN (pattern, 0);
+
+  set = XVECEXP (pattern, 0, 0);
+  mem = save_p ? SET_DEST (set) : SET_SRC (set);
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+
+  last_set = XVECEXP (pattern, 0, n - 1);
+  last_reg = save_p ? SET_SRC (last_set) : SET_DEST (last_set);
+
+  if (REGNO (last_reg) == 31)
+    n--;
+
+  gcc_assert (n <= 9);
+  if (n == 0)
+    ;
+  else if (n == 1)
+    s += sprintf (s, "%s,", reg_names[16]);
+  else if (n < 9)
+    s += sprintf (s, "%s-%s,", reg_names[16], reg_names[15 + n]);
+  else if (n == 9)
+    s += sprintf (s, "%s-%s,%s,", reg_names[16], reg_names[23],
+		  reg_names[30]);
+
+  if (REGNO (last_reg) == 31)
+    s += sprintf (s, "%s,", reg_names[31]);
+
+  s += sprintf (s, "%d(%s)", (int)offset, reg_names[REGNO (base)]);
+  return buffer;
+}
+
+/* Return true if MEM1 and MEM2 use the same base register, and the
+   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
+   register into (from) which the contents of MEM1 will be loaded
+   (stored), depending on the value of LOAD_P.
+   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
+
+static bool
+umips_load_store_pair_p_1 (bool load_p, bool swap_p,
+			   rtx first_reg, rtx mem1, rtx mem2)
+{
+  rtx base1, base2;
+  HOST_WIDE_INT offset1, offset2;
+
+  if (!MEM_P (mem1) || !MEM_P (mem2))
+    return false;
+
+  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
+  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
+
+  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
+    return false;
+
+  /* Avoid invalid load pair instructions.  */
+  if (load_p && REGNO (first_reg) == REGNO (base1))
+    return false;
+
+  /* We must avoid this case for anti-dependence.
+     Ex:  lw $3, 4($3)
+          lw $2, 0($3)
+     first_reg is $2, but the base is $3.  */
+  if (load_p
+      && swap_p
+      && REGNO (first_reg) + 1 == REGNO (base1))
+    return false;
+
+  if (offset2 != offset1 + 4)
+    return false;
+
+  if (!UMIPS_12BIT_OFFSET_P (offset1))
+    return false;
+
+  return true;
+}
+
+/* OPERANDS describes the operands to a pair of SETs, in the order
+   dest1, src1, dest2, src2.  Return true if the operands can be used
+   in an LWP or SWP instruction; LOAD_P says which.  */
+
+bool
+umips_load_store_pair_p (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    return umips_load_store_pair_p_1 (load_p, false, reg1, mem1, mem2);
+
+  if (REGNO (reg1) == REGNO (reg2) + 1)
+    return umips_load_store_pair_p_1 (load_p, true, reg2, mem2, mem1);
+
+  return false;
+}
+
+/* Return the assembly instruction for a microMIPS LWP or SWP in which
+   the first register is REG and the first memory slot is MEM.
+   LOAD_P is true for LWP.  */
+
+static void
+umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
+{
+  rtx ops[] = {reg, mem};
+
+  if (load_p)
+    output_asm_insn ("lwp\t%0,%1", ops);
+  else
+    output_asm_insn ("swp\t%0,%1", ops);
+}
+
+/* Output the assembly instruction for a microMIPS LWP or SWP instruction.
+   LOAD_P and OPERANDS are as for umips_load_store_pair_p.  */
+
+void
+umips_output_load_store_pair (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    {
+      umips_output_load_store_pair_1 (load_p, reg1, mem1);
+      return;
+    }
+
+  gcc_assert (REGNO (reg1) == REGNO (reg2) + 1);
+  umips_output_load_store_pair_1 (load_p, reg2, mem2);
+}
+
+/* Return true if REG1 and REG2 match the criteria for a movep insn.  */
+
+bool
+umips_movep_target_p (rtx reg1, rtx reg2)
+{
+  int regno1, regno2, pair;
+  unsigned int i;
+  static const int match[8] = {
+    0x00000060, /* 5, 6 */
+    0x000000a0, /* 5, 7 */
+    0x000000c0, /* 6, 7 */
+    0x00200010, /* 4, 21 */
+    0x00400010, /* 4, 22 */
+    0x00000030, /* 4, 5 */
+    0x00000050, /* 4, 6 */
+    0x00000090  /* 4, 7 */
+  };
+
+  if (!REG_P (reg1) || !REG_P (reg2))
+    return false;
+
+  regno1 = REGNO (reg1);
+  regno2 = REGNO (reg2);
+
+  if (!GP_REG_P (regno1) || !GP_REG_P (regno2))
+    return false;
+
+  pair = (1 << regno1) | (1 << regno2);
+
+  for (i = 0; i < ARRAY_SIZE (match); i++)
+    if (pair == match[i])
+      return true;
+
+  return false;
+}
 \f
 /* Return the size in bytes of the trampoline code, padded to
    TRAMPOLINE_ALIGNMENT bits.  The static chain pointer and target
@@ -17342,7 +17868,7 @@
      It therefore seems best to switch back to non-MIPS16 mode at
      save time, and to ensure that mips16_globals remains null after
      a PCH load.  */
-  mips_set_mips16_mode (false);
+  mips_set_compression_mode (0);
   mips16_globals = 0;
 }
 \f
Index: gcc/config/mips/mips.h
===================================================================
--- gcc/config/mips/mips.h	(revision 196218)
+++ gcc/config/mips/mips.h	(working copy)
@@ -174,6 +174,9 @@
 #define ISA_HAS_DSP_MULT ISA_HAS_DSPR2
 #endif
 
+/* The ISA compression flags that are currently in effect.  */
+#define TARGET_COMPRESSION (target_flags & (MASK_MIPS16 | MASK_MICROMIPS))
+
 /* Generate mips16 code */
 #define TARGET_MIPS16		((target_flags & MASK_MIPS16) != 0)
 /* Generate mips16e code. Default 16bit ASE for mips32* and mips64* */
@@ -374,7 +377,7 @@
       else								\
 	builtin_define ("__mips_fpr=32");				\
 									\
-      if (mips_base_mips16)						\
+      if (mips_base_compression_flags & MASK_MIPS16)			\
 	builtin_define ("__mips16");					\
 									\
       if (TARGET_MIPS3D)						\
@@ -383,6 +386,9 @@
       if (TARGET_SMARTMIPS)						\
 	builtin_define ("__mips_smartmips");				\
 									\
+      if (mips_base_compression_flags & MASK_MICROMIPS)			\
+	builtin_define ("__mips_micromips");				\
+									\
       if (TARGET_MCU)							\
 	builtin_define ("__mips_mcu");					\
 									\
@@ -702,7 +708,7 @@
        |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
      %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
      %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
-       |march=34k*|march=74k*|march=1004k*: -mips32r2} \
+       |march=34k*|march=74k*|march=m14k*|march=1004k*: -mips32r2} \
      %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
        |march=xlr|march=loongson3a: -mips64} \
      %{march=mips64r2|march=octeon|march=xlp: -mips64r2} \
@@ -716,7 +722,7 @@
   "%{mhard-float|msoft-float|mno-float|march=mips*:; \
      march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
      |march=34kc|march=34kn|march=74kc|march=1004kc|march=5kc \
-     |march=octeon|march=xlr: -msoft-float;		  \
+     |march=m14k*|march=octeon|march=xlr: -msoft-float;		  \
      march=*: -mhard-float}"
 
 /* A spec condition that matches 32-bit options.  It only works if
@@ -989,7 +995,8 @@
 				     || ISA_MIPS64R2))
 
 /* ISA has lwxs instruction (load w/scaled index address.  */
-#define ISA_HAS_LWXS		(TARGET_SMARTMIPS && !TARGET_MIPS16)
+#define ISA_HAS_LWXS		((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
+				 && !TARGET_MIPS16)
 
 /* ISA has lbx, lbux, lhx, lhx, lhux, lwx, lwux, or ldx instruction. */
 #define ISA_HAS_LBX		(TARGET_OCTEON2)
@@ -1012,7 +1019,8 @@
    and "addiu $4,$4,1".  */
 #define ISA_HAS_LOAD_DELAY	(ISA_MIPS1				\
 				 && !TARGET_MIPS3900			\
-				 && !TARGET_MIPS16)
+				 && !TARGET_MIPS16			\
+				 && !TARGET_MICROMIPS)
 
 /* Likewise mtc1 and mfc1.  */
 #define ISA_HAS_XFER_DELAY	(mips_isa <= 3			\
@@ -1123,6 +1131,7 @@
 %{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
 %{mips32*} %{mips64*} \
 %{mips16} %{mno-mips16:-no-mips16} \
+%{mmicromips} %{mno-micromips} \
 %{mips3d} %{mno-mips3d:-no-mips3d} \
 %{mdmx} %{mno-mdmx:-no-mdmx} \
 %{mdsp} %{mno-dsp} \
@@ -1672,6 +1681,8 @@
   ((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define M16_REG_P(REGNO) \
   (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 16 || (REGNO) == 17)
+#define M16STORE_REG_P(REGNO) \
+  (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 0 || (REGNO) == 17)
 #define FP_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
 #define MD_REG_P(REGNO) \
@@ -2034,6 +2045,7 @@
 #define SMALL_INT(X) SMALL_OPERAND (INTVAL (X))
 #define SMALL_INT_UNSIGNED(X) SMALL_OPERAND_UNSIGNED (INTVAL (X))
 #define LUI_INT(X) LUI_OPERAND (INTVAL (X))
+#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))
 
 /* The HI and LO registers can only be reloaded via the general
    registers.  Condition code registers can only be loaded to the
@@ -2452,17 +2464,32 @@
    all calls should use assembly macros.  Otherwise, all indirect
    calls should use "jr" or "jalr"; we will arrange to restore $gp
    afterwards if necessary.  Finally, we can only generate direct
-   calls for -mabicalls by temporarily switching to non-PIC mode.  */
+   calls for -mabicalls by temporarily switching to non-PIC mode.
+
+   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+   instruction is in the delay slot of jal(r).  */
 #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)	\
   (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
    ? "%*" INSN "\t%" #TARGET_OPNO "%/"				\
-   : (REG_P (OPERANDS[TARGET_OPNO])				\
-      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))	\
-   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
-      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
    : REG_P (OPERANDS[TARGET_OPNO])				\
-   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"				\
+   ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)		\
+      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"		\
+	 "1:\t" INSN "r\t%" #TARGET_OPNO "%/")			\
+      : TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED	\
+      ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"			\
+      : "%*" INSN "r\t%" #TARGET_OPNO "%/")			\
    : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
+
+/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
+   "jrc" when nop is in the delay slot of "jr".  */
+
+#define MICROMIPS_J(INSN, OPERANDS, OPNO)			\
+  (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS			\
+   ? "%*j\t%" #OPNO "%/"					\
+   : REG_P (OPERANDS[OPNO])					\
+   ? "%*jr%:\t%" #OPNO						\
+   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #OPNO "%/"))
+
 \f
 /* Control the assembler format that we output.  */
 
@@ -2877,7 +2904,7 @@
 extern int mips_isa;			/* architectural level */
 extern const struct mips_cpu_info *mips_arch_info;
 extern const struct mips_cpu_info *mips_tune_info;
-extern bool mips_base_mips16;
+extern unsigned int mips_base_compression_flags;
 extern GTY(()) struct target_globals *mips16_globals;
 #endif
 
Index: gcc/config/mips/t-sde
===================================================================
--- gcc/config/mips/t-sde	(revision 196218)
+++ gcc/config/mips/t-sde	(working copy)
@@ -16,8 +16,8 @@
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
-MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16 msoft-float/mfp64 mcode-readable=no
-MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 sof f64 spram
+MULTILIB_OPTIONS = EL/EB mips32/mips32r2/mips64/mips64r2 mips16/mmicromips msoft-float/mfp64 mcode-readable=no
+MULTILIB_DIRNAMES = el eb mips32 mips32r2 mips64 mips64r2 mips16 micromips sof f64 spram
 MULTILIB_MATCHES = EL=mel EB=meb
 
 # The -mfp64 option is only valid in conjunction with -mips32r2.

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-24 23:52                       ` Moore, Catherine
@ 2013-02-25  9:41                         ` Richard Sandiford
  2013-02-25 13:55                           ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-02-25  9:41 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> HI Richard, 
> The base patch is now committed.  The final patch, including your final
> edits is attached.  I will be posting the optimization pieces later this
> week.

Sorry, when I said that it was ok for 4.9, I meant that it should wait
until 4.8 had branched.  As I say, I think the patch is too invasive
for 4.8 at this (regression fixes only) stage.

Please revert the patch for now and reapply it once 4.9 starts.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-02-25  9:41                         ` Richard Sandiford
@ 2013-02-25 13:55                           ` Moore, Catherine
  0 siblings, 0 replies; 41+ messages in thread
From: Moore, Catherine @ 2013-02-25 13:55 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Monday, February 25, 2013 4:42 AM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> > HI Richard,
> > The base patch is now committed.  The final patch, including your
> > final edits is attached.  I will be posting the optimization pieces
> > later this week.
> 
> Sorry, when I said that it was ok for 4.9, I meant that it should wait until 4.8
> had branched.  As I say, I think the patch is too invasive for 4.8 at this
> (regression fixes only) stage.
> 
> Please revert the patch for now and reapply it once 4.9 starts.
> 

Now reverted.  I thought that we had branched.
Catherine

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2012-07-20  0:46   ` Richard Sandiford
  2013-01-22 20:23     ` Moore, Catherine
@ 2013-03-04 19:43     ` Moore, Catherine
  2013-03-04 20:54       ` Richard Sandiford
  1 sibling, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-04 19:43 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Moore, Catherine, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 2810 bytes --]

Hi Richard,
I've attached an example patch for the add pattern that tries to identify the short microMIPS variants.  In your last review, you mentioned that you would like to see the register requirements modeled in the patterns.  Do you have any comments on the approach that I'm taking?  Thanks,
Catherine

> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Thursday, July 19, 2012 8:46 PM
> -------------------------------------------------------------------------
> +(define_attr "umips_arith" "no, yes"
> +  (if_then_else (and (eq_attr "type" "arith")
> +		     (not (eq_attr "mode" "DI"))
> +		     (match_test "umips_three_reg_match0 (PATTERN
> (insn))"))
> +  (const_string "yes")
> +  (const_string "no")))
> -------------------------------------------------------------------------
> 
> Well, I suppose this OK for now, but it seems odd to be hiding the difference
> from the main patterns.  Don't we want IRA+reload to optimise for this
> where possible?  Or does that produce bad results?
> More below.
> 
> Rather than define lots of attributes, please just use [(cond ...)] to set the
> default directly:
> 
> (define_attr "umips_short_insn" "no, yes"
>   (cond [(and (eq_attr "type" "arith")
> 	      (not (eq_attr "mode" "DI"))
>  	      (match_test "umips_three_reg_match0 (PATTERN (insn))"))
> 	 (const_string "yes")
> 
> 	 ...]
> 	(const_string "no")))
> 


> -------------------------------------------------------------------------
> +/* Return true if the insn has three micromips register operands.  */
> +int
> +umips_three_reg (rtx insn)
> +{
> +   rtx op0 = XEXP (insn, 0);
> +   rtx op1 = XEXP (insn, 1);
> +   rtx op2 = XEXP (insn, 2);
> +
> +   return (op0 != NULL_RTX
> +           && op1 != NULL_RTX
> +	   && op2 != NULL_RTX
> +	   && REG_P (op0)
> +	   && M16_REG_P (REGNO (op0))
> +	   && REG_P (op1)
> +	   && M16_REG_P (REGNO (op1))
> +	   && REG_P (op2)
> +	   && M16_REG_P (REGNO (op2)));
> +}
> -------------------------------------------------------------------------
> 
> This doesn't look right.  You pass in a complete PATTERN,
> so XEXP (insn, 1) will typically be the SET_SRC (such as a PLUS)
> and XEXP (insn, 2) usually isn't valid.
> 
> I think --enable-checking=yes,rtl would have tripped over the op2
> extraction and flagged it as a problem.  Could you use that option
> when testing the updated patch?
> 
> Same problem with the other predicates.
> 
> Please make the predicates return bool rather than int.
> 
> Like I said above, I'd really prefer to see the register requirements
> modelled in the patterns directly.  You could use the "enabled" to
> prevent the new alternatives from being used by non-MIPS16 code.
> 
> 
> Richard

[-- Attachment #2: short-delay.cl --]
[-- Type: application/octet-stream, Size: 779 bytes --]

2012-03-04  Catherine Moore  <clm@codesourcery.com>

	* constraints.md (u, w): New register constraints.
	* predicates.md (umips_addius5_imm): New predicate.
	(umips_addiusp_imm): Likewise.
	* mips.md (compression): New attribute.
	(enabled): New attribute.
	(length): Update for microMIPS.
	(*add<mode>3): Add microMIPS alternatives.
	* mips-protos.h (umips_match_reg_p): New prototype.
	(umips_addiur1sp_imm_p): New prototype.
	(umips_addiur2_imm_p): New prototype.
	* mips.c (mips_regno_to_class): Initialize R29 to STACK_POINTER_REG.
	(umips_match_reg_p): New function.
	(umips_addiur1sp_imm_p): New function.
	(umips_addiur2_imm_p): New function.
	* mips.h (regclass): Add STACK_POINTER_REG.
	(reg_class_names): Likewise.
	(REG_CLASS_CONTENTS): Likewise.

[-- Attachment #3: short-delay.patch --]
[-- Type: application/octet-stream, Size: 7781 bytes --]

Index: constraints.md
===================================================================
--- constraints.md	(revision 196341)
+++ constraints.md	(working copy)
@@ -43,6 +43,12 @@
 (define_register_constraint "b" "ALL_REGS"
   "@internal")
 
+(define_register_constraint "u" "M16_REGS"
+  "@internal")
+
+(define_register_constraint "w" "STACK_POINTER_REG"
+  "@internal")
+
 ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
 ;; for details.
 (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
@@ -253,6 +259,22 @@
 		 (match_test "umips_12bit_offset_address_p (op, mode)")
 		 (match_test "mips_address_insns (op, mode, false)")))
 
+(define_constraint "Zm"
+  "@internal"
+  (match_operand 0 "umips_addiusp_imm" ""))
+
+(define_constraint "Zn"
+  "@internal"
+  (match_test "umips_addiur1sp_imm_p (op)"))
+
+(define_constraint "Zo"
+  "@internal"
+  (match_operand 0 "umips_addius5_imm" ""))
+
+(define_constraint "Zp"
+  "@internal"
+  (match_test "umips_addiur2_imm_p (op)"))
+
 (define_memory_constraint "ZR"
  "@internal
   An address valid for loading/storing register exclusive"
Index: predicates.md
===================================================================
--- predicates.md	(revision 196341)
+++ predicates.md	(working copy)
@@ -122,6 +122,13 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "umips_addius5_imm"
+  (match_test "IN_RANGE (INTVAL (op), -8, 7)"))
+
+(define_predicate "umips_addiusp_imm"
+  (ior (match_test "IN_RANGE (INTVAL (op), 2, 257)")
+       (match_test "IN_RANGE (INTVAL (op), -258, -3)")))
+
 (define_predicate "movep_src_register"
   (and (match_code "reg")
        (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
@@ -131,6 +138,14 @@
   (ior (match_operand 0 "const_0_operand")
        (match_operand 0 "movep_src_register")))
 
+(define_predicate "m16_register"
+  (and (match_code "reg")
+       (match_test "M16_REG_P (REGNO (op))")))
+
+(define_predicate "sp_register"
+  (and (match_code "reg")
+       (match_test "REGNO (op) == STACK_POINTER_REGNUM")))
+
 (define_predicate "lo_operand"
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
Index: mips.md
===================================================================
--- mips.md	(revision 196341)
+++ mips.md	(working copy)
@@ -412,12 +412,26 @@
 		(const_string "yes")
 		(const_string "no")))
 
+(define_attr "compression" "none,micromips,mips16"
+  (const_string "none"))
+
+(define_attr "enabled" "no,yes"
+  (if_then_else (and (eq_attr "compression" "micromips")
+		     (match_test "!TARGET_MICROMIPS"))
+	        (const_string "no")
+	        (const_string "yes")))
+  
 ;; Length of instruction in bytes.
 (define_attr "length" ""
    (cond [(and (eq_attr "extended_mips16" "yes")
 	       (match_test "TARGET_MIPS16"))
 	  (const_int 8)
 
+	  (and (eq_attr "compression" "micromips")
+	       (eq_attr "dword_mode" "no")
+	       (match_test "TARGET_MICROMIPS"))
+	  (const_int 2)
+
 	  ;; Direct microMIPS branch instructions have a range of
 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
 	  ;; If a branch is outside this range, we have a choice of two
@@ -1131,14 +1145,26 @@
   "")
 
 (define_insn "*add<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
-		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!w,d,d,d")
+	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,0,!w,!w,d")
+		  (match_operand:GPR 2 "arith_operand" "!u,d,Zp,Zo,Zm,Zn,Q")))]
   "!TARGET_MIPS16"
-  "@
-    <d>addu\t%0,%1,%2
-    <d>addiu\t%0,%1,%2"
+{
+  if (which_alternative == 0 
+      || which_alternative == 1)
+    return "<d>addu\t%0,%1,%2";
+  else
+    return "<d>addiu\t%0,%1,%2";
+}
   [(set_attr "alu_type" "add")
+   (set_attr_alternative "compression"
+	[(const_string "micromips")
+	 (const_string "none")
+	 (const_string "micromips")
+	 (const_string "micromips")
+	 (const_string "micromips")
+	 (const_string "micromips")
+	 (const_string "none")])
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*add<mode>3_mips16"
Index: mips-protos.h
===================================================================
--- mips-protos.h	(revision 196341)
+++ mips-protos.h	(working copy)
@@ -350,6 +350,9 @@
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern bool umips_match_reg_p (rtx, rtx);
+extern bool umips_addiur1sp_imm_p (rtx);
+extern bool umips_addiur2_imm_p (rtx);
 extern const char *umips_output_save_restore (bool, rtx);
 extern bool umips_save_restore_pattern_p (bool, rtx);
 extern bool umips_load_store_pair_p (bool, rtx *);
Index: mips.c
===================================================================
--- mips.c	(revision 196341)
+++ mips.c	(working copy)
@@ -622,7 +622,7 @@
   M16_REGS,	M16_REGS,	LEA_REGS,	LEA_REGS,
   LEA_REGS,	LEA_REGS,	LEA_REGS,	LEA_REGS,
   T_REG,	PIC_FN_ADDR_REG, LEA_REGS,	LEA_REGS,
-  LEA_REGS,	LEA_REGS,	LEA_REGS,	LEA_REGS,
+  LEA_REGS,	STACK_POINTER_REG, LEA_REGS,	LEA_REGS,
   FP_REGS,	FP_REGS,	FP_REGS,	FP_REGS,
   FP_REGS,	FP_REGS,	FP_REGS,	FP_REGS,
   FP_REGS,	FP_REGS,	FP_REGS,	FP_REGS,
@@ -2377,6 +2377,39 @@
   return 0;
 }
 
+/* Return true if reg1 is the same as reg0.  */
+bool
+umips_match_reg_p (rtx reg0, rtx reg1)
+{
+  if (REGNO (reg0) == REGNO (reg1))
+    return true;
+
+  return false;
+}
+
+/* Return true if imm1 is a valid microMIPS ADDIUR1SP value.  */
+bool
+umips_addiur1sp_imm_p (rtx imm1)
+{
+  return ((INTVAL (imm1) & 3) == 0 && IN_RANGE (INTVAL (imm1), 0, 252));
+}
+
+/* Return true if imm1 is a valid microMIPS ADDIUR2 value.  */
+bool umips_addiur2_imm_p (rtx imm1)
+{
+  if (INTVAL (imm1) == -1
+      || INTVAL (imm1) == 1
+      || INTVAL (imm1) == 4
+      || INTVAL (imm1) == 8 
+      || INTVAL (imm1) == 12
+      || INTVAL (imm1) == 16
+      || INTVAL (imm1) == 20
+      || INTVAL (imm1) == 24)
+    return true;
+
+  return false;
+}
+
 /* Return true if X is a legitimate address with a 12-bit offset.
    MODE is the mode of the value being accessed.  */
 
Index: mips.h
===================================================================
--- mips.h	(revision 196341)
+++ mips.h	(working copy)
@@ -1848,6 +1848,7 @@
   DSP_ACC_REGS,			/* DSP accumulator registers */
   ACC_REGS,			/* Hi/Lo and DSP accumulator registers */
   FRAME_REGS,			/* $arg and $frame */
+  STACK_POINTER_REG,		/* $sp */
   GR_AND_MD0_REGS,		/* union classes */
   GR_AND_MD1_REGS,
   GR_AND_MD_REGS,
@@ -1886,6 +1887,7 @@
   "DSP_ACC_REGS",							\
   "ACC_REGS",								\
   "FRAME_REGS",								\
+  "STACK_POINTER_REG",							\
   "GR_AND_MD0_REGS",							\
   "GR_AND_MD1_REGS",							\
   "GR_AND_MD_REGS",							\
@@ -1925,6 +1927,7 @@
   { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x003f0000 },	/* DSP_ACC_REGS */	\
   { 0x00000000, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x003f0000 },	/* ACC_REGS */		\
   { 0x00000000, 0x00000000, 0x00006000, 0x00000000, 0x00000000, 0x00000000 },	/* FRAME_REGS */	\
+  { 0x20000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },	/* STACK_POINTER_REG */	\
   { 0xffffffff, 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000000 },	/* GR_AND_MD0_REGS */	\
   { 0xffffffff, 0x00000000, 0x00000002, 0x00000000, 0x00000000, 0x00000000 },	/* GR_AND_MD1_REGS */	\
   { 0xffffffff, 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000000 },	/* GR_AND_MD_REGS */	\

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-04 19:43     ` Moore, Catherine
@ 2013-03-04 20:54       ` Richard Sandiford
  2013-03-04 22:47         ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-04 20:54 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> Hi Richard,
> I've attached an example patch for the add pattern that tries to
> identify the short microMIPS variants.  In your last review, you
> mentioned that you would like to see the register requirements modeled
> in the patterns.  Do you have any comments on the approach that I'm
> taking?  Thanks,

Looks good, thanks.  I was a bit surprised that we want to hide this
completely from the register allocators (by adding "!" to all of
the micromips forms) but I can see that being too honest about the
alternatives might lead to poor decisions.  That's definitely something
that could be retuned later if someone wants to.

A few bikesheddy comments:

- Please use "Y..." constraints for constants (as with "Yb", "Yh", etc.).
  I was hoping to keep "Y..." for constants and "Z..." for memory stuff. 

- You used a mixture of predicates and out-of-line functions to do
  the matching.  I think we should use the predicate approach across
  the board, because it's hard to predict which ones will come in
  useful in future.

- Predicates should always check the code though.  E.g.:

  (define_predicate "umips_addius5_imm"
    (and (match_code "const_int")
         (match_test "IN_RANGE (INTVAL (op), -8, 7)")))

- In general, please try to make the names of the predicates as generic
  as possible.  There's nothing really add-specific about the predicate
  above.  Or microMIPS-specific either really: some of these predicates
  are probably going to be useful for MIPS16 too.

  The existing MIPS16 functions follow the convention:

      "n" if negated (optional)
    + "s" or "u" for signed vs. unsigned
    + "imm"
    + number of significant bits
    + "_"
    + multiplication factor or, er, "b" for "+1"...

  It might be nice to have a similar convention for microMIPS.
  The choices there are a bit more exotic, so please feel free to
  diverge from the MIPS16 one above; we can switch MIPS16 over once
  the microMIPS one is settled.  In fact, a new convention that's
  compact enough to be used in both predicate and constraint names
  would be great.  E.g. for the umips_addius5_imm predicate above,
  a name like "Ys5" would be easier to remember than "Zo"/"Yo".

  That said,I realise things like umips_addiur2_imm_p are a bit
  hard to describe this way and might need to stay instruction-specific.

- We already have a "ks" constraint for the stack pointer.

- I like the choice of "u" for M16_REGS.  Kind of lucky that that letter's
  still free. :-) As you've probably noticed though, we're running desparately
  short of contraint letters, so if you also need names for other less
  frequently-used classes, it might be better to use "k..."  for those.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-04 20:54       ` Richard Sandiford
@ 2013-03-04 22:47         ` Moore, Catherine
  2013-03-05 21:06           ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-04 22:47 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej



> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Monday, March 04, 2013 3:54 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> > Hi Richard,
> - Predicates should always check the code though.  E.g.:
> 
>   (define_predicate "umips_addius5_imm"
>     (and (match_code "const_int")
>          (match_test "IN_RANGE (INTVAL (op), -8, 7)")))
> 
> - In general, please try to make the names of the predicates as generic
>   as possible.  There's nothing really add-specific about the predicate
>   above.  Or microMIPS-specific either really: some of these predicates
>   are probably going to be useful for MIPS16 too.
> 
>   The existing MIPS16 functions follow the convention:
> 
>       "n" if negated (optional)
>     + "s" or "u" for signed vs. unsigned
>     + "imm"
>     + number of significant bits
>     + "_"
>     + multiplication factor or, er, "b" for "+1"...
> 
>   It might be nice to have a similar convention for microMIPS.
>   The choices there are a bit more exotic, so please feel free to
>   diverge from the MIPS16 one above; we can switch MIPS16 over once
>   the microMIPS one is settled.  In fact, a new convention that's
>   compact enough to be used in both predicate and constraint names
>   would be great.  E.g. for the umips_addius5_imm predicate above,
>   a name like "Ys5" would be easier to remember than "Zo"/"Yo".

How compact would you consider "compact enough"?  I would need to change the existing "Y" constraints as well.
Would YG --> Yvec0 be too long?
I think trying to invent some convention with less than four letter will be difficult and even with four, I doubt it could be uniformly followed.
I think we could get descriptive with four, however.
Let me know what you think.

> 
>   That said,I realise things like umips_addiur2_imm_p are a bit
>   hard to describe this way and might need to stay instruction-specific.
> 
> - We already have a "ks" constraint for the stack pointer.
> 
> - I like the choice of "u" for M16_REGS.  Kind of lucky that that letter's
>   still free. :-) As you've probably noticed though, we're running desparately
>   short of contraint letters, so if you also need names for other less
>   frequently-used classes, it might be better to use "k..."  for those.
> 
> Thanks,
> Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-04 22:47         ` Moore, Catherine
@ 2013-03-05 21:06           ` Richard Sandiford
  2013-03-13 20:30             ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-05 21:06 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 4039 bytes --]

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> -----Original Message-----
>> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
>> Sent: Monday, March 04, 2013 3:54 PM
>> To: Moore, Catherine
>> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
>> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
>> 
>> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> > Hi Richard,
>> - Predicates should always check the code though.  E.g.:
>> 
>>   (define_predicate "umips_addius5_imm"
>>     (and (match_code "const_int")
>>          (match_test "IN_RANGE (INTVAL (op), -8, 7)")))
>> 
>> - In general, please try to make the names of the predicates as generic
>>   as possible.  There's nothing really add-specific about the predicate
>>   above.  Or microMIPS-specific either really: some of these predicates
>>   are probably going to be useful for MIPS16 too.
>> 
>>   The existing MIPS16 functions follow the convention:
>> 
>>       "n" if negated (optional)
>>     + "s" or "u" for signed vs. unsigned
>>     + "imm"
>>     + number of significant bits
>>     + "_"
>>     + multiplication factor or, er, "b" for "+1"...
>> 
>>   It might be nice to have a similar convention for microMIPS.
>>   The choices there are a bit more exotic, so please feel free to
>>   diverge from the MIPS16 one above; we can switch MIPS16 over once
>>   the microMIPS one is settled.  In fact, a new convention that's
>>   compact enough to be used in both predicate and constraint names
>>   would be great.  E.g. for the umips_addius5_imm predicate above,
>>   a name like "Ys5" would be easier to remember than "Zo"/"Yo".
>
> How compact would you consider "compact enough"?  I would need to change
> the existing "Y" constraints as well.

Argh, sorry, I'd forgotten about that restriction.

We have a few internal-only undocumented constraints that aren't used much,
so we should be able to move them to the "Y" space instead.  The patch
below does this for "T" and "U".  Then we could use "U" for new, longer
constraints.

> I think trying to invent some convention with less than four letter will
> be difficult and even with four, I doubt it could be uniformly followed.
> I think we could get descriptive with four, however.
> Let me know what you think.

Four sounds good.  Here's one idea:

U<type><factor><bits>

where <type> is:

  s for signed
  u for unsigned
  d for decremented unsigned (-1 ... N)
  i for incremented unsigned (1 ... N)

where <factor> is:

  b for "byte" (*1)
  h for "halfwords" (*2)
  w for "words" (*4)
  d for "doublewords" (*8) -- useful for 64-bit MIPS16 but probably not
      needed for 32-bit microMIPS

and where <bits> is the number of bits.  <type> and <factor> could be
replaced with an ad-hoc two-letter combination for special cases.
E.g. "Uas9" ("add stack") for ADDISUP.

Just a suggestion though.  I'm not saying these names are totally intuitive
or anything, but they should at least be better than arbitrary letters.

Also, <bits> could be two digits if necessary, or we could just use
hex digits.

We could have:

/* Return true if X fits within an unsigned field of BITS bits that is
   shifted left SHIFT bits before being used.  */

static inline bool
mips_unsigned_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
{
  return (x & ((1 << shift) - 1)) == 0 && x < (1 << (shift + bits));
}

/* Return true if X fits within a signed field of BITS bits that is
   shifted left SHIFT bits before being used.  */

static inline bool
mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
{
  x += 1 << (bits + shift - 1);
  return mips_unsigned_immediate_p (x, bits, shift);
}

The 'd' and 'i' cases would pass a biased X to mips_unsigned_immediate_p.

I'll apply the patch below once 4.9 starts.

Thanks,
Richard


gcc/
	* config/mips/constraints.md (T): Rename to...
	(Yf): ...this.
	(U): Rename to...
	(Yd): ...this.
	* config/mips/mips.md (*movdi_64bit, *movdi_64bit_mips16)
	(*mov<mode>_internal, *mov<mode>_mips16): Update accordingly.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: rename-const-constraints.diff --]
[-- Type: text/x-patch, Size: 3960 bytes --]

Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	2013-02-25 21:45:10.000000000 +0000
+++ gcc/config/mips/constraints.md	2013-03-05 08:22:36.687354771 +0000
@@ -170,22 +170,6 @@ (define_constraint "S"
   (and (match_operand 0 "call_insn_operand")
        (match_test "CONSTANT_P (op)")))
 
-(define_constraint "T"
-  "@internal
-   A constant @code{move_operand} that cannot be safely loaded into @code{$25}
-   using @code{la}."
-  (and (match_operand 0 "move_operand")
-       (match_test "CONSTANT_P (op)")
-       (match_test "mips_dangerous_for_la25_p (op)")))
-
-(define_constraint "U"
-  "@internal
-   A constant @code{move_operand} that can be safely loaded into @code{$25}
-   using @code{la}."
-  (and (match_operand 0 "move_operand")
-       (match_test "CONSTANT_P (op)")
-       (not (match_test "mips_dangerous_for_la25_p (op)"))))
-
 (define_memory_constraint "W"
   "@internal
    A memory address based on a member of @code{BASE_REG_CLASS}.  This is
@@ -220,6 +204,22 @@ (define_constraint "Yb"
    "@internal"
    (match_operand 0 "qi_mask_operand"))
 
+(define_constraint "Yd"
+  "@internal
+   A constant @code{move_operand} that can be safely loaded into @code{$25}
+   using @code{la}."
+  (and (match_operand 0 "move_operand")
+       (match_test "CONSTANT_P (op)")
+       (not (match_test "mips_dangerous_for_la25_p (op)"))))
+
+(define_constraint "Yf"
+  "@internal
+   A constant @code{move_operand} that cannot be safely loaded into @code{$25}
+   using @code{la}."
+  (and (match_operand 0 "move_operand")
+       (match_test "CONSTANT_P (op)")
+       (match_test "mips_dangerous_for_la25_p (op)")))
+
 (define_constraint "Yh"
    "@internal"
     (match_operand 0 "hi_mask_operand"))
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	2013-02-25 21:45:10.000000000 +0000
+++ gcc/config/mips/mips.md	2013-03-05 08:25:31.762333026 +0000
@@ -4268,7 +4268,7 @@ (define_insn "*movdi_32bit_mips16"
 
 (define_insn "*movdi_64bit"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*a,*d,*B*C*D,*B*C*D,*d,*m")
-	(match_operand:DI 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+	(match_operand:DI 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
   "TARGET_64BIT && !TARGET_MIPS16
    && (register_operand (operands[0], DImode)
        || reg_or_0_operand (operands[1], DImode))"
@@ -4278,7 +4278,7 @@ (define_insn "*movdi_64bit"
 
 (define_insn "*movdi_64bit_mips16"
   [(set (match_operand:DI 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d")
-	(match_operand:DI 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))]
+	(match_operand:DI 1 "move_operand" "d,d,y,K,N,Yd,kf,m,d,*a"))]
   "TARGET_64BIT && TARGET_MIPS16
    && (register_operand (operands[0], DImode)
        || register_operand (operands[1], DImode))"
@@ -4346,7 +4346,7 @@ (define_expand "mov<mode>"
 
 (define_insn "*mov<mode>_internal"
   [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
-	(match_operand:IMOVE32 1 "move_operand" "d,U,T,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
@@ -4356,7 +4356,7 @@ (define_insn "*mov<mode>_internal"
 
 (define_insn "*mov<mode>_mips16"
   [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,y,d,d,d,d,d,d,m,*d")
-	(match_operand:IMOVE32 1 "move_operand" "d,d,y,K,N,U,kf,m,d,*a"))]
+	(match_operand:IMOVE32 1 "move_operand" "d,d,y,K,N,Yd,kf,m,d,*a"))]
   "TARGET_MIPS16
    && (register_operand (operands[0], <MODE>mode)
        || register_operand (operands[1], <MODE>mode))"

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-05 21:06           ` Richard Sandiford
@ 2013-03-13 20:30             ` Moore, Catherine
  2013-03-14 20:55               ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-13 20:30 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 1691 bytes --]

> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Tuesday, March 05, 2013 4:06 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support:
> 
> We have a few internal-only undocumented constraints that aren't used
> much, so we should be able to move them to the "Y" space instead.  The
> patch below does this for "T" and "U".  Then we could use "U" for new,
> longer constraints.
> 
> 
> U<type><factor><bits>
> 
> where <type> is:
> 
>   s for signed
>   u for unsigned
>   d for decremented unsigned (-1 ... N)
>   i for incremented unsigned (1 ... N)
> 
> where <factor> is:
> 
>   b for "byte" (*1)
>   h for "halfwords" (*2)
>   w for "words" (*4)
>   d for "doublewords" (*8) -- useful for 64-bit MIPS16 but probably not
>       needed for 32-bit microMIPS
> 
> and where <bits> is the number of bits.  <type> and <factor> could be
> replaced with an ad-hoc two-letter combination for special cases.
> E.g. "Uas9" ("add stack") for ADDISUP.
> 
> Just a suggestion though.  I'm not saying these names are totally intuitive or
> anything, but they should at least be better than arbitrary letters.
> 
> Also, <bits> could be two digits if necessary, or we could just use hex digits.

I extended this proposal a bit by:
1.  Adding a <type> e for encoded.  The constraint will start with Ue, when the operand is an encoded value.
2. I decided to use two digits for <bits>.
3. The ad-hoc combination is used for anything else.

Patch is attached.  WDYT?
I'm still testing, but results so far look really good.
Catherine


[-- Attachment #2: short-delay.cl --]
[-- Type: application/octet-stream, Size: 1238 bytes --]

2012-03-12  Catherine Moore  <clm@codesourcery.com>

	* config/mips/constraints.md (u, Udb07, Ueand, Ueas6, Ueas9,
	Ueim4, Umem0, Uload, Ustor, Usb03, Uib03): New constraints.
	* config/mips/predicates.md (Umem0_operand, Uload_operand,
	Ustore_operand, Udb07_operand, Ueas9_operand, Ueas6_operand,
	Ueim4_operand, Ueand_operand, Usb03_operand, Uib03_operand):
	New predicates.
	* config/mips/mips.md (compression): New attribute.
	(enabled): New attribute.
	(length): Record length of short microMIPS insns.
 	(*add<mode>3): New operands. Record compression.
	(sub<mode>3): Likewise.
	(one_cmpl<mode>2): Likewise.
	(*and<mode>3): Likewise.
	(*ior<mode>3): Likewise.
	(unnamed pattern for xor): Likewise.
	(*zero_extend<SHORT:mode><GPR:mode>2): Likewise.
	(*<optab><mode>3): Likewise.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New.
	*mips_unsigned_immediate_p): New.
	(umips_lwsp_swsp_address_p): New.
	(umips_address_p): New.
	* config/mips/mips.c (mips_unsigned_immediate_p): New function.
	(mips_signed_immediate_p): New function.
	(umips_address_p): New function.
	(umips_lwsp_swsp_address_p): New function.
	(mips_print_operand_punctuation): Recognize short delay slot insns
	for microMIPS.

[-- Attachment #3: short-delay.patch --]
[-- Type: application/octet-stream, Size: 17830 bytes --]

Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	(revision 196638)
+++ gcc/config/mips/constraints.md	(working copy)
@@ -43,6 +43,9 @@
 (define_register_constraint "b" "ALL_REGS"
   "@internal")
 
+(define_register_constraint "u" "M16_REGS"
+  "@internal")
+
 ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
 ;; for details.
 (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
@@ -170,6 +173,59 @@
   (and (match_operand 0 "call_insn_operand")
        (match_test "CONSTANT_P (op)")))
 
+(define_constraint "Udb07"
+  "@internal
+   A decremented unsigned constant of 7 bits."
+  (match_operand 0 "Udb07_operand" ""))
+
+(define_constraint "Ueand"
+  "@internal
+   A microMIPS encoded andi operand."
+  (match_operand 0 "Ueand_operand" ""))
+
+(define_constraint "Ueas6"
+  "@internal
+   A microMIPS encoded ADDIUR1SP operand."
+  (match_operand 0 "Ueas6_operand" ""))
+
+(define_constraint "Ueas9"
+  "@internal
+   A microMIPS encoded ADDIUSP operand."
+  (match_operand 0 "Ueas9_operand" ""))
+
+(define_constraint "Ueim4"
+  "@internal
+   A microMIPS encoded ADDIUR2 immediate operand."
+  (match_operand 0 "Ueim4_operand" ""))
+
+(define_memory_constraint "Umem0"
+  "@internal
+   A microMIPS memory operand for use with the LWSP/SWSP insns."
+  (and (match_code "mem")
+       (match_operand 0 "Umem0_operand" "")))
+
+(define_memory_constraint "Uload"
+  "@internal
+   A microMIPS memory operand for use with the various LOAD insns."
+  (and (match_code "mem")
+       (match_operand 0 "Uload_operand" "")))
+
+(define_memory_constraint "Ustor"
+  "@internal
+   A microMIPS memory operand for use with the various STORE insns."
+  (and (match_code "mem")
+       (match_operand 0 "Ustore_operand" "")))
+  
+(define_constraint "Usb03"
+  "@internal
+   A signed three-bit constant."
+  (match_operand 0 "Usb03_operand" ""))
+
+(define_constraint "Uib03"
+  "@internal
+   An unsigned, incremented three-bit constant."
+  (match_operand 0 "Uib03_operand" ""))
+
 (define_memory_constraint "W"
   "@internal
    A memory address based on a member of @code{BASE_REG_CLASS}.  This is
Index: gcc/config/mips/predicates.md
===================================================================
--- gcc/config/mips/predicates.md	(revision 196638)
+++ gcc/config/mips/predicates.md	(working copy)
@@ -122,6 +122,61 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "Umem0_operand"
+  (and (match_code "mem")
+       (match_test "umips_lwsp_swsp_address_p (XEXP (op, 0), mode)")))
+
+(define_predicate "Uload_operand"
+  (and (match_code "mem")
+       (match_test "umips_address_p (XEXP (op, 0), true, mode)")))
+
+(define_predicate "Ustore_operand"
+  (and (match_code "mem")
+       (match_test "umips_address_p (XEXP (op, 0), false, mode)")))
+
+(define_predicate "Udb07_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7, 0)")))
+
+(define_predicate "Ueas9_operand"
+  (and (match_code "const_int")
+       (ior (match_test "(IN_RANGE (INTVAL (op), 2, 257))")
+	    (match_test "(IN_RANGE (INTVAL (op), -258, -3))"))))
+
+(define_predicate "Ueas6_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 8, 2)")))
+
+(define_predicate "Ueim4_operand"
+  (and (match_code "const_int")
+	(ior (match_test "INTVAL (op) == -1")
+	     (match_test "INTVAL (op) == 1")
+	     (match_test "INTVAL (op) == 4")
+	     (match_test "INTVAL (op) == 8")
+	     (match_test "INTVAL (op) == 12")
+	     (match_test "INTVAL (op) == 16")
+	     (match_test "INTVAL (op) == 20")
+	     (match_test "INTVAL (op) == 24"))))
+
+(define_predicate "Ueand_operand"
+  (and (match_code "const_int")
+	(ior (match_test "IN_RANGE (INTVAL (op), 1, 4)")
+	     (match_test "IN_RANGE (INTVAL (op), 7, 8)")
+	     (match_test "IN_RANGE (INTVAL (op), 15, 16)")
+	     (match_test "IN_RANGE (INTVAL (op), 31, 32)")
+	     (match_test "IN_RANGE (INTVAL (op), 63, 64)")
+	     (match_test "INTVAL (op) == 255")
+	     (match_test "INTVAL (op) == 32768")
+	     (match_test "INTVAL (op) == 65535"))))
+
+(define_predicate "Usb03_operand"
+  (and (match_code "const_int")
+       (match_test "mips_signed_immediate_p (INTVAL (op), 3, 0)")))
+
+(define_predicate "Uib03_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 3, 0)")))
+
 (define_predicate "movep_src_register"
   (and (match_code "reg")
        (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 196638)
+++ gcc/config/mips/mips.md	(working copy)
@@ -412,12 +412,29 @@
 		(const_string "yes")
 		(const_string "no")))
 
+(define_attr "compression" "none,all,micromips,mips16"
+  (const_string "none"))
+
+(define_attr "enabled" "no,yes"
+  (if_then_else (ior (eq_attr "compression" "all")
+		     (eq_attr "compression" "none")
+		     (and (eq_attr "compression" "micromips")
+	                  (match_test "TARGET_MICROMIPS")))
+	        (const_string "yes")
+	        (const_string "no")))
+  
 ;; Length of instruction in bytes.
 (define_attr "length" ""
    (cond [(and (eq_attr "extended_mips16" "yes")
 	       (match_test "TARGET_MIPS16"))
 	  (const_int 8)
 
+	  (and (ior (eq_attr "compression" "micromips")
+		    (eq_attr "compression" "all"))
+	       (eq_attr "dword_mode" "no")
+	       (match_test "TARGET_MICROMIPS"))
+	  (const_int 2)
+
 	  ;; Direct microMIPS branch instructions have a range of
 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
 	  ;; If a branch is outside this range, we have a choice of two
@@ -1131,14 +1148,19 @@
   "")
 
 (define_insn "*add<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
-		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!ks,d,d,d")
+	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,0,!ks,!ks,d")
+		  (match_operand:GPR 2 "arith_operand" "!u,d,Ueim4,Usb03,Ueas9,Ueas6,Q")))]
   "!TARGET_MIPS16"
-  "@
-    <d>addu\t%0,%1,%2
-    <d>addiu\t%0,%1,%2"
+{
+  if (which_alternative == 0 
+      || which_alternative == 1)
+    return "<d>addu\t%0,%1,%2";
+  else
+    return "<d>addiu\t%0,%1,%2";
+}
   [(set_attr "alu_type" "add")
+   (set_attr "compression" "micromips,*,micromips,micromips,micromips,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*add<mode>3_mips16"
@@ -1347,12 +1369,13 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "sub<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
-		   (match_operand:GPR 2 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		   (match_operand:GPR 2 "register_operand" "!u,d")))]
   ""
-  "<d>subu\t%0,%1,%2"
+{ return "<d>subu\t%0,%1,%2"; }
   [(set_attr "alu_type" "sub")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*subsi3_extended"
@@ -2828,8 +2851,8 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "one_cmpl<mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(not:GPR (match_operand:GPR 1 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(not:GPR (match_operand:GPR 1 "register_operand" "!u,d")))]
   ""
 {
   if (TARGET_MIPS16)
@@ -2838,6 +2861,7 @@
     return "nor\t%0,%.,%1";
 }
   [(set_attr "alu_type" "not")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 \f
 ;;
@@ -2878,9 +2902,9 @@
 ;;  register =op1                      x
 
 (define_insn "*and<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
-	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
-		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
+	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
+		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Ueand,K,Yx,Yw,!u,d")))]
   "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
 {
   int len;
@@ -2897,20 +2921,23 @@
       operands[1] = gen_lowpart (SImode, operands[1]);
       return "lwu\t%0,%1";
     case 3:
+    case 4:
       return "andi\t%0,%1,%x2";
-    case 4:
+    case 5:
       len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
       operands[2] = GEN_INT (len);
       return "<d>ext\t%0,%1,0,%2";
-    case 5:
+    case 6:
       return "#";
-    case 6:
+    case 7:
+    case 8:
       return "and\t%0,%1,%2";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
+  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
+   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*and<mode>3_mips16"
@@ -2952,14 +2979,16 @@
 })
 
 (define_insn "*ior<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(ior:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    or\t%0,%1,%2
+   or\t%0,%1,%2
    ori\t%0,%1,%x2"
   [(set_attr "alu_type" "or")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*ior<mode>3_mips16"
@@ -2979,14 +3008,16 @@
   "")
 
 (define_insn ""
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    xor\t%0,%1,%2
+   xor\t%0,%1,%2
    xori\t%0,%1,%x2"
   [(set_attr "alu_type" "xor")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn ""
@@ -3162,14 +3193,16 @@
 })
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
         (zero_extend:GPR
-	     (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
+	     (match_operand:SHORT 1 "nonimmediate_operand" "!u,d,m")))]
   "!TARGET_MIPS16"
   "@
    andi\t%0,%1,<SHORT:mask>
+   andi\t%0,%1,<SHORT:mask>
    l<SHORT:size>u\t%0,%1"
-  [(set_attr "move_type" "andi,load")
+  [(set_attr "move_type" "andi,andi,load")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<GPR:MODE>")])
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e"
@@ -4362,13 +4395,14 @@
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "*mov<mode>_internal"
-  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
-	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,d,e,!u,!u,d,d,Umem0,Ustor,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
+	(match_operand:IMOVE32 1 "move_operand" "d,J,Yd,Yf,Udb07,Uload,Umem0,m,ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+  [(set_attr "move_type" "move,move,const,const,load,load,load,load,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+   (set_attr "compression" "all,micromips,*,*,micromips,micromips,micromips,*,micromips,micromips,*,*,*,*,*,*,*,*,*,*,*,*,*")
    (set_attr "mode" "SI")])
 
 (define_insn "*mov<mode>_mips16"
@@ -5225,9 +5259,9 @@
 })
 
 (define_insn "*<optab><mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
-		       (match_operand:SI 2 "arith_operand" "dI")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(any_shift:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		       (match_operand:SI 2 "arith_operand" "Uib03,dI")))]
   "!TARGET_MIPS16"
 {
   if (CONST_INT_P (operands[2]))
@@ -5237,6 +5271,12 @@
   return "<d><insn>\t%0,%1,%2";
 }
   [(set_attr "type" "shift")
+   (set_attr_alternative "compression"
+	[(if_then_else (ior (match_test "GET_CODE (SET_SRC (PATTERN (insn))) == ASHIFT")
+			    (match_test "GET_CODE (SET_SRC (PATTERN (insn))) == LSHIFTRT"))
+		       (const_string "micromips")
+		       (const_string "none"))
+	(const_string "none")])
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*<optab>si3_extend"
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 196638)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -350,12 +350,19 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern bool mips_signed_immediate_p (unsigned HOST_WIDE_INT, int, int);
+extern bool mips_unsigned_immediate_p (unsigned HOST_WIDE_INT, int, int);
+
 extern const char *umips_output_save_restore (bool, rtx);
 extern bool umips_save_restore_pattern_p (bool, rtx);
 extern bool umips_load_store_pair_p (bool, rtx *);
 extern void umips_output_load_store_pair (bool, rtx *);
 extern bool umips_movep_target_p (rtx, rtx);
+
+extern bool umips_lwsp_swsp_address_p (rtx, enum machine_mode);
+extern bool umips_address_p (rtx, bool, enum machine_mode);
 extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
+
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 196638)
+++ gcc/config/mips/mips.c	(working copy)
@@ -2377,6 +2377,71 @@ mips_address_insns (rtx x, enum machine_mode mode,
   return 0;
 }
 
+/* Return true if X fits within an unsigned field of BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_unsigned_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+  return (x & ((1 << shift) - 1)) == 0 && x < (1 << (shift + bits));
+}
+
+/* Return true if X fits within a signed field of  BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+ x += 1 << (bits + shift - 1);
+ return mips_unsigned_immediate_p (x, bits, shift);
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for any of the short microMIPS LOAD or STORE instructions except LWSP
+   or SWSP.  */
+
+bool
+umips_address_p (rtx x, bool load, enum machine_mode mode)
+{
+
+  struct mips_address_info addr;
+  bool ok = mips_classify_address (&addr, x, mode, false)
+	    && addr.type == ADDRESS_REG
+	    && M16_REG_P (REGNO (addr.reg))
+	    && CONST_INT_P (addr.offset);
+
+  if (!ok)
+    return false;
+
+  if (mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
+      || mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 1))
+    return true;
+
+  if (load && IN_RANGE (INTVAL (addr.offset), -1, 14))
+    return true;
+
+  if (!load && IN_RANGE (INTVAL (addr.offset), 0, 15))
+    return true;
+
+  return false;
+
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for a microMIPS LWSP or SWSP insn.  */
+
+bool
+umips_lwsp_swsp_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
+	  && CONST_INT_P (addr.offset)
+	  && mips_unsigned_immediate_p (INTVAL (addr.offset), 5, 2));
+}
+
 /* Return true if X is a legitimate address with a 12-bit offset.
    MODE is the mode of the value being accessed.  */
 
@@ -8010,9 +8075,17 @@ mips_print_operand_punctuation (FILE *file, int ch
 
     case '!':
       /* When final_sequence is 0, the delay slot will be a nop.  We can
-	 a 16-bit delay slot for microMIPS.  */
+	 use a 16-bit delay slot for microMIPS.  */
       if (final_sequence == 0)
 	putc ('s', file);
+      else 
+	{
+	  /* Use the compact version for microMIPS if the delay slot is a
+	     compact microMIPS instruction.  */
+	  rtx insn = XVECEXP (final_sequence, 0, 1);
+	  if (get_attr_length (insn) == 2)
+	    putc ('s', file);
+	}
       break;
 
     default:

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-13 20:30             ` Moore, Catherine
@ 2013-03-14 20:55               ` Richard Sandiford
  2013-03-15 18:00                 ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-14 20:55 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> -----Original Message-----
>> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
>> Sent: Tuesday, March 05, 2013 4:06 PM
>> To: Moore, Catherine
>> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
>> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support:
>> 
>> We have a few internal-only undocumented constraints that aren't used
>> much, so we should be able to move them to the "Y" space instead.  The
>> patch below does this for "T" and "U".  Then we could use "U" for new,
>> longer constraints.
>> 
>> 
>> U<type><factor><bits>
>> 
>> where <type> is:
>> 
>>   s for signed
>>   u for unsigned
>>   d for decremented unsigned (-1 ... N)
>>   i for incremented unsigned (1 ... N)
>> 
>> where <factor> is:
>> 
>>   b for "byte" (*1)
>>   h for "halfwords" (*2)
>>   w for "words" (*4)
>>   d for "doublewords" (*8) -- useful for 64-bit MIPS16 but probably not
>>       needed for 32-bit microMIPS
>> 
>> and where <bits> is the number of bits.  <type> and <factor> could be
>> replaced with an ad-hoc two-letter combination for special cases.
>> E.g. "Uas9" ("add stack") for ADDISUP.
>> 
>> Just a suggestion though.  I'm not saying these names are totally intuitive or
>> anything, but they should at least be better than arbitrary letters.
>> 
>> Also, <bits> could be two digits if necessary, or we could just use hex digits.
>
> I extended this proposal a bit by:
> 1.  Adding a <type> e for encoded.  The constraint will start with Ue,
> when the operand is an encoded value.
> 2. I decided to use two digits for <bits>.
> 3. The ad-hoc combination is used for anything else.

First of all, thanks for coming up with a counter-suggestion.  I'm hopeless
at naming things, so I was hoping there would be at least some pushback.

"e" for "encoded" sounds good.  I'm less keen on the mixture of single-
and double-digit widths though (single digit for some "Ue"s, double
digits for other "U"s.)  I think we should either:

(a) use the same number of digits for all "U" constraints.  That leaves
    one character for the "Ue" type, which isn't as mnemonic, but is in
    line with what we do elsewhere.

(b) avoid digits in the "Ue" forms and just have an ad-hoc letter combination.

Please keep "U" for constants though.  The memory constraints should go
under "Z" instead (and therefore be only two letters long).  The idea is
that the first letter of the constraint tells you what type it is.

I don't think there's any need for the "Ue" constraints to have
predicates of the same name.  We can go with longer, mnemonic,
names instead.  The idea behind suggesting "sb4_operand", etc.,
was that (a) every character was predictable and (b) I'm not sure
the extra verbosity of (say) "signed_byte_4_operand" would help.
But "addiur2_operand" would be good.

> +(define_constraint "Udb07"
> +  "@internal
> +   A decremented unsigned constant of 7 bits."
> +  (match_operand 0 "Udb07_operand" ""))

Very minor nit, but these "" are redundant.

> +(define_constraint "Ueim4"
> +  "@internal
> +   A microMIPS encoded ADDIUR2 immediate operand."
> +  (match_operand 0 "Ueim4_operand" ""))

Again minor, but the name doesn't really seem to match the description.
Is this constraint needed for things other than ADDIUR2?  If so, it might
be worth giving a second example, otherwise it might be better to make
the name a bit less general.  Unless this name comes from the manual,
of course :-)  (The microMIPS link on the MIPS website was still
broken last time I checked, but I haven't tried it again in the
last couple of weeks.)

> +(define_predicate "Umem0_operand"
> +  (and (match_code "mem")
> +       (match_test "umips_lwsp_swsp_address_p (XEXP (op, 0), mode)")))
> +
> +(define_predicate "Uload_operand"
> +  (and (match_code "mem")
> +       (match_test "umips_address_p (XEXP (op, 0), true, mode)")))
> +
> +(define_predicate "Ustore_operand"
> +  (and (match_code "mem")
> +       (match_test "umips_address_p (XEXP (op, 0), false, mode)")))

With the two-letter Z constraints, these should have descriptive names.

> +(define_predicate "Udb07_operand"
> +  (and (match_code "const_int")
> +       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7, 0)")))

Please drop the "U"s in the predicate names.

> +(define_attr "compression" "none,all,micromips,mips16"
> +  (const_string "none"))

Thinking about it a bit more, it would probably be better to leave the
"all" and "mips16" values out until we need them.

> +(define_attr "enabled" "no,yes"
> +  (if_then_else (ior (eq_attr "compression" "all")
> +		     (eq_attr "compression" "none")
> +		     (and (eq_attr "compression" "micromips")
> +	                  (match_test "TARGET_MICROMIPS")))
> +	        (const_string "yes")
> +	        (const_string "no")))

FWIW (probably not much after the above), it's also possible to write:

    (eq_attr "compression" "all,none")

> @@ -5237,6 +5271,12 @@
>    return "<d><insn>\t%0,%1,%2";
>  }
>    [(set_attr "type" "shift")
> +   (set_attr_alternative "compression"
> +	[(if_then_else (ior (match_test "GET_CODE (SET_SRC (PATTERN (insn))) == ASHIFT")
> +			    (match_test "GET_CODE (SET_SRC (PATTERN (insn))) == LSHIFTRT"))
> +		       (const_string "micromips")
> +		       (const_string "none"))
> +	(const_string "none")])
>     (set_attr "mode" "<MODE>")])

This would probably be better as:

(define_code_attr shift_compression [(ashift "micromips")
                                     (lshiftrt "micromips")
                                     (ashiftrt "none")])
...
  (set_attr "compression" "micromips,<shift_compression>")

which makes the distinction at compile time.

The mips.md changes look good otherwise though.

One idea (just as a nice-to-have) is that we could add an option that
makes the asm output routines add ".16" to mnemonics that we think are
16 bits long, as a bit of extra sanity checking.  That would be a separate
patch though and is definitely not a requirement.

> +/* Return true if X is a legitimate address that conforms to the requirements
> +   for any of the short microMIPS LOAD or STORE instructions except LWSP
> +   or SWSP.  */
> +
> +bool
> +umips_address_p (rtx x, bool load, enum machine_mode mode)
> +{
> +
> +  struct mips_address_info addr;
> +  bool ok = mips_classify_address (&addr, x, mode, false)
> +	    && addr.type == ADDRESS_REG
> +	    && M16_REG_P (REGNO (addr.reg))
> +	    && CONST_INT_P (addr.offset);
> +
> +  if (!ok)
> +    return false;
> +
> +  if (mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
> +      || mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 1))
> +    return true;
> +
> +  if (load && IN_RANGE (INTVAL (addr.offset), -1, 14))
> +    return true;
> +
> +  if (!load && IN_RANGE (INTVAL (addr.offset), 0, 15))
> +    return true;
> +
> +  return false;
> +
> +}

No blank lines after "{" and before "}".

More importantly, what cases are these range tests covering?
Both binutils and qemu seem to think that LW and SW need offsets
that exactly match:

    mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)

i.e.:

bool
umips_address_p (rtx x, enum machine_mode mode)
{
  struct mips_address_info addr;
  if (mips_classify_address (&addr, x, mode, false)
      && addr.type == ADDRESS_REG
      && M16_REG_P (REGNO (addr.reg))
      && uw4_operand (addr.offset))
    return true;
}

with no load vs. store check.

> +/* Return true if X is a legitimate address that conforms to the requirements
> +   for a microMIPS LWSP or SWSP insn.  */
> +
> +bool
> +umips_lwsp_swsp_address_p (rtx x, enum machine_mode mode)
> +{
> +  struct mips_address_info addr;
> +
> +  return (mips_classify_address (&addr, x, mode, false)
> +	  && addr.type == ADDRESS_REG
> +	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
> +	  && CONST_INT_P (addr.offset)
> +	  && mips_unsigned_immediate_p (INTVAL (addr.offset), 5, 2));

I'd prefer:

  return (mips_classify_address (&addr, x, mode, false)
	  && addr.type == ADDRESS_REG
	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
	  && uw5_operand (addr.offset));

> @@ -8010,9 +8075,17 @@ mips_print_operand_punctuation (FILE *file, int ch
>  
>      case '!':
>        /* When final_sequence is 0, the delay slot will be a nop.  We can
> -	 a 16-bit delay slot for microMIPS.  */
> +	 use a 16-bit delay slot for microMIPS.  */
>        if (final_sequence == 0)
>  	putc ('s', file);
> +      else 
> +	{
> +	  /* Use the compact version for microMIPS if the delay slot is a
> +	     compact microMIPS instruction.  */
> +	  rtx insn = XVECEXP (final_sequence, 0, 1);
> +	  if (get_attr_length (insn) == 2)
> +	    putc ('s', file);
> +	}

I think this is easier as:

    if (final_sequence == 0
	|| get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
      putc ('s', file);

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-14 20:55               ` Richard Sandiford
@ 2013-03-15 18:00                 ` Moore, Catherine
  2013-03-19 19:26                   ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-15 18:00 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 10383 bytes --]

Hi Richard,
There are a couple of embedded comments, plus new patch attached.  Are we there yet?
Thanks,
Catherine

> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Thursday, March 14, 2013 4:55 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> >> -----Original Message-----
> >> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> >> Sent: Tuesday, March 05, 2013 4:06 PM
> >> To: Moore, Catherine
> >> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> >> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support:
> >>
> >> We have a few internal-only undocumented constraints that aren't used
> >> much, so we should be able to move them to the "Y" space instead.
> >> The patch below does this for "T" and "U".  Then we could use "U" for
> >> new, longer constraints.
> >>
> >>
> >> U<type><factor><bits>
> >>
> >> where <type> is:
> >>
> >>   s for signed
> >>   u for unsigned
> >>   d for decremented unsigned (-1 ... N)
> >>   i for incremented unsigned (1 ... N)
> >>
> >> where <factor> is:
> >>
> >>   b for "byte" (*1)
> >>   h for "halfwords" (*2)
> >>   w for "words" (*4)
> >>   d for "doublewords" (*8) -- useful for 64-bit MIPS16 but probably not
> >>       needed for 32-bit microMIPS
> >>
> >> and where <bits> is the number of bits.  <type> and <factor> could be
> >> replaced with an ad-hoc two-letter combination for special cases.
> >> E.g. "Uas9" ("add stack") for ADDISUP.
> >>
> >> Just a suggestion though.  I'm not saying these names are totally
> >> intuitive or anything, but they should at least be better than arbitrary
> letters.
> >>
> >> Also, <bits> could be two digits if necessary, or we could just use hex
> digits.
> >
> > I extended this proposal a bit by:
> > 1.  Adding a <type> e for encoded.  The constraint will start with Ue,
> > when the operand is an encoded value.
> > 2. I decided to use two digits for <bits>.
> > 3. The ad-hoc combination is used for anything else.
> 
> First of all, thanks for coming up with a counter-suggestion.  I'm hopeless at
> naming things, so I was hoping there would be at least some pushback.
> 
> "e" for "encoded" sounds good.  I'm less keen on the mixture of single- and
> double-digit widths though (single digit for some "Ue"s, double digits for
> other "U"s.)  I think we should either:
> 
> (a) use the same number of digits for all "U" constraints.  That leaves
>     one character for the "Ue" type, which isn't as mnemonic, but is in
>     line with what we do elsewhere.
> 
> (b) avoid digits in the "Ue" forms and just have an ad-hoc letter combination.
> 
> Please keep "U" for constants though.  The memory constraints should go
> under "Z" instead (and therefore be only two letters long).  The idea is that
> the first letter of the constraint tells you what type it is.
> 
> I don't think there's any need for the "Ue" constraints to have predicates of
> the same name.  We can go with longer, mnemonic, names instead.  The idea
> behind suggesting "sb4_operand", etc., was that (a) every character was
> predictable and (b) I'm not sure the extra verbosity of (say)
> "signed_byte_4_operand" would help.
> But "addiur2_operand" would be good.
> 
> > +(define_constraint "Udb07"
> > +  "@internal
> > +   A decremented unsigned constant of 7 bits."
> > +  (match_operand 0 "Udb07_operand" ""))
> 
> Very minor nit, but these "" are redundant.
> 
> > +(define_constraint "Ueim4"
> > +  "@internal
> > +   A microMIPS encoded ADDIUR2 immediate operand."
> > +  (match_operand 0 "Ueim4_operand" ""))
> 
> Again minor, but the name doesn't really seem to match the description.
> Is this constraint needed for things other than ADDIUR2?  

The constraint is only used for ADDIUR2.

If so, it might be
> worth giving a second example, otherwise it might be better to make the
> name a bit less general.  Unless this name comes from the manual, of course
> :-)  (The microMIPS link on the MIPS website was still broken last time I
> checked, but I haven't tried it again in the last couple of weeks.)
> 
> > +(define_predicate "Umem0_operand"
> > +  (and (match_code "mem")
> > +       (match_test "umips_lwsp_swsp_address_p (XEXP (op, 0),
> > +mode)")))
> > +
> > +(define_predicate "Uload_operand"
> > +  (and (match_code "mem")
> > +       (match_test "umips_address_p (XEXP (op, 0), true, mode)")))
> > +
> > +(define_predicate "Ustore_operand"
> > +  (and (match_code "mem")
> > +       (match_test "umips_address_p (XEXP (op, 0), false, mode)")))
> 
> With the two-letter Z constraints, these should have descriptive names.
> 
> > +(define_predicate "Udb07_operand"
> > +  (and (match_code "const_int")
> > +       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7,
> > +0)")))
> 
> Please drop the "U"s in the predicate names.
> 
> > +(define_attr "compression" "none,all,micromips,mips16"
> > +  (const_string "none"))
> 
> Thinking about it a bit more, it would probably be better to leave the "all" and
> "mips16" values out until we need them.

You probably missed it, but there is one use of the "all constraint in the patch.  It's the first alternative in the *mov<mode>_internal pattern.  I've removed the "mips16" value in the current patch.
> 
> > +(define_attr "enabled" "no,yes"
> > +  (if_then_else (ior (eq_attr "compression" "all")
> > +		     (eq_attr "compression" "none")
> > +		     (and (eq_attr "compression" "micromips")
> > +	                  (match_test "TARGET_MICROMIPS")))
> > +	        (const_string "yes")
> > +	        (const_string "no")))
> 
> FWIW (probably not much after the above), it's also possible to write:
> 
>     (eq_attr "compression" "all,none")
> 
> > @@ -5237,6 +5271,12 @@
> >    return "<d><insn>\t%0,%1,%2";
> >  }
> >    [(set_attr "type" "shift")
> > +   (set_attr_alternative "compression"
> > +	[(if_then_else (ior (match_test "GET_CODE (SET_SRC (PATTERN
> (insn))) == ASHIFT")
> > +			    (match_test "GET_CODE (SET_SRC (PATTERN
> (insn))) == LSHIFTRT"))
> > +		       (const_string "micromips")
> > +		       (const_string "none"))
> > +	(const_string "none")])
> >     (set_attr "mode" "<MODE>")])
> 
> This would probably be better as:
> 
> (define_code_attr shift_compression [(ashift "micromips")
>                                      (lshiftrt "micromips")
>                                      (ashiftrt "none")]) ...
>   (set_attr "compression" "micromips,<shift_compression>")
> 
> which makes the distinction at compile time.
> 
> The mips.md changes look good otherwise though.
> 
> One idea (just as a nice-to-have) is that we could add an option that makes
> the asm output routines add ".16" to mnemonics that we think are
> 16 bits long, as a bit of extra sanity checking.  That would be a separate patch
> though and is definitely not a requirement.
> 
> > +/* Return true if X is a legitimate address that conforms to the
> requirements
> > +   for any of the short microMIPS LOAD or STORE instructions except LWSP
> > +   or SWSP.  */
> > +
> > +bool
> > +umips_address_p (rtx x, bool load, enum machine_mode mode) {
> > +
> > +  struct mips_address_info addr;
> > +  bool ok = mips_classify_address (&addr, x, mode, false)
> > +	    && addr.type == ADDRESS_REG
> > +	    && M16_REG_P (REGNO (addr.reg))
> > +	    && CONST_INT_P (addr.offset);
> > +
> > +  if (!ok)
> > +    return false;
> > +
> > +  if (mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
> > +      || mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 1))
> > +    return true;
> > +
> > +  if (load && IN_RANGE (INTVAL (addr.offset), -1, 14))
> > +    return true;
> > +
> > +  if (!load && IN_RANGE (INTVAL (addr.offset), 0, 15))
> > +    return true;
> > +
> > +  return false;
> > +
> > +}
> 
> No blank lines after "{" and before "}".
> 
> More importantly, what cases are these range tests covering?
> Both binutils and qemu seem to think that LW and SW need offsets that
> exactly match:
> 
>     mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
> 

Those range tests are for the LBU16 and SB16 instructions.  LBU16 supports offsets from -1 to 14 (encodes -1 as 15) while the SB16 insn supports offsets from 0-15.  

> i.e.:
> 
> bool
> umips_address_p (rtx x, enum machine_mode mode) {
>   struct mips_address_info addr;
>   if (mips_classify_address (&addr, x, mode, false)
>       && addr.type == ADDRESS_REG
>       && M16_REG_P (REGNO (addr.reg))
>       && uw4_operand (addr.offset))
>     return true;
> }
> 
> with no load vs. store check.
> 
> > +/* Return true if X is a legitimate address that conforms to the
> requirements
> > +   for a microMIPS LWSP or SWSP insn.  */
> > +
> > +bool
> > +umips_lwsp_swsp_address_p (rtx x, enum machine_mode mode) {
> > +  struct mips_address_info addr;
> > +
> > +  return (mips_classify_address (&addr, x, mode, false)
> > +	  && addr.type == ADDRESS_REG
> > +	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
> > +	  && CONST_INT_P (addr.offset)
> > +	  && mips_unsigned_immediate_p (INTVAL (addr.offset), 5, 2));
> 
> I'd prefer:
> 
>   return (mips_classify_address (&addr, x, mode, false)
> 	  && addr.type == ADDRESS_REG
> 	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
> 	  && uw5_operand (addr.offset));
> 
> > @@ -8010,9 +8075,17 @@ mips_print_operand_punctuation (FILE *file, int
> > ch
> >
> >      case '!':
> >        /* When final_sequence is 0, the delay slot will be a nop.  We can
> > -	 a 16-bit delay slot for microMIPS.  */
> > +	 use a 16-bit delay slot for microMIPS.  */
> >        if (final_sequence == 0)
> >  	putc ('s', file);
> > +      else
> > +	{
> > +	  /* Use the compact version for microMIPS if the delay slot is a
> > +	     compact microMIPS instruction.  */
> > +	  rtx insn = XVECEXP (final_sequence, 0, 1);
> > +	  if (get_attr_length (insn) == 2)
> > +	    putc ('s', file);
> > +	}
> 
> I think this is easier as:
> 
>     if (final_sequence == 0
> 	|| get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
>       putc ('s', file);
> 
> Richard

[-- Attachment #2: short-delay.cl --]
[-- Type: application/octet-stream, Size: 1788 bytes --]

2012-03-15  Catherine Moore  <clm@codesourcery.com>

	* config/mips/constraints.md (u, Udb8, Uea4, Uean, Ueim,
	Uib3, Uesp, Usb3, ZS, ZT, ZU): New constraints.
	* config/mips/predicates.md (umips_lwsp_swsp_operand): New predicate.
	(umips_load_operand): Likewise.
	(umips_store_operand): Likewise.
	(db4_operand): Likewise.
	(db7_operand): Likewise.
	(ib3_operand): Likewise.
	(sb3_operand): Likewise.
	(ub4_operand): Likewise.
	(uh4_operand): Likewise.
	(uw4_operand): Likewise.
	(uw5_operand): Likewise.
	(addiur1sp_operand): Likewise.
	(addiur2_operand): Likewise.
	(addiusp_operand): Likewise.
	(andi16_operand): Likewise.
	* config/mips/mips.md
	* config/mips/mips.md (compression): New attribute.
	(enabled): New attribute.
	(length): Record length of short microMIPS insns.
	(shift_compression): New code attribute.
 	(*add<mode>3): New operands. Record compression.
	(sub<mode>3): Likewise.
	(one_cmpl<mode>2): Likewise.
	(*and<mode>3): Likewise.
	(*ior<mode>3): Likewise.
	(unnamed pattern for xor): Likewise.
	(*zero_extend<SHORT:mode><GPR:mode>2): Likewise.
	(*<optab><mode>3): Likewise.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New.
	*mips_unsigned_immediate_p): New.
	(umips_lwsp_swsp_address_p): New.
	(umips_address_p): New.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New prototype.
	(mips_unsigned_immediate_p): New prototype.
	(umips_lwsp_swsp_address_p): New prototype.
	(umips_load_store_address_p): New prototype.
	* config/mips/mips.c (mips_unsigned_immediate_p): New function.
	(mips_signed_immediate_p): New function.
	(umips_load_store_address_p): New function.
	(umips_lwsp_swsp_address_p): New function.
	(mips_print_operand_punctuation): Recognize short delay slot insns
	for microMIPS.

[-- Attachment #3: short-delay.patch --]
[-- Type: application/octet-stream, Size: 18630 bytes --]

Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	(revision 196638)
+++ gcc/config/mips/constraints.md	(working copy)
@@ -43,6 +43,9 @@
 (define_register_constraint "b" "ALL_REGS"
   "@internal")
 
+(define_register_constraint "u" "M16_REGS"
+  "@internal")
+
 ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
 ;; for details.
 (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
@@ -170,6 +173,41 @@
   (and (match_operand 0 "call_insn_operand")
        (match_test "CONSTANT_P (op)")))
 
+(define_constraint "Udb7"
+  "@internal
+   A decremented unsigned constant of 7 bits."
+  (match_operand 0 "db7_operand"))
+
+(define_constraint "Uea4"
+  "@internal
+   A microMIPS encoded ADDIUR2 immediate operand."
+  (match_operand 0 "addiur2_operand"))
+  
+(define_constraint "Uean"
+  "@internal
+   A microMIPS encoded andi operand."
+  (match_operand 0 "andi16_operand"))
+
+(define_constraint "Ueim"
+  "@internal
+   A microMIPS encoded ADDIUSP operand."
+  (match_operand 0 "addiusp_operand"))
+
+(define_constraint "Uib3"
+  "@internal
+   An unsigned, incremented three-bit constant."
+  (match_operand 0 "ib3_operand"))
+
+(define_constraint "Uesp"
+  "@internal
+   A microMIPS encoded ADDIUR1SP operand."
+  (match_operand 0 "addiur1sp_operand"))
+
+(define_constraint "Usb3"
+  "@internal
+   A signed three-bit constant."
+  (match_operand 0 "sb3_operand"))
+
 (define_memory_constraint "W"
   "@internal
    A memory address based on a member of @code{BASE_REG_CLASS}.  This is
@@ -257,3 +295,21 @@
  "@internal
   An address valid for loading/storing register exclusive"
  (match_operand 0 "mem_noofs_operand"))
+
+(define_memory_constraint "ZS"
+  "@internal
+   A microMIPS memory operand for use with the LWSP/SWSP insns."
+  (and (match_code "mem")
+       (match_operand 0 "umips_lwsp_swsp_operand")))
+
+(define_memory_constraint "ZT"
+  "@internal
+   A microMIPS memory operand for use with the various LOAD insns."
+  (and (match_code "mem")
+       (match_operand 0 "umips_load_operand")))
+
+(define_memory_constraint "ZU"
+  "@internal
+   A microMIPS memory operand for use with the various STORE insns."
+  (and (match_code "mem")
+       (match_operand 0 "umips_store_operand")))
Index: gcc/config/mips/predicates.md
===================================================================
--- gcc/config/mips/predicates.md	(revision 196638)
+++ gcc/config/mips/predicates.md	(working copy)
@@ -122,6 +122,81 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "umips_lwsp_swsp_operand"
+  (and (match_code "mem")
+       (match_test "umips_lwsp_swsp_address_p (XEXP (op, 0), mode)")))
+
+(define_predicate "umips_load_operand"
+  (and (match_code "mem")
+       (match_test "umips_load_store_address_p (XEXP (op, 0), true, mode)")))
+
+(define_predicate "umips_store_operand"
+  (and (match_code "mem")
+       (match_test "umips_load_store_address_p (XEXP (op, 0), false, mode)")))
+
+(define_predicate "db4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 4, 0)")))
+
+(define_predicate "db7_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7, 0)")))
+
+(define_predicate "ib3_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 3, 0)")))
+
+(define_predicate "sb3_operand"
+  (and (match_code "const_int")
+       (match_test "mips_signed_immediate_p (INTVAL (op), 3, 0)")))
+
+(define_predicate "ub4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "uh4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 1)")))
+
+(define_predicate "uw4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 2)")))
+
+(define_predicate "uw5_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 5, 2)")))
+
+(define_predicate "addiur1sp_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 8, 2)")))
+
+(define_predicate "addiur2_operand"
+  (and (match_code "const_int")
+	(ior (match_test "INTVAL (op) == -1")
+	     (match_test "INTVAL (op) == 1")
+	     (match_test "INTVAL (op) == 4")
+	     (match_test "INTVAL (op) == 8")
+	     (match_test "INTVAL (op) == 12")
+	     (match_test "INTVAL (op) == 16")
+	     (match_test "INTVAL (op) == 20")
+	     (match_test "INTVAL (op) == 24"))))
+
+(define_predicate "addiusp_operand"
+  (and (match_code "const_int")
+       (ior (match_test "(IN_RANGE (INTVAL (op), 2, 257))")
+	    (match_test "(IN_RANGE (INTVAL (op), -258, -3))"))))
+
+(define_predicate "andi16_operand"
+  (and (match_code "const_int")
+	(ior (match_test "IN_RANGE (INTVAL (op), 1, 4)")
+	     (match_test "IN_RANGE (INTVAL (op), 7, 8)")
+	     (match_test "IN_RANGE (INTVAL (op), 15, 16)")
+	     (match_test "IN_RANGE (INTVAL (op), 31, 32)")
+	     (match_test "IN_RANGE (INTVAL (op), 63, 64)")
+	     (match_test "INTVAL (op) == 255")
+	     (match_test "INTVAL (op) == 32768")
+	     (match_test "INTVAL (op) == 65535"))))
+
 (define_predicate "movep_src_register"
   (and (match_code "reg")
        (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 196638)
+++ gcc/config/mips/mips.md	(working copy)
@@ -412,12 +412,28 @@
 		(const_string "yes")
 		(const_string "no")))
 
+(define_attr "compression" "none,all,micromips"
+  (const_string "none"))
+
+(define_attr "enabled" "no,yes"
+  (if_then_else (ior (eq_attr "compression" "all,none")
+		     (and (eq_attr "compression" "micromips")
+	                  (match_test "TARGET_MICROMIPS")))
+	        (const_string "yes")
+	        (const_string "no")))
+  
 ;; Length of instruction in bytes.
 (define_attr "length" ""
    (cond [(and (eq_attr "extended_mips16" "yes")
 	       (match_test "TARGET_MIPS16"))
 	  (const_int 8)
 
+	  (and (ior (eq_attr "compression" "micromips")
+		    (eq_attr "compression" "all"))
+	       (eq_attr "dword_mode" "no")
+	       (match_test "TARGET_MICROMIPS"))
+	  (const_int 2)
+
 	  ;; Direct microMIPS branch instructions have a range of
 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
 	  ;; If a branch is outside this range, we have a choice of two
@@ -964,6 +980,10 @@
 				  (xor "xori")
 				  (and "andi")])
 
+(define_code_attr shift_compression [(ashift "micromips")
+				     (lshiftrt "micromips")
+				     (ashiftrt "none")])
+
 ;; <fcond> is the c.cond.fmt condition associated with a particular code.
 (define_code_attr fcond [(unordered "un")
 			 (uneq "ueq")
@@ -1131,14 +1151,19 @@
   "")
 
 (define_insn "*add<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
-		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!ks,d,d,d")
+	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,0,!ks,!ks,d")
+		  (match_operand:GPR 2 "arith_operand" "!u,d,Uea4,Usb3,Ueim,Uesp,Q")))]
   "!TARGET_MIPS16"
-  "@
-    <d>addu\t%0,%1,%2
-    <d>addiu\t%0,%1,%2"
+{
+  if (which_alternative == 0 
+      || which_alternative == 1)
+    return "<d>addu\t%0,%1,%2";
+  else
+    return "<d>addiu\t%0,%1,%2";
+}
   [(set_attr "alu_type" "add")
+   (set_attr "compression" "micromips,*,micromips,micromips,micromips,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*add<mode>3_mips16"
@@ -1347,12 +1372,13 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "sub<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
-		   (match_operand:GPR 2 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		   (match_operand:GPR 2 "register_operand" "!u,d")))]
   ""
-  "<d>subu\t%0,%1,%2"
+{ return "<d>subu\t%0,%1,%2"; }
   [(set_attr "alu_type" "sub")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*subsi3_extended"
@@ -2828,8 +2854,8 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "one_cmpl<mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(not:GPR (match_operand:GPR 1 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(not:GPR (match_operand:GPR 1 "register_operand" "!u,d")))]
   ""
 {
   if (TARGET_MIPS16)
@@ -2838,6 +2864,7 @@
     return "nor\t%0,%.,%1";
 }
   [(set_attr "alu_type" "not")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 \f
 ;;
@@ -2878,9 +2905,9 @@
 ;;  register =op1                      x
 
 (define_insn "*and<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
-	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
-		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
+	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
+		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
   "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
 {
   int len;
@@ -2897,20 +2924,23 @@
       operands[1] = gen_lowpart (SImode, operands[1]);
       return "lwu\t%0,%1";
     case 3:
+    case 4:
       return "andi\t%0,%1,%x2";
-    case 4:
+    case 5:
       len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
       operands[2] = GEN_INT (len);
       return "<d>ext\t%0,%1,0,%2";
-    case 5:
+    case 6:
       return "#";
-    case 6:
+    case 7:
+    case 8:
       return "and\t%0,%1,%2";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
+  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
+   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*and<mode>3_mips16"
@@ -2952,14 +2982,16 @@
 })
 
 (define_insn "*ior<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(ior:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    or\t%0,%1,%2
+   or\t%0,%1,%2
    ori\t%0,%1,%x2"
   [(set_attr "alu_type" "or")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*ior<mode>3_mips16"
@@ -2979,14 +3011,16 @@
   "")
 
 (define_insn ""
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    xor\t%0,%1,%2
+   xor\t%0,%1,%2
    xori\t%0,%1,%x2"
   [(set_attr "alu_type" "xor")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn ""
@@ -3162,14 +3196,16 @@
 })
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
         (zero_extend:GPR
-	     (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
+	     (match_operand:SHORT 1 "nonimmediate_operand" "!u,d,m")))]
   "!TARGET_MIPS16"
   "@
    andi\t%0,%1,<SHORT:mask>
+   andi\t%0,%1,<SHORT:mask>
    l<SHORT:size>u\t%0,%1"
-  [(set_attr "move_type" "andi,load")
+  [(set_attr "move_type" "andi,andi,load")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<GPR:MODE>")])
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e"
@@ -4362,13 +4398,14 @@
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "*mov<mode>_internal"
-  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
-	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,d,e,!u,!u,d,d,ZS,ZU,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
+	(match_operand:IMOVE32 1 "move_operand" "d,J,Yd,Yf,Udb7,ZT,ZS,m,ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+  [(set_attr "move_type" "move,move,const,const,load,load,load,load,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+   (set_attr "compression" "all,micromips,*,*,micromips,micromips,micromips,*,micromips,micromips,*,*,*,*,*,*,*,*,*,*,*,*,*")
    (set_attr "mode" "SI")])
 
 (define_insn "*mov<mode>_mips16"
@@ -5225,9 +5262,9 @@
 })
 
 (define_insn "*<optab><mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
-		       (match_operand:SI 2 "arith_operand" "dI")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(any_shift:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		       (match_operand:SI 2 "arith_operand" "Uib3,dI")))]
   "!TARGET_MIPS16"
 {
   if (CONST_INT_P (operands[2]))
@@ -5237,6 +5274,7 @@
   return "<d><insn>\t%0,%1,%2";
 }
   [(set_attr "type" "shift")
+   (set_attr "compression" "<shift_compression>,none")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*<optab>si3_extend"
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 196638)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -350,12 +350,19 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern bool mips_signed_immediate_p (unsigned HOST_WIDE_INT, int, int);
+extern bool mips_unsigned_immediate_p (unsigned HOST_WIDE_INT, int, int);
+
 extern const char *umips_output_save_restore (bool, rtx);
 extern bool umips_save_restore_pattern_p (bool, rtx);
 extern bool umips_load_store_pair_p (bool, rtx *);
 extern void umips_output_load_store_pair (bool, rtx *);
 extern bool umips_movep_target_p (rtx, rtx);
+
+extern bool umips_lwsp_swsp_address_p (rtx, enum machine_mode);
+extern bool umips_load_store_address_p (rtx, bool, enum machine_mode);
 extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
+
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 196638)
+++ gcc/config/mips/mips.c	(working copy)
@@ -2377,6 +2377,70 @@ mips_address_insns (rtx x, enum machine_mode mode,
   return 0;
 }
 
+/* Return true if X fits within an unsigned field of BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_unsigned_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+  return (x & ((1 << shift) - 1)) == 0 && x < (1 << (shift + bits));
+}
+
+/* Return true if X fits within a signed field of  BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+ x += 1 << (bits + shift - 1);
+ return mips_unsigned_immediate_p (x, bits, shift);
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for any of the short microMIPS LOAD or STORE instructions except LWSP
+   or SWSP.  */
+
+bool
+umips_load_store_address_p (rtx x, bool load, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+  bool ok = mips_classify_address (&addr, x, mode, false)
+	    && addr.type == ADDRESS_REG
+	    && M16_REG_P (REGNO (addr.reg))
+	    && CONST_INT_P (addr.offset);
+
+  if (!ok)
+    return false;
+
+  /* For the LBU16 insn.  */
+  if (load && db4_operand (addr.offset, mode))
+    return true;
+
+  /* For the SB16 insn.  */
+  if (!load && ub4_operand (addr.offset, mode))
+    return true;
+
+  /* For SH16, LHU16, SW16 and LW16 insns.  */
+  return uw4_operand (addr.offset, mode)
+          || uh4_operand (addr.offset, mode);
+
+  return false;
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for a microMIPS LWSP or SWSP insn.  */
+
+bool
+umips_lwsp_swsp_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
+	  && uw5_operand (addr.offset, mode));
+}
+
 /* Return true if X is a legitimate address with a 12-bit offset.
    MODE is the mode of the value being accessed.  */
 
@@ -8009,9 +8073,10 @@ mips_print_operand_punctuation (FILE *file, int ch
       break;
 
     case '!':
-      /* When final_sequence is 0, the delay slot will be a nop.  We can
-	 a 16-bit delay slot for microMIPS.  */
-      if (final_sequence == 0)
+      /* If the delay slot instruction is short, then use the
+	 compact version.  */
+      if (final_sequence == 0
+	  || get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
 	putc ('s', file);
       break;
 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-15 18:00                 ` Moore, Catherine
@ 2013-03-19 19:26                   ` Richard Sandiford
  2013-03-19 21:23                     ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-19 19:26 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> >> -----Original Message-----
>> >> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
>> >> Sent: Tuesday, March 05, 2013 4:06 PM
>> >> To: Moore, Catherine
>> >> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
>> >> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support:
>> >>
>> >> We have a few internal-only undocumented constraints that aren't used
>> >> much, so we should be able to move them to the "Y" space instead.
>> >> The patch below does this for "T" and "U".  Then we could use "U" for
>> >> new, longer constraints.
>> >>
>> >>
>> >> U<type><factor><bits>
>> >>
>> >> where <type> is:
>> >>
>> >>   s for signed
>> >>   u for unsigned
>> >>   d for decremented unsigned (-1 ... N)
>> >>   i for incremented unsigned (1 ... N)
>> >>
>> >> where <factor> is:
>> >>
>> >>   b for "byte" (*1)
>> >>   h for "halfwords" (*2)
>> >>   w for "words" (*4)
>> >>   d for "doublewords" (*8) -- useful for 64-bit MIPS16 but probably not
>> >>       needed for 32-bit microMIPS
>> >>
>> >> and where <bits> is the number of bits.  <type> and <factor> could be
>> >> replaced with an ad-hoc two-letter combination for special cases.
>> >> E.g. "Uas9" ("add stack") for ADDISUP.
>> >>
>> >> Just a suggestion though.  I'm not saying these names are totally
>> >> intuitive or anything, but they should at least be better than arbitrary
>> letters.
>> >>
>> >> Also, <bits> could be two digits if necessary, or we could just use hex
>> digits.
>> >
>> > I extended this proposal a bit by:
>> > 1.  Adding a <type> e for encoded.  The constraint will start with Ue,
>> > when the operand is an encoded value.
>> > 2. I decided to use two digits for <bits>.
>> > 3. The ad-hoc combination is used for anything else.
>> 
>> First of all, thanks for coming up with a counter-suggestion.  I'm hopeless at
>> naming things, so I was hoping there would be at least some pushback.
>> 
>> "e" for "encoded" sounds good.  I'm less keen on the mixture of single- and
>> double-digit widths though (single digit for some "Ue"s, double digits for
>> other "U"s.)  I think we should either:
>> 
>> (a) use the same number of digits for all "U" constraints.  That leaves
>>     one character for the "Ue" type, which isn't as mnemonic, but is in
>>     line with what we do elsewhere.
>> 
>> (b) avoid digits in the "Ue" forms and just have an ad-hoc letter combination.

FWIW, as far as this point goes, the patch still has "Uea4".

>> > +/* Return true if X is a legitimate address that conforms to the
>> requirements
>> > +   for any of the short microMIPS LOAD or STORE instructions except LWSP
>> > +   or SWSP.  */
>> > +
>> > +bool
>> > +umips_address_p (rtx x, bool load, enum machine_mode mode) {
>> > +
>> > +  struct mips_address_info addr;
>> > +  bool ok = mips_classify_address (&addr, x, mode, false)
>> > +	    && addr.type == ADDRESS_REG
>> > +	    && M16_REG_P (REGNO (addr.reg))
>> > +	    && CONST_INT_P (addr.offset);
>> > +
>> > +  if (!ok)
>> > +    return false;
>> > +
>> > +  if (mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
>> > +      || mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 1))
>> > +    return true;
>> > +
>> > +  if (load && IN_RANGE (INTVAL (addr.offset), -1, 14))
>> > +    return true;
>> > +
>> > +  if (!load && IN_RANGE (INTVAL (addr.offset), 0, 15))
>> > +    return true;
>> > +
>> > +  return false;
>> > +
>> > +}
>> 
>> No blank lines after "{" and before "}".
>> 
>> More importantly, what cases are these range tests covering?
>> Both binutils and qemu seem to think that LW and SW need offsets that
>> exactly match:
>> 
>>     mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
>> 
>
> Those range tests are for the LBU16 and SB16 instructions.  LBU16
> supports offsets from -1 to 14 (encodes -1 as 15) while the SB16 insn
> supports offsets from 0-15.

They need to use separate constraints in that case.  The patch as written
allows -1 offsets for LW16 too.  (In rare cases, offsets like -1 can be
used even with aligned word loads.)

E.g. we could have:

/* Return true if X is legitimate for accessing values of mode MODE,
   if it is based on a MIPS16 register, and if the offset satisfies
   OFFSET_PREDICATE.  */

bool
m16_based_address_p (rtx x, enum machine_mode mode,
		     insn_operand_predicate_fn predicate)
{
  struct mips_address_info addr;
  return (mips_classify_address (&addr, x, mode, false)
	  && addr.type == ADDRESS_REG
	  && M16_REG_P (REGNO (addr.reg))
	  && offset_predicate (addr.offset));
}

Perhaps if there are so many of these, we should define "T???" to be
a memory constraint in which the base register is an M16_REG and in
which "???" has the same format as for "U".  E.g. "Tuw4" for LW and SW.
That's just a suggestion though.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-19 19:26                   ` Richard Sandiford
@ 2013-03-19 21:23                     ` Moore, Catherine
  2013-03-19 21:23                       ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-19 21:23 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej



> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Tuesday, March 19, 2013 3:26 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> >> >> -----Original Message-----
> >> >> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> >> >> Sent: Tuesday, March 05, 2013 4:06 PM
> >> >> To: Moore, Catherine
> >> >> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> >> >> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support:
> >> >>
> >> >> We have a few internal-only undocumented constraints that aren't
> >> >> used much, so we should be able to move them to the "Y" space
> instead.
> >> >> The patch below does this for "T" and "U".  Then we could use "U"
> >> >> for new, longer constraints.
> >> >>
> >> >>
> >> >> U<type><factor><bits>
> >> >>
> >> >> where <type> is:
> >> >>
> >> >>   s for signed
> >> >>   u for unsigned
> >> >>   d for decremented unsigned (-1 ... N)
> >> >>   i for incremented unsigned (1 ... N)
> >> >>
> >> >> where <factor> is:
> >> >>
> >> >>   b for "byte" (*1)
> >> >>   h for "halfwords" (*2)
> >> >>   w for "words" (*4)
> >> >>   d for "doublewords" (*8) -- useful for 64-bit MIPS16 but probably not
> >> >>       needed for 32-bit microMIPS
> >> >>
> >> >> and where <bits> is the number of bits.  <type> and <factor> could
> >> >> be replaced with an ad-hoc two-letter combination for special cases.
> >> >> E.g. "Uas9" ("add stack") for ADDISUP.
> >> >>
> >> >> Just a suggestion though.  I'm not saying these names are totally
> >> >> intuitive or anything, but they should at least be better than
> >> >> arbitrary
> >> letters.
> >> >>
> >> >> Also, <bits> could be two digits if necessary, or we could just
> >> >> use hex
> >> digits.
> >> >
> >> > I extended this proposal a bit by:
> >> > 1.  Adding a <type> e for encoded.  The constraint will start with
> >> > Ue, when the operand is an encoded value.
> >> > 2. I decided to use two digits for <bits>.
> >> > 3. The ad-hoc combination is used for anything else.
> >>
> >> First of all, thanks for coming up with a counter-suggestion.  I'm
> >> hopeless at naming things, so I was hoping there would be at least some
> pushback.
> >>
> >> "e" for "encoded" sounds good.  I'm less keen on the mixture of
> >> single- and double-digit widths though (single digit for some "Ue"s,
> >> double digits for other "U"s.)  I think we should either:
> >>
> >> (a) use the same number of digits for all "U" constraints.  That leaves
> >>     one character for the "Ue" type, which isn't as mnemonic, but is in
> >>     line with what we do elsewhere.
> >>
> >> (b) avoid digits in the "Ue" forms and just have an ad-hoc letter
> combination.
> 
> FWIW, as far as this point goes, the patch still has "Uea4".
> 
> >> > +/* Return true if X is a legitimate address that conforms to the
> >> requirements
> >> > +   for any of the short microMIPS LOAD or STORE instructions except
> LWSP
> >> > +   or SWSP.  */
> >> > +
> >> > +bool
> >> > +umips_address_p (rtx x, bool load, enum machine_mode mode) {
> >> > +
> >> > +  struct mips_address_info addr;
> >> > +  bool ok = mips_classify_address (&addr, x, mode, false)
> >> > +	    && addr.type == ADDRESS_REG
> >> > +	    && M16_REG_P (REGNO (addr.reg))
> >> > +	    && CONST_INT_P (addr.offset);
> >> > +
> >> > +  if (!ok)
> >> > +    return false;
> >> > +
> >> > +  if (mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
> >> > +      || mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 1))
> >> > +    return true;
> >> > +
> >> > +  if (load && IN_RANGE (INTVAL (addr.offset), -1, 14))
> >> > +    return true;
> >> > +
> >> > +  if (!load && IN_RANGE (INTVAL (addr.offset), 0, 15))
> >> > +    return true;
> >> > +
> >> > +  return false;
> >> > +
> >> > +}
> >>
> >> No blank lines after "{" and before "}".
> >>
> >> More importantly, what cases are these range tests covering?
> >> Both binutils and qemu seem to think that LW and SW need offsets that
> >> exactly match:
> >>
> >>     mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
> >>
> >
> > Those range tests are for the LBU16 and SB16 instructions.  LBU16
> > supports offsets from -1 to 14 (encodes -1 as 15) while the SB16 insn
> > supports offsets from 0-15.
> 
> They need to use separate constraints in that case.  The patch as written
> allows -1 offsets for LW16 too.  (In rare cases, offsets like -1 can be used even
> with aligned word loads.)
> 
> E.g. we could have:
> 
> /* Return true if X is legitimate for accessing values of mode MODE,
>    if it is based on a MIPS16 register, and if the offset satisfies
>    OFFSET_PREDICATE.  */
> 
> bool
> m16_based_address_p (rtx x, enum machine_mode mode,
> 		     insn_operand_predicate_fn predicate) {
>   struct mips_address_info addr;
>   return (mips_classify_address (&addr, x, mode, false)
> 	  && addr.type == ADDRESS_REG
> 	  && M16_REG_P (REGNO (addr.reg))
> 	  && offset_predicate (addr.offset));
> }
> 
> Perhaps if there are so many of these, we should define "T???" to be a
> memory constraint in which the base register is an M16_REG and in which
> "???" has the same format as for "U".  E.g. "Tuw4" for LW and SW.
> That's just a suggestion though.
> 

I'd just as soon leave them as "Z" constraints, if that's okay with you.  I do see the need for separate constraints.  I'll fix that up.
Adding the new microMIPS memory constraints here would take ZS-ZZ.  The base microMIPS patch used ZC and ZD and ZR has been used.
That leaves ZA, ZB, and ZD to ZQ.
Catherine

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-19 21:23                     ` Moore, Catherine
@ 2013-03-19 21:23                       ` Richard Sandiford
  2013-03-20 20:15                         ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-19 21:23 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> -----Original Message-----
>> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
>> Sent: Tuesday, March 19, 2013 3:26 PM
>> To: Moore, Catherine
>> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
>> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
>> 
>> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> >> >> -----Original Message-----
>> >> >> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
>> >> >> Sent: Tuesday, March 05, 2013 4:06 PM
>> >> >> To: Moore, Catherine
>> >> >> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
>> >> >> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support:
>> >> >>
>> >> >> We have a few internal-only undocumented constraints that aren't
>> >> >> used much, so we should be able to move them to the "Y" space
>> instead.
>> >> >> The patch below does this for "T" and "U".  Then we could use "U"
>> >> >> for new, longer constraints.
>> >> >>
>> >> >>
>> >> >> U<type><factor><bits>
>> >> >>
>> >> >> where <type> is:
>> >> >>
>> >> >>   s for signed
>> >> >>   u for unsigned
>> >> >>   d for decremented unsigned (-1 ... N)
>> >> >>   i for incremented unsigned (1 ... N)
>> >> >>
>> >> >> where <factor> is:
>> >> >>
>> >> >>   b for "byte" (*1)
>> >> >>   h for "halfwords" (*2)
>> >> >>   w for "words" (*4)
>> >> >>   d for "doublewords" (*8) -- useful for 64-bit MIPS16 but probably not
>> >> >>       needed for 32-bit microMIPS
>> >> >>
>> >> >> and where <bits> is the number of bits.  <type> and <factor> could
>> >> >> be replaced with an ad-hoc two-letter combination for special cases.
>> >> >> E.g. "Uas9" ("add stack") for ADDISUP.
>> >> >>
>> >> >> Just a suggestion though.  I'm not saying these names are totally
>> >> >> intuitive or anything, but they should at least be better than
>> >> >> arbitrary
>> >> letters.
>> >> >>
>> >> >> Also, <bits> could be two digits if necessary, or we could just
>> >> >> use hex
>> >> digits.
>> >> >
>> >> > I extended this proposal a bit by:
>> >> > 1.  Adding a <type> e for encoded.  The constraint will start with
>> >> > Ue, when the operand is an encoded value.
>> >> > 2. I decided to use two digits for <bits>.
>> >> > 3. The ad-hoc combination is used for anything else.
>> >>
>> >> First of all, thanks for coming up with a counter-suggestion.  I'm
>> >> hopeless at naming things, so I was hoping there would be at least some
>> pushback.
>> >>
>> >> "e" for "encoded" sounds good.  I'm less keen on the mixture of
>> >> single- and double-digit widths though (single digit for some "Ue"s,
>> >> double digits for other "U"s.)  I think we should either:
>> >>
>> >> (a) use the same number of digits for all "U" constraints.  That leaves
>> >>     one character for the "Ue" type, which isn't as mnemonic, but is in
>> >>     line with what we do elsewhere.
>> >>
>> >> (b) avoid digits in the "Ue" forms and just have an ad-hoc letter
>> combination.
>> 
>> FWIW, as far as this point goes, the patch still has "Uea4".
>> 
>> >> > +/* Return true if X is a legitimate address that conforms to the
>> >> requirements
>> >> > +   for any of the short microMIPS LOAD or STORE instructions except
>> LWSP
>> >> > +   or SWSP.  */
>> >> > +
>> >> > +bool
>> >> > +umips_address_p (rtx x, bool load, enum machine_mode mode) {
>> >> > +
>> >> > +  struct mips_address_info addr;
>> >> > +  bool ok = mips_classify_address (&addr, x, mode, false)
>> >> > +	    && addr.type == ADDRESS_REG
>> >> > +	    && M16_REG_P (REGNO (addr.reg))
>> >> > +	    && CONST_INT_P (addr.offset);
>> >> > +
>> >> > +  if (!ok)
>> >> > +    return false;
>> >> > +
>> >> > +  if (mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
>> >> > +      || mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 1))
>> >> > +    return true;
>> >> > +
>> >> > +  if (load && IN_RANGE (INTVAL (addr.offset), -1, 14))
>> >> > +    return true;
>> >> > +
>> >> > +  if (!load && IN_RANGE (INTVAL (addr.offset), 0, 15))
>> >> > +    return true;
>> >> > +
>> >> > +  return false;
>> >> > +
>> >> > +}
>> >>
>> >> No blank lines after "{" and before "}".
>> >>
>> >> More importantly, what cases are these range tests covering?
>> >> Both binutils and qemu seem to think that LW and SW need offsets that
>> >> exactly match:
>> >>
>> >>     mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
>> >>
>> >
>> > Those range tests are for the LBU16 and SB16 instructions.  LBU16
>> > supports offsets from -1 to 14 (encodes -1 as 15) while the SB16 insn
>> > supports offsets from 0-15.
>> 
>> They need to use separate constraints in that case.  The patch as written
>> allows -1 offsets for LW16 too.  (In rare cases, offsets like -1 can be used even
>> with aligned word loads.)
>> 
>> E.g. we could have:
>> 
>> /* Return true if X is legitimate for accessing values of mode MODE,
>>    if it is based on a MIPS16 register, and if the offset satisfies
>>    OFFSET_PREDICATE.  */
>> 
>> bool
>> m16_based_address_p (rtx x, enum machine_mode mode,
>> 		     insn_operand_predicate_fn predicate) {
>>   struct mips_address_info addr;
>>   return (mips_classify_address (&addr, x, mode, false)
>> 	  && addr.type == ADDRESS_REG
>> 	  && M16_REG_P (REGNO (addr.reg))
>> 	  && offset_predicate (addr.offset));
>> }
>> 
>> Perhaps if there are so many of these, we should define "T???" to be a
>> memory constraint in which the base register is an M16_REG and in which
>> "???" has the same format as for "U".  E.g. "Tuw4" for LW and SW.
>> That's just a suggestion though.
>> 
>
> I'd just as soon leave them as "Z" constraints, if that's okay with you.

Yeah, that's fine.

> I do see the need for separate constraints.  I'll fix that up.
> Adding the new microMIPS memory constraints here would take ZS-ZZ.  The
> base microMIPS patch used ZC and ZD and ZR has been used.
> That leaves ZA, ZB, and ZD to ZQ.

Sounds good, thanks.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-19 21:23                       ` Richard Sandiford
@ 2013-03-20 20:15                         ` Moore, Catherine
  2013-03-20 21:48                           ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-20 20:15 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 6767 bytes --]



> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Tuesday, March 19, 2013 4:38 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> >> -----Original Message-----
> >> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> >> Sent: Tuesday, March 19, 2013 3:26 PM
> >> To: Moore, Catherine
> >> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> >> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> >>
> >> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> >> >> >> -----Original Message-----
> >> >> >> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> >> >> >> Sent: Tuesday, March 05, 2013 4:06 PM
> >> >> >> To: Moore, Catherine
> >> >> >> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> >> >> >> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support:
> >> >> >>
> >> >> >> We have a few internal-only undocumented constraints that
> >> >> >> aren't used much, so we should be able to move them to the "Y"
> >> >> >> space
> >> instead.
> >> >> >> The patch below does this for "T" and "U".  Then we could use "U"
> >> >> >> for new, longer constraints.
> >> >> >>
> >> >> >>
> >> >> >> U<type><factor><bits>
> >> >> >>
> >> >> >> where <type> is:
> >> >> >>
> >> >> >>   s for signed
> >> >> >>   u for unsigned
> >> >> >>   d for decremented unsigned (-1 ... N)
> >> >> >>   i for incremented unsigned (1 ... N)
> >> >> >>
> >> >> >> where <factor> is:
> >> >> >>
> >> >> >>   b for "byte" (*1)
> >> >> >>   h for "halfwords" (*2)
> >> >> >>   w for "words" (*4)
> >> >> >>   d for "doublewords" (*8) -- useful for 64-bit MIPS16 but probably
> not
> >> >> >>       needed for 32-bit microMIPS
> >> >> >>
> >> >> >> and where <bits> is the number of bits.  <type> and <factor>
> >> >> >> could be replaced with an ad-hoc two-letter combination for special
> cases.
> >> >> >> E.g. "Uas9" ("add stack") for ADDISUP.
> >> >> >>
> >> >> >> Just a suggestion though.  I'm not saying these names are
> >> >> >> totally intuitive or anything, but they should at least be
> >> >> >> better than arbitrary
> >> >> letters.
> >> >> >>
> >> >> >> Also, <bits> could be two digits if necessary, or we could just
> >> >> >> use hex
> >> >> digits.
> >> >> >
> >> >> > I extended this proposal a bit by:
> >> >> > 1.  Adding a <type> e for encoded.  The constraint will start
> >> >> > with Ue, when the operand is an encoded value.
> >> >> > 2. I decided to use two digits for <bits>.
> >> >> > 3. The ad-hoc combination is used for anything else.
> >> >>
> >> >> First of all, thanks for coming up with a counter-suggestion.  I'm
> >> >> hopeless at naming things, so I was hoping there would be at least
> >> >> some
> >> pushback.
> >> >>
> >> >> "e" for "encoded" sounds good.  I'm less keen on the mixture of
> >> >> single- and double-digit widths though (single digit for some
> >> >> "Ue"s, double digits for other "U"s.)  I think we should either:
> >> >>
> >> >> (a) use the same number of digits for all "U" constraints.  That leaves
> >> >>     one character for the "Ue" type, which isn't as mnemonic, but is in
> >> >>     line with what we do elsewhere.
> >> >>
> >> >> (b) avoid digits in the "Ue" forms and just have an ad-hoc letter
> >> combination.
> >>
> >> FWIW, as far as this point goes, the patch still has "Uea4".
> >>
> >> >> > +/* Return true if X is a legitimate address that conforms to
> >> >> > +the
> >> >> requirements
> >> >> > +   for any of the short microMIPS LOAD or STORE instructions
> >> >> > + except
> >> LWSP
> >> >> > +   or SWSP.  */
> >> >> > +
> >> >> > +bool
> >> >> > +umips_address_p (rtx x, bool load, enum machine_mode mode) {
> >> >> > +
> >> >> > +  struct mips_address_info addr;
> >> >> > +  bool ok = mips_classify_address (&addr, x, mode, false)
> >> >> > +	    && addr.type == ADDRESS_REG
> >> >> > +	    && M16_REG_P (REGNO (addr.reg))
> >> >> > +	    && CONST_INT_P (addr.offset);
> >> >> > +
> >> >> > +  if (!ok)
> >> >> > +    return false;
> >> >> > +
> >> >> > +  if (mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
> >> >> > +      || mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 1))
> >> >> > +    return true;
> >> >> > +
> >> >> > +  if (load && IN_RANGE (INTVAL (addr.offset), -1, 14))
> >> >> > +    return true;
> >> >> > +
> >> >> > +  if (!load && IN_RANGE (INTVAL (addr.offset), 0, 15))
> >> >> > +    return true;
> >> >> > +
> >> >> > +  return false;
> >> >> > +
> >> >> > +}
> >> >>
> >> >> No blank lines after "{" and before "}".
> >> >>
> >> >> More importantly, what cases are these range tests covering?
> >> >> Both binutils and qemu seem to think that LW and SW need offsets
> >> >> that exactly match:
> >> >>
> >> >>     mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
> >> >>
> >> >
> >> > Those range tests are for the LBU16 and SB16 instructions.  LBU16
> >> > supports offsets from -1 to 14 (encodes -1 as 15) while the SB16
> >> > insn supports offsets from 0-15.
> >>
> >> They need to use separate constraints in that case.  The patch as
> >> written allows -1 offsets for LW16 too.  (In rare cases, offsets like
> >> -1 can be used even with aligned word loads.)
> >>
> >> E.g. we could have:
> >>
> >> /* Return true if X is legitimate for accessing values of mode MODE,
> >>    if it is based on a MIPS16 register, and if the offset satisfies
> >>    OFFSET_PREDICATE.  */
> >>
> >> bool
> >> m16_based_address_p (rtx x, enum machine_mode mode,
> >> 		     insn_operand_predicate_fn predicate) {
> >>   struct mips_address_info addr;
> >>   return (mips_classify_address (&addr, x, mode, false)
> >> 	  && addr.type == ADDRESS_REG
> >> 	  && M16_REG_P (REGNO (addr.reg))
> >> 	  && offset_predicate (addr.offset)); }
> >>
> >> Perhaps if there are so many of these, we should define "T???" to be
> >> a memory constraint in which the base register is an M16_REG and in
> >> which "???" has the same format as for "U".  E.g. "Tuw4" for LW and SW.
> >> That's just a suggestion though.
> >>
> >
> > I'd just as soon leave them as "Z" constraints, if that's okay with you.
> 
> Yeah, that's fine.
> 
> > I do see the need for separate constraints.  I'll fix that up.
> > Adding the new microMIPS memory constraints here would take ZS-ZZ.
> > The base microMIPS patch used ZC and ZD and ZR has been used.
> > That leaves ZA, ZB, and ZD to ZQ.
> 
> Sounds good, thanks.
> 
HI Richard,
Now done.  New patch and ChangeLog attached.  Thanks for reviewing.
Catherine


[-- Attachment #2: short-delay.cl --]
[-- Type: application/octet-stream, Size: 1662 bytes --]

2013-03-20  Catherine Moore  <clm@codesourcery.com>

	* config/mips/constraints.md (u, Udb7, Uead, Uean, Ueim, Uib3,
	Uesp, Usb3, ZS, ZT, ZU, ZV, ZW, ZX, ZY, ZZ): New constraints.
	* config/mips/predicates.md (lwsp_swsp_operand, lw16_operand,
	lhu16_operand, lbu16_operand, sw16_operand, sh16_operand,
	sb16_operand, db4_operand, db7_operand, ib3_operand,
	sb3_operand, ub4_operand, uh4_operand, uw4_operand,
	uw5_operand, addiur1sp_operand, addiur2_operand,
	addiusp_operand, andi16_operand): New predicates.
	* config/mips/mips.md (compression): New attribute.
	(enabled): New attribute.
	(length): Consider compression in computing length.
	(shift_compression): New code attribute.
	(*add<mode>3): New operands. Record compression.
	(sub<mode>3): Likewise.
	(one_cmpl<mode>2): Likewise.
	(*and<mode>3): Likewise.
	(*ior<mode>3): Likewise.
	(unnamed pattern for xor): Likewise.
	(*zero_extend<SHORT:mode><GPR:mode>2): Likewise.
	(*<optab><mode>3): Likewise.
	(*mov<mode>_internal: Likewise.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New.
	(mips_unsigned_immediate_p): New.
	(umips_lwsp_swsp_address_p): New.
	(m16_based_address_p): New.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New prototype.
	(mips_unsigned_immediate_p): New prototype.
	(lwsp_swsp_address_p): New prototype.
	(m16_based_address_p): New prototype.
	* config/mips/mips.c (mips_unsigned_immediate_p): New function.
	(mips_signed_immediate_p): New function.
	(m16_based_address_p): New function.
	(lwsp_swsp_address_p): New function.
	(mips_print_operand_punctuation): Recognize short delay slot insns
	for microMIPS.add<mode>3"

[-- Attachment #3: short-delay.patch --]
[-- Type: application/octet-stream, Size: 18810 bytes --]

Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	(revision 196638)
+++ gcc/config/mips/constraints.md	(working copy)
@@ -43,6 +43,9 @@
 (define_register_constraint "b" "ALL_REGS"
   "@internal")
 
+(define_register_constraint "u" "M16_REGS"
+  "@internal")
+
 ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
 ;; for details.
 (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
@@ -170,6 +173,41 @@
   (and (match_operand 0 "call_insn_operand")
        (match_test "CONSTANT_P (op)")))
 
+(define_constraint "Udb7"
+  "@internal
+   A decremented unsigned constant of 7 bits."
+  (match_operand 0 "db7_operand"))
+
+(define_constraint "Uea4"
+  "@internal
+   A microMIPS encoded ADDIUR2 immediate operand."
+  (match_operand 0 "addiur2_operand"))
+  
+(define_constraint "Uean"
+  "@internal
+   A microMIPS encoded andi operand."
+  (match_operand 0 "andi16_operand" ""))
+
+(define_constraint "Ueim"
+  "@internal
+   A microMIPS encoded ADDIUSP operand."
+  (match_operand 0 "addiusp_operand" ""))
+
+(define_constraint "Uib3"
+  "@internal
+   An unsigned, incremented three-bit constant."
+  (match_operand 0 "ib3_operand"))
+
+(define_constraint "Uesp"
+  "@internal
+   A microMIPS encoded ADDIUR1SP operand."
+  (match_operand 0 "addiur1sp_operand" ""))
+
+(define_constraint "Usb3"
+  "@internal
+   A signed three-bit constant."
+  (match_operand 0 "sb3_operand"))
+
 (define_memory_constraint "W"
   "@internal
    A memory address based on a member of @code{BASE_REG_CLASS}.  This is
@@ -257,3 +295,21 @@
  "@internal
   An address valid for loading/storing register exclusive"
  (match_operand 0 "mem_noofs_operand"))
+
+(define_memory_constraint "ZS"
+  "@internal
+   A microMIPS memory operand for use with the LWSP/SWSP insns."
+  (and (match_code "mem")
+       (match_operand 0 "umips_lwsp_swsp_operand")))
+
+(define_memory_constraint "ZT"
+  "@internal
+   A microMIPS memory operand for use with the various LOAD insns."
+  (and (match_code "mem")
+       (match_operand 0 "umips_load_operand")))
+
+(define_memory_constraint "ZU"
+  "@internal
+   A microMIPS memory operand for use with the various STORE insns."
+  (and (match_code "mem")
+       (match_operand 0 "umips_store_operand")))
Index: gcc/config/mips/predicates.md
===================================================================
--- gcc/config/mips/predicates.md	(revision 196638)
+++ gcc/config/mips/predicates.md	(working copy)
@@ -122,6 +122,81 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "umips_lwsp_swsp_operand"
+  (and (match_code "mem")
+       (match_test "umips_lwsp_swsp_address_p (XEXP (op, 0), mode)")))
+
+(define_predicate "umips_load_operand"
+  (and (match_code "mem")
+       (match_test "umips_load_store_address_p (XEXP (op, 0), true, mode)")))
+
+(define_predicate "umips_store_operand"
+  (and (match_code "mem")
+       (match_test "umips_load_store_address_p (XEXP (op, 0), false, mode)")))
+
+(define_predicate "db4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 4, 0)")))
+
+(define_predicate "db7_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7, 0)")))
+
+(define_predicate "ib3_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 3, 0)")))
+
+(define_predicate "sb3_operand"
+  (and (match_code "const_int")
+       (match_test "mips_signed_immediate_p (INTVAL (op), 3, 0)")))
+
+(define_predicate "ub4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "uh4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 1)")))
+
+(define_predicate "uw4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 2)")))
+
+(define_predicate "uw5_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 5, 2)")))
+
+(define_predicate "addiur1sp_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 8, 2)")))
+
+(define_predicate "addiur2_operand"
+  (and (match_code "const_int")
+	(ior (match_test "INTVAL (op) == -1")
+	     (match_test "INTVAL (op) == 1")
+	     (match_test "INTVAL (op) == 4")
+	     (match_test "INTVAL (op) == 8")
+	     (match_test "INTVAL (op) == 12")
+	     (match_test "INTVAL (op) == 16")
+	     (match_test "INTVAL (op) == 20")
+	     (match_test "INTVAL (op) == 24"))))
+
+(define_predicate "addiusp_operand"
+  (and (match_code "const_int")
+       (ior (match_test "(IN_RANGE (INTVAL (op), 2, 257))")
+	    (match_test "(IN_RANGE (INTVAL (op), -258, -3))"))))
+
+(define_predicate "andi16_operand"
+  (and (match_code "const_int")
+	(ior (match_test "IN_RANGE (INTVAL (op), 1, 4)")
+	     (match_test "IN_RANGE (INTVAL (op), 7, 8)")
+	     (match_test "IN_RANGE (INTVAL (op), 15, 16)")
+	     (match_test "IN_RANGE (INTVAL (op), 31, 32)")
+	     (match_test "IN_RANGE (INTVAL (op), 63, 64)")
+	     (match_test "INTVAL (op) == 255")
+	     (match_test "INTVAL (op) == 32768")
+	     (match_test "INTVAL (op) == 65535"))))
+
 (define_predicate "movep_src_register"
   (and (match_code "reg")
        (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 196638)
+++ gcc/config/mips/mips.md	(working copy)
@@ -412,12 +412,28 @@
 		(const_string "yes")
 		(const_string "no")))
 
+(define_attr "compression" "none,all,micromips"
+  (const_string "none"))
+
+(define_attr "enabled" "no,yes"
+  (if_then_else (ior (eq_attr "compression" "all,none")
+		     (and (eq_attr "compression" "micromips")
+	                  (match_test "TARGET_MICROMIPS")))
+	        (const_string "yes")
+	        (const_string "no")))
+  
 ;; Length of instruction in bytes.
 (define_attr "length" ""
    (cond [(and (eq_attr "extended_mips16" "yes")
 	       (match_test "TARGET_MIPS16"))
 	  (const_int 8)
 
+	  (and (ior (eq_attr "compression" "micromips")
+		    (eq_attr "compression" "all"))
+	       (eq_attr "dword_mode" "no")
+	       (match_test "TARGET_MICROMIPS"))
+	  (const_int 2)
+
 	  ;; Direct microMIPS branch instructions have a range of
 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
 	  ;; If a branch is outside this range, we have a choice of two
@@ -964,6 +980,10 @@
 				  (xor "xori")
 				  (and "andi")])
 
+(define_code_attr shift_compression [(ashift "micromips")
+				     (lshiftrt "micromips")
+				     (ashiftrt "none")])
+
 ;; <fcond> is the c.cond.fmt condition associated with a particular code.
 (define_code_attr fcond [(unordered "un")
 			 (uneq "ueq")
@@ -1131,14 +1151,19 @@
   "")
 
 (define_insn "*add<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
-		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!ks,d,d,d")
+	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,0,!ks,!ks,d")
+		  (match_operand:GPR 2 "arith_operand" "!u,d,Uea4,Usb3,Ueim,Uesp,Q")))]
   "!TARGET_MIPS16"
-  "@
-    <d>addu\t%0,%1,%2
-    <d>addiu\t%0,%1,%2"
+{
+  if (which_alternative == 0 
+      || which_alternative == 1)
+    return "<d>addu\t%0,%1,%2";
+  else
+    return "<d>addiu\t%0,%1,%2";
+}
   [(set_attr "alu_type" "add")
+   (set_attr "compression" "micromips,*,micromips,micromips,micromips,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*add<mode>3_mips16"
@@ -1347,12 +1372,13 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "sub<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
-		   (match_operand:GPR 2 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		   (match_operand:GPR 2 "register_operand" "!u,d")))]
   ""
-  "<d>subu\t%0,%1,%2"
+{ return "<d>subu\t%0,%1,%2"; }
   [(set_attr "alu_type" "sub")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*subsi3_extended"
@@ -2828,8 +2854,8 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "one_cmpl<mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(not:GPR (match_operand:GPR 1 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(not:GPR (match_operand:GPR 1 "register_operand" "!u,d")))]
   ""
 {
   if (TARGET_MIPS16)
@@ -2838,6 +2864,7 @@
     return "nor\t%0,%.,%1";
 }
   [(set_attr "alu_type" "not")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 \f
 ;;
@@ -2878,9 +2905,9 @@
 ;;  register =op1                      x
 
 (define_insn "*and<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
-	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
-		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
+	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
+		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
   "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
 {
   int len;
@@ -2897,20 +2924,23 @@
       operands[1] = gen_lowpart (SImode, operands[1]);
       return "lwu\t%0,%1";
     case 3:
+    case 4:
       return "andi\t%0,%1,%x2";
-    case 4:
+    case 5:
       len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
       operands[2] = GEN_INT (len);
       return "<d>ext\t%0,%1,0,%2";
-    case 5:
+    case 6:
       return "#";
-    case 6:
+    case 7:
+    case 8:
       return "and\t%0,%1,%2";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
+  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
+   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*and<mode>3_mips16"
@@ -2952,14 +2982,16 @@
 })
 
 (define_insn "*ior<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(ior:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    or\t%0,%1,%2
+   or\t%0,%1,%2
    ori\t%0,%1,%x2"
   [(set_attr "alu_type" "or")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*ior<mode>3_mips16"
@@ -2979,14 +3011,16 @@
   "")
 
 (define_insn ""
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    xor\t%0,%1,%2
+   xor\t%0,%1,%2
    xori\t%0,%1,%x2"
   [(set_attr "alu_type" "xor")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn ""
@@ -3162,14 +3196,16 @@
 })
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
         (zero_extend:GPR
-	     (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
+	     (match_operand:SHORT 1 "nonimmediate_operand" "!u,d,m")))]
   "!TARGET_MIPS16"
   "@
    andi\t%0,%1,<SHORT:mask>
+   andi\t%0,%1,<SHORT:mask>
    l<SHORT:size>u\t%0,%1"
-  [(set_attr "move_type" "andi,load")
+  [(set_attr "move_type" "andi,andi,load")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<GPR:MODE>")])
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e"
@@ -4362,13 +4398,14 @@
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "*mov<mode>_internal"
-  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
-	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,d,e,!u,!u,d,d,ZS,ZU,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
+	(match_operand:IMOVE32 1 "move_operand" "d,J,Yd,Yf,Udb7,ZT,ZS,m,ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+  [(set_attr "move_type" "move,move,const,const,load,load,load,load,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+   (set_attr "compression" "all,micromips,*,*,micromips,micromips,micromips,*,micromips,micromips,*,*,*,*,*,*,*,*,*,*,*,*,*")
    (set_attr "mode" "SI")])
 
 (define_insn "*mov<mode>_mips16"
@@ -5225,9 +5262,9 @@
 })
 
 (define_insn "*<optab><mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
-		       (match_operand:SI 2 "arith_operand" "dI")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(any_shift:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		       (match_operand:SI 2 "arith_operand" "Uib3,dI")))]
   "!TARGET_MIPS16"
 {
   if (CONST_INT_P (operands[2]))
@@ -5237,6 +5274,7 @@
   return "<d><insn>\t%0,%1,%2";
 }
   [(set_attr "type" "shift")
+   (set_attr "compression" "<shift_compression>,none")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*<optab>si3_extend"
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 196638)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -350,12 +350,19 @@
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern bool mips_signed_immediate_p (unsigned HOST_WIDE_INT, int, int);
+extern bool mips_unsigned_immediate_p (unsigned HOST_WIDE_INT, int, int);
+
 extern const char *umips_output_save_restore (bool, rtx);
 extern bool umips_save_restore_pattern_p (bool, rtx);
 extern bool umips_load_store_pair_p (bool, rtx *);
 extern void umips_output_load_store_pair (bool, rtx *);
 extern bool umips_movep_target_p (rtx, rtx);
+
+extern bool umips_lwsp_swsp_address_p (rtx, enum machine_mode);
+extern bool umips_load_store_address_p (rtx, bool, enum machine_mode);
 extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
+
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 196638)
+++ gcc/config/mips/mips.c	(working copy)
@@ -2377,6 +2377,81 @@
   return 0;
 }
 
+/* Return true if X fits within an unsigned field of BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_unsigned_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+  return (x & ((1 << shift) - 1)) == 0 && x < (1 << (shift + bits));
+}
+
+/* Return true if X fits within a signed field of  BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+ x += 1 << (bits + shift - 1);
+ return mips_unsigned_immediate_p (x, bits, shift);
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for any of the short microMIPS LOAD or STORE instructions except LWSP
+   or SWSP.  */
+
+bool
+umips_load_store_address_p (rtx x, bool load, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+  bool ok = mips_classify_address (&addr, x, mode, false)
+	    && addr.type == ADDRESS_REG
+	    && M16_REG_P (REGNO (addr.reg))
+	    && CONST_INT_P (addr.offset);
+
+  if (!ok)
+    return false;
+
+  /* For the LBU16 insn.  */
+  if (load && db4_operand (addr.offset, mode))
+    return true;
+
+  /* For the SB16 insn.  */
+  if (!load && ub4_operand (addr.offset, mode))
+    return true;
+
+  /* For SH16, LHU16, SW16 and LW16 insns.  */
+  return uw4_operand (addr.offset, mode)
+          || uh4_operand (addr.offset, mode);
+
+#if 0
+  if (mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 2)
+      || mips_unsigned_immediate_p (INTVAL (addr.offset), 4, 1))
+    return true;
+
+  if (load && IN_RANGE (INTVAL (addr.offset), -1, 14))
+    return true;
+
+  if (!load && IN_RANGE (INTVAL (addr.offset), 0, 15))
+    return true;
+#endif
+  return false;
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for a microMIPS LWSP or SWSP insn.  */
+
+bool
+umips_lwsp_swsp_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
+	  && uw5_operand (addr.offset, mode));
+}
+
 /* Return true if X is a legitimate address with a 12-bit offset.
    MODE is the mode of the value being accessed.  */
 
@@ -8009,9 +8084,10 @@
       break;
 
     case '!':
-      /* When final_sequence is 0, the delay slot will be a nop.  We can
-	 a 16-bit delay slot for microMIPS.  */
-      if (final_sequence == 0)
+      /* If the delay slot instruction is short, then use the
+	 compact version.  */
+      if (final_sequence == 0
+	  || get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
 	putc ('s', file);
       break;
 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-20 20:15                         ` Moore, Catherine
@ 2013-03-20 21:48                           ` Richard Sandiford
  2013-03-20 22:02                             ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-20 21:48 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> Index: gcc/config/mips/constraints.md
> ===================================================================
> --- gcc/config/mips/constraints.md	(revision 196638)
> +++ gcc/config/mips/constraints.md	(working copy)
> @@ -43,6 +43,9 @@
>  (define_register_constraint "b" "ALL_REGS"
>    "@internal")
>  
> +(define_register_constraint "u" "M16_REGS"
> +  "@internal")
> +
>  ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
>  ;; for details.
>  (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
> @@ -170,6 +173,41 @@
>    (and (match_operand 0 "call_insn_operand")
>         (match_test "CONSTANT_P (op)")))
>  
> +(define_constraint "Udb7"
> +  "@internal
> +   A decremented unsigned constant of 7 bits."
> +  (match_operand 0 "db7_operand"))
> +
> +(define_constraint "Uea4"
> +  "@internal
> +   A microMIPS encoded ADDIUR2 immediate operand."
> +  (match_operand 0 "addiur2_operand"))

I'm still wary of having digits for some "Ue"s and not others,
especially because (as I understand it) ADDIUR2 takes a 3-bit rather
than 4-bit operand.  How about "Ueau" here (= add of "u" register).
For consistency...

> +(define_constraint "Ueim"
> +  "@internal
> +   A microMIPS encoded ADDIUSP operand."
> +  (match_operand 0 "addiusp_operand" ""))

...this could be "Ueas" (= add of stack register).  Redundant "".

> +(define_constraint "Uesp"
> +  "@internal
> +   A microMIPS encoded ADDIUR1SP operand."
> +  (match_operand 0 "addiur1sp_operand" ""))

This is "6 bits zero extended and shifted left twice", so the constraint
should be "Uuw6" and the predicate should be "uw6_operand".  Redundant "".

> +(define_memory_constraint "ZS"
> +  "@internal
> +   A microMIPS memory operand for use with the LWSP/SWSP insns."
> +  (and (match_code "mem")
> +       (match_operand 0 "umips_lwsp_swsp_operand")))
> +
> +(define_memory_constraint "ZT"
> +  "@internal
> +   A microMIPS memory operand for use with the various LOAD insns."
> +  (and (match_code "mem")
> +       (match_operand 0 "umips_load_operand")))
> +
> +(define_memory_constraint "ZU"
> +  "@internal
> +   A microMIPS memory operand for use with the various STORE insns."
> +  (and (match_code "mem")
> +       (match_operand 0 "umips_store_operand")))

As I mentioned before, we need a separate predicate and constraint for
each range.  We can't have things like:

> +  /* For the LBU16 insn.  */
> +  if (load && db4_operand (addr.offset, mode))
> +    return true;
> +
> +  /* For the SB16 insn.  */
> +  if (!load && ub4_operand (addr.offset, mode))
> +    return true;
> +
> +  /* For SH16, LHU16, SW16 and LW16 insns.  */
> +  return uw4_operand (addr.offset, mode)
> +          || uh4_operand (addr.offset, mode);

because this allows SH16 to be ub4_operand, uw4_operand or uh4_operand,
and so on.  There needs to be one predicate/constraint pair for ub4_operands,
one for db4_operands, one for uw4_operands and one for uh4_operands.

Please use the function I suggested in my previous reply, in which the
offset predicate is passed in as a function pointer.

> @@ -1131,14 +1151,19 @@
>    "")
>  
>  (define_insn "*add<mode>3"
> -  [(set (match_operand:GPR 0 "register_operand" "=d,d")
> -	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
> -		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
> +  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!ks,d,d,d")
> +	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,0,!ks,!ks,d")
> +		  (match_operand:GPR 2 "arith_operand" "!u,d,Uea4,Usb3,Ueim,Uesp,Q")))]

Hmm, not sure about these alternatives.  Two have the form d/ks/U...
(the last two) and I'm not sure which instruction Usb3 corresponds to.

My guess from the manual would be:

  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!u,!ks,!d,d")
	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,!ks,!ks,0,d")
		  (match_operand:GPR 2 "arith_operand"
		     "!u,d,Ueau,Uuw6,Ueas,Usb4,Q")))]

> @@ -1347,12 +1372,13 @@
>     (set_attr "mode" "<UNITMODE>")])
>  
>  (define_insn "sub<mode>3"
> -  [(set (match_operand:GPR 0 "register_operand" "=d")
> -	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
> -		   (match_operand:GPR 2 "register_operand" "d")))]
> +  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
> +	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
> +		   (match_operand:GPR 2 "register_operand" "!u,d")))]
>    ""
> -  "<d>subu\t%0,%1,%2"
> +{ return "<d>subu\t%0,%1,%2"; }

The change to the last line shouldn't be needed.  (Plain "..."
is better than { return "...."; } where possible, because the
generator doesn't need to create a separate output function.)

> @@ -2878,9 +2905,9 @@
>  ;;  register =op1                      x
>  
>  (define_insn "*and<mode>3"
> -  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
> -	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
> -		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
> +  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
> +	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
> +		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
>    "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
>  {
>    int len;
> @@ -2897,20 +2924,23 @@
>        operands[1] = gen_lowpart (SImode, operands[1]);
>        return "lwu\t%0,%1";
>      case 3:
> +    case 4:
>        return "andi\t%0,%1,%x2";
> -    case 4:
> +    case 5:
>        len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
>        operands[2] = GEN_INT (len);
>        return "<d>ext\t%0,%1,0,%2";
> -    case 5:
> +    case 6:
>        return "#";
> -    case 6:
> +    case 7:
> +    case 8:
>        return "and\t%0,%1,%2";
>      default:
>        gcc_unreachable ();
>      }
>  }
> -  [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
> +  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
> +   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
>     (set_attr "mode" "<MODE>")])

Looks good.

> @@ -4362,13 +4398,14 @@
>  ;; in FP registers (off by default, use -mdebugh to enable).
>  
>  (define_insn "*mov<mode>_internal"
> -  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> -	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
> +  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,d,e,!u,!u,d,d,ZS,ZU,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> +	(match_operand:IMOVE32 1 "move_operand" "d,J,Yd,Yf,Udb7,ZT,ZS,m,ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]

The d <- ZS alternative (the 7th) should be !ks <- ZS instead.

>    "!TARGET_MIPS16
>     && (register_operand (operands[0], <MODE>mode)
>         || reg_or_0_operand (operands[1], <MODE>mode))"
>    { return mips_output_move (operands[0], operands[1]); }
> -  [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
> +  [(set_attr "move_type" "move,move,const,const,load,load,load,load,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")

I think the 5th alternative (!u <- Udb7) should be "const" rather than "load".

> +/* Return true if X fits within a signed field of  BITS bits that is
> +   shifted left SHIFT bits before being used.  */

Too many spaces before "BITS".

> +
> +bool
> +mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
> +{
> + x += 1 << (bits + shift - 1);
> + return mips_unsigned_immediate_p (x, bits, shift);
> +}

Formatting: there should be one extra space of indentantion.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-20 21:48                           ` Richard Sandiford
@ 2013-03-20 22:02                             ` Moore, Catherine
  2013-03-21  8:05                               ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-20 22:02 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 9165 bytes --]

Hi Richard,
I'm sorry for wasting your time.  I accidentally posted an older version of the patch earlier this afternoon.
This is the version that I meant to post and is hopefully a lot closer to what you are looking for.
I named some of the predicates/constraints differently than your current suggestions, but hopefully they will be OK.
Thanks,
Catherine


> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Wednesday, March 20, 2013 5:48 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> > Index: gcc/config/mips/constraints.md
> >
> ==========================================================
> =========
> > --- gcc/config/mips/constraints.md	(revision 196638)
> > +++ gcc/config/mips/constraints.md	(working copy)
> > @@ -43,6 +43,9 @@
> >  (define_register_constraint "b" "ALL_REGS"
> >    "@internal")
> >
> > +(define_register_constraint "u" "M16_REGS"
> > +  "@internal")
> > +
> >  ;; MIPS16 code always calls through a MIPS16 register; see
> > mips_emit_call_insn  ;; for details.
> >  (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS @@ -170,6
> > +173,41 @@
> >    (and (match_operand 0 "call_insn_operand")
> >         (match_test "CONSTANT_P (op)")))
> >
> > +(define_constraint "Udb7"
> > +  "@internal
> > +   A decremented unsigned constant of 7 bits."
> > +  (match_operand 0 "db7_operand"))
> > +
> > +(define_constraint "Uea4"
> > +  "@internal
> > +   A microMIPS encoded ADDIUR2 immediate operand."
> > +  (match_operand 0 "addiur2_operand"))
> 
> I'm still wary of having digits for some "Ue"s and not others, especially
> because (as I understand it) ADDIUR2 takes a 3-bit rather than 4-bit operand.
> How about "Ueau" here (= add of "u" register).
> For consistency...
> 
> > +(define_constraint "Ueim"
> > +  "@internal
> > +   A microMIPS encoded ADDIUSP operand."
> > +  (match_operand 0 "addiusp_operand" ""))
> 
> ...this could be "Ueas" (= add of stack register).  Redundant "".
> 
> > +(define_constraint "Uesp"
> > +  "@internal
> > +   A microMIPS encoded ADDIUR1SP operand."
> > +  (match_operand 0 "addiur1sp_operand" ""))
> 
> This is "6 bits zero extended and shifted left twice", so the constraint should
> be "Uuw6" and the predicate should be "uw6_operand".  Redundant "".
> 
> > +(define_memory_constraint "ZS"
> > +  "@internal
> > +   A microMIPS memory operand for use with the LWSP/SWSP insns."
> > +  (and (match_code "mem")
> > +       (match_operand 0 "umips_lwsp_swsp_operand")))
> > +
> > +(define_memory_constraint "ZT"
> > +  "@internal
> > +   A microMIPS memory operand for use with the various LOAD insns."
> > +  (and (match_code "mem")
> > +       (match_operand 0 "umips_load_operand")))
> > +
> > +(define_memory_constraint "ZU"
> > +  "@internal
> > +   A microMIPS memory operand for use with the various STORE insns."
> > +  (and (match_code "mem")
> > +       (match_operand 0 "umips_store_operand")))
> 
> As I mentioned before, we need a separate predicate and constraint for each
> range.  We can't have things like:
> 
> > +  /* For the LBU16 insn.  */
> > +  if (load && db4_operand (addr.offset, mode))
> > +    return true;
> > +
> > +  /* For the SB16 insn.  */
> > +  if (!load && ub4_operand (addr.offset, mode))
> > +    return true;
> > +
> > +  /* For SH16, LHU16, SW16 and LW16 insns.  */  return uw4_operand
> > + (addr.offset, mode)
> > +          || uh4_operand (addr.offset, mode);
> 
> because this allows SH16 to be ub4_operand, uw4_operand or uh4_operand,
> and so on.  There needs to be one predicate/constraint pair for
> ub4_operands, one for db4_operands, one for uw4_operands and one for
> uh4_operands.
> 
> Please use the function I suggested in my previous reply, in which the offset
> predicate is passed in as a function pointer.
> 
> > @@ -1131,14 +1151,19 @@
> >    "")
> >
> >  (define_insn "*add<mode>3"
> > -  [(set (match_operand:GPR 0 "register_operand" "=d,d")
> > -	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
> > -		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
> > +  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!ks,d,d,d")
> > +	(plus:GPR (match_operand:GPR 1 "register_operand"
> "!u,d,!u,0,!ks,!ks,d")
> > +		  (match_operand:GPR 2 "arith_operand"
> > +"!u,d,Uea4,Usb3,Ueim,Uesp,Q")))]
> 
> Hmm, not sure about these alternatives.  Two have the form d/ks/U...
> (the last two) and I'm not sure which instruction Usb3 corresponds to.
> 
> My guess from the manual would be:
> 
>   [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!u,!ks,!d,d")
> 	(plus:GPR (match_operand:GPR 1 "register_operand"
> "!u,d,!u,!ks,!ks,0,d")
> 		  (match_operand:GPR 2 "arith_operand"
> 		     "!u,d,Ueau,Uuw6,Ueas,Usb4,Q")))]
> 
> > @@ -1347,12 +1372,13 @@
> >     (set_attr "mode" "<UNITMODE>")])
> >
> >  (define_insn "sub<mode>3"
> > -  [(set (match_operand:GPR 0 "register_operand" "=d")
> > -	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
> > -		   (match_operand:GPR 2 "register_operand" "d")))]
> > +  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
> > +	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
> > +		   (match_operand:GPR 2 "register_operand" "!u,d")))]
> >    ""
> > -  "<d>subu\t%0,%1,%2"
> > +{ return "<d>subu\t%0,%1,%2"; }
> 
> The change to the last line shouldn't be needed.  (Plain "..."
> is better than { return "...."; } where possible, because the generator doesn't
> need to create a separate output function.)
> 
> > @@ -2878,9 +2905,9 @@
> >  ;;  register =op1                      x
> >
> >  (define_insn "*and<mode>3"
> > -  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
> > -	(and:GPR (match_operand:GPR 1 "nonimmediate_operand"
> "o,o,W,d,d,d,d")
> > -		 (match_operand:GPR 2 "and_operand"
> "Yb,Yh,Yw,K,Yx,Yw,d")))]
> > +  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
> > +	(and:GPR (match_operand:GPR 1 "nonimmediate_operand"
> "o,o,W,!u,d,d,d,0,d")
> > +		 (match_operand:GPR 2 "and_operand"
> > +"Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
> >    "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1],
> operands[2])"
> >  {
> >    int len;
> > @@ -2897,20 +2924,23 @@
> >        operands[1] = gen_lowpart (SImode, operands[1]);
> >        return "lwu\t%0,%1";
> >      case 3:
> > +    case 4:
> >        return "andi\t%0,%1,%x2";
> > -    case 4:
> > +    case 5:
> >        len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
> >        operands[2] = GEN_INT (len);
> >        return "<d>ext\t%0,%1,0,%2";
> > -    case 5:
> > +    case 6:
> >        return "#";
> > -    case 6:
> > +    case 7:
> > +    case 8:
> >        return "and\t%0,%1,%2";
> >      default:
> >        gcc_unreachable ();
> >      }
> >  }
> > -  [(set_attr "move_type"
> > "load,load,load,andi,ext_ins,shift_shift,logical")
> > +  [(set_attr "move_type"
> "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
> > +   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
> >     (set_attr "mode" "<MODE>")])
> 
> Looks good.
> 
> > @@ -4362,13 +4398,14 @@
> >  ;; in FP registers (off by default, use -mdebugh to enable).
> >
> >  (define_insn "*mov<mode>_internal"
> > -  [(set (match_operand:IMOVE32 0 "nonimmediate_operand"
> "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> > -	(match_operand:IMOVE32 1 "move_operand"
> "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
> > +  [(set (match_operand:IMOVE32 0 "nonimmediate_operand"
> "=d,!u,d,e,!u,!u,d,d,ZS,ZU,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*
> m")
> > +	(match_operand:IMOVE32 1 "move_operand"
> > +"d,J,Yd,Yf,Udb7,ZT,ZS,m,ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B
> > +*C*D,*B*C*D"))]
> 
> The d <- ZS alternative (the 7th) should be !ks <- ZS instead.
> 
> >    "!TARGET_MIPS16
> >     && (register_operand (operands[0], <MODE>mode)
> >         || reg_or_0_operand (operands[1], <MODE>mode))"
> >    { return mips_output_move (operands[0], operands[1]); }
> > -  [(set_attr "move_type"
> > "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,
> > mtc,fpload,mfc,fpstore")
> > +  [(set_attr "move_type"
> > + "move,move,const,const,load,load,load,load,store,store,store,mtc,fpl
> > + oad,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
> 
> I think the 5th alternative (!u <- Udb7) should be "const" rather than "load".
> 
> > +/* Return true if X fits within a signed field of  BITS bits that is
> > +   shifted left SHIFT bits before being used.  */
> 
> Too many spaces before "BITS".
> 
> > +
> > +bool
> > +mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int
> > +shift = 0) {  x += 1 << (bits + shift - 1);  return
> > +mips_unsigned_immediate_p (x, bits, shift); }
> 
> Formatting: there should be one extra space of indentantion.
> 
> Richard

[-- Attachment #2: short-delay-03.20.patch --]
[-- Type: application/octet-stream, Size: 19613 bytes --]

Index: constraints.md
===================================================================
--- constraints.md	(revision 196638)
+++ constraints.md	(working copy)
@@ -43,6 +43,9 @@
 (define_register_constraint "b" "ALL_REGS"
   "@internal")
 
+(define_register_constraint "u" "M16_REGS"
+  "@internal")
+
 ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
 ;; for details.
 (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
@@ -170,6 +173,41 @@
   (and (match_operand 0 "call_insn_operand")
        (match_test "CONSTANT_P (op)")))
 
+(define_constraint "Udb7"
+  "@internal
+   A decremented unsigned constant of 7 bits."
+  (match_operand 0 "db7_operand"))
+
+(define_constraint "Uead"
+  "@internal
+   A microMIPS encoded ADDIUR2 immediate operand."
+  (match_operand 0 "addiur2_operand"))
+  
+(define_constraint "Uean"
+  "@internal
+   A microMIPS encoded andi operand."
+  (match_operand 0 "andi16_operand"))
+
+(define_constraint "Ueim"
+  "@internal
+   A microMIPS encoded ADDIUSP operand."
+  (match_operand 0 "addiusp_operand"))
+
+(define_constraint "Uib3"
+  "@internal
+   An unsigned, incremented three-bit constant."
+  (match_operand 0 "ib3_operand"))
+
+(define_constraint "Uesp"
+  "@internal
+   A microMIPS encoded ADDIUR1SP operand."
+  (match_operand 0 "addiur1sp_operand"))
+
+(define_constraint "Usb3"
+  "@internal
+   A signed three-bit constant."
+  (match_operand 0 "sb3_operand"))
+
 (define_memory_constraint "W"
   "@internal
    A memory address based on a member of @code{BASE_REG_CLASS}.  This is
@@ -257,3 +295,51 @@
  "@internal
   An address valid for loading/storing register exclusive"
  (match_operand 0 "mem_noofs_operand"))
+
+(define_memory_constraint "ZS"
+  "@internal
+   A microMIPS memory operand for use with the LWSP/SWSP insns."
+  (and (match_code "mem")
+       (match_operand 0 "lwsp_swsp_operand")))
+
+(define_memory_constraint "ZT"
+  "@internal
+   A microMIPS memory operand for use with the LW16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "lw16_operand")))
+
+(define_memory_constraint "ZU"
+  "@internal
+   A microMIPS memory operand for use with the SB16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "sb16_operand")))
+
+(define_memory_constraint "ZV"
+  "@internal
+   A microMIPS memory operand for use with the LHU16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "lhu16_operand")))
+
+(define_memory_constraint "ZW"
+  "@internal
+   A microMIPS memory operand for use with the LBU16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "lbu16_operand")))
+
+(define_memory_constraint "ZX"
+  "@internal
+   A microMIPS memory operand for use with the SW16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "sw16_operand")))
+
+(define_memory_constraint "ZY"
+  "@internal
+   A microMIPS memory operand for use with the SH16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "sh16_operand")))
+
+(define_memory_constraint "ZZ"
+  "@internal
+   A microMIPS memory operand for use with the SB16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "sb16_operand")))
Index: predicates.md
===================================================================
--- predicates.md	(revision 196638)
+++ predicates.md	(working copy)
@@ -122,6 +122,103 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "lwsp_swsp_operand"
+  (and (match_code "mem")
+       (match_test "lwsp_swsp_address_p (XEXP (op, 0), mode)")))
+
+(define_predicate "lw16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, uw4_operand)")))
+
+(define_predicate "lhu16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, uh4_operand)")))
+
+(define_predicate "lbu16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, db4_operand)")))
+
+(define_predicate "sw16_operand"
+  (ior (and (match_code "mem")
+       	    (match_test "m16_based_address_p (XEXP (op, 0), mode, uw4_operand)"))
+       (and (match_code "reg")
+	    (match_test "REGNO (op) == GP_REG_FIRST"))))
+
+(define_predicate "sh16_operand"
+  (ior (and (match_code "mem")
+       	    (match_test "m16_based_address_p (XEXP (op, 0), mode, uh4_operand)"))
+       (and (match_code "reg")
+	    (match_test "REGNO (op) == GP_REG_FIRST"))))
+
+(define_predicate "sb16_operand"
+  (ior (and (match_code "mem")
+       	    (match_test "m16_based_address_p (XEXP (op, 0), mode, ub4_operand)"))
+       (and (match_code "reg")
+	    (match_test "REGNO (op) == GP_REG_FIRST"))))
+
+(define_predicate "db4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 4, 0)")))
+
+(define_predicate "db7_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7, 0)")))
+
+(define_predicate "ib3_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 3, 0)")))
+
+(define_predicate "sb3_operand"
+  (and (match_code "const_int")
+       (match_test "mips_signed_immediate_p (INTVAL (op), 3, 0)")))
+
+(define_predicate "ub4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "uh4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 1)")))
+
+(define_predicate "uw4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 2)")))
+
+(define_predicate "uw5_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 5, 2)")))
+
+(define_predicate "addiur1sp_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 8, 2)")))
+
+(define_predicate "addiur2_operand"
+  (and (match_code "const_int")
+	(ior (match_test "INTVAL (op) == -1")
+	     (match_test "INTVAL (op) == 1")
+	     (match_test "INTVAL (op) == 4")
+	     (match_test "INTVAL (op) == 8")
+	     (match_test "INTVAL (op) == 12")
+	     (match_test "INTVAL (op) == 16")
+	     (match_test "INTVAL (op) == 20")
+	     (match_test "INTVAL (op) == 24"))))
+
+(define_predicate "addiusp_operand"
+  (and (match_code "const_int")
+       (ior (match_test "(IN_RANGE (INTVAL (op), 2, 257))")
+	    (match_test "(IN_RANGE (INTVAL (op), -258, -3))"))))
+
+(define_predicate "andi16_operand"
+  (and (match_code "const_int")
+	(ior (match_test "IN_RANGE (INTVAL (op), 1, 4)")
+	     (match_test "IN_RANGE (INTVAL (op), 7, 8)")
+	     (match_test "IN_RANGE (INTVAL (op), 15, 16)")
+	     (match_test "IN_RANGE (INTVAL (op), 31, 32)")
+	     (match_test "IN_RANGE (INTVAL (op), 63, 64)")
+	     (match_test "INTVAL (op) == 255")
+	     (match_test "INTVAL (op) == 32768")
+	     (match_test "INTVAL (op) == 65535"))))
+
 (define_predicate "movep_src_register"
   (and (match_code "reg")
        (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
Index: mips.md
===================================================================
--- mips.md	(revision 196638)
+++ mips.md	(working copy)
@@ -412,12 +412,28 @@
 		(const_string "yes")
 		(const_string "no")))
 
+(define_attr "compression" "none,all,micromips"
+  (const_string "none"))
+
+(define_attr "enabled" "no,yes"
+  (if_then_else (ior (eq_attr "compression" "all,none")
+		     (and (eq_attr "compression" "micromips")
+	                  (match_test "TARGET_MICROMIPS")))
+	        (const_string "yes")
+	        (const_string "no")))
+  
 ;; Length of instruction in bytes.
 (define_attr "length" ""
    (cond [(and (eq_attr "extended_mips16" "yes")
 	       (match_test "TARGET_MIPS16"))
 	  (const_int 8)
 
+	  (and (ior (eq_attr "compression" "micromips")
+		    (eq_attr "compression" "all"))
+	       (eq_attr "dword_mode" "no")
+	       (match_test "TARGET_MICROMIPS"))
+	  (const_int 2)
+
 	  ;; Direct microMIPS branch instructions have a range of
 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
 	  ;; If a branch is outside this range, we have a choice of two
@@ -964,6 +980,10 @@
 				  (xor "xori")
 				  (and "andi")])
 
+(define_code_attr shift_compression [(ashift "micromips")
+				     (lshiftrt "micromips")
+				     (ashiftrt "none")])
+
 ;; <fcond> is the c.cond.fmt condition associated with a particular code.
 (define_code_attr fcond [(unordered "un")
 			 (uneq "ueq")
@@ -1131,14 +1151,19 @@
   "")
 
 (define_insn "*add<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
-		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!ks,d,d,d")
+	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,0,!ks,!ks,d")
+		  (match_operand:GPR 2 "arith_operand" "!u,d,Uead,Usb3,Ueim,Uesp,Q")))]
   "!TARGET_MIPS16"
-  "@
-    <d>addu\t%0,%1,%2
-    <d>addiu\t%0,%1,%2"
+{
+  if (which_alternative == 0 
+      || which_alternative == 1)
+    return "<d>addu\t%0,%1,%2";
+  else
+    return "<d>addiu\t%0,%1,%2";
+}
   [(set_attr "alu_type" "add")
+   (set_attr "compression" "micromips,*,micromips,micromips,micromips,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*add<mode>3_mips16"
@@ -1347,12 +1372,13 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "sub<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
-		   (match_operand:GPR 2 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		   (match_operand:GPR 2 "register_operand" "!u,d")))]
   ""
-  "<d>subu\t%0,%1,%2"
+{ return "<d>subu\t%0,%1,%2"; }
   [(set_attr "alu_type" "sub")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*subsi3_extended"
@@ -2828,8 +2854,8 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "one_cmpl<mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(not:GPR (match_operand:GPR 1 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(not:GPR (match_operand:GPR 1 "register_operand" "!u,d")))]
   ""
 {
   if (TARGET_MIPS16)
@@ -2838,6 +2864,7 @@
     return "nor\t%0,%.,%1";
 }
   [(set_attr "alu_type" "not")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 \f
 ;;
@@ -2878,9 +2905,9 @@
 ;;  register =op1                      x
 
 (define_insn "*and<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
-	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
-		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
+	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
+		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
   "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
 {
   int len;
@@ -2897,20 +2924,23 @@
       operands[1] = gen_lowpart (SImode, operands[1]);
       return "lwu\t%0,%1";
     case 3:
+    case 4:
       return "andi\t%0,%1,%x2";
-    case 4:
+    case 5:
       len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
       operands[2] = GEN_INT (len);
       return "<d>ext\t%0,%1,0,%2";
-    case 5:
+    case 6:
       return "#";
-    case 6:
+    case 7:
+    case 8:
       return "and\t%0,%1,%2";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
+  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
+   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*and<mode>3_mips16"
@@ -2952,14 +2982,16 @@
 })
 
 (define_insn "*ior<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(ior:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    or\t%0,%1,%2
+   or\t%0,%1,%2
    ori\t%0,%1,%x2"
   [(set_attr "alu_type" "or")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*ior<mode>3_mips16"
@@ -2979,14 +3011,16 @@
   "")
 
 (define_insn ""
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    xor\t%0,%1,%2
+   xor\t%0,%1,%2
    xori\t%0,%1,%x2"
   [(set_attr "alu_type" "xor")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn ""
@@ -3162,14 +3196,16 @@
 })
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
         (zero_extend:GPR
-	     (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
+	     (match_operand:SHORT 1 "nonimmediate_operand" "!u,d,m")))]
   "!TARGET_MIPS16"
   "@
    andi\t%0,%1,<SHORT:mask>
+   andi\t%0,%1,<SHORT:mask>
    l<SHORT:size>u\t%0,%1"
-  [(set_attr "move_type" "andi,load")
+  [(set_attr "move_type" "andi,andi,load")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<GPR:MODE>")])
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e"
@@ -4362,13 +4398,14 @@
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "*mov<mode>_internal"
-  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
-	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,d,e,!u,!u,d,d,ZS,ZU,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
+	(match_operand:IMOVE32 1 "move_operand" "d,J,Yd,Yf,Udb7,ZT,ZS,m,ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+  [(set_attr "move_type" "move,move,const,const,load,load,load,load,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+   (set_attr "compression" "all,micromips,*,*,micromips,micromips,micromips,*,micromips,micromips,*,*,*,*,*,*,*,*,*,*,*,*,*")
    (set_attr "mode" "SI")])
 
 (define_insn "*mov<mode>_mips16"
@@ -5225,9 +5262,9 @@
 })
 
 (define_insn "*<optab><mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
-		       (match_operand:SI 2 "arith_operand" "dI")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(any_shift:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		       (match_operand:SI 2 "arith_operand" "Uib3,dI")))]
   "!TARGET_MIPS16"
 {
   if (CONST_INT_P (operands[2]))
@@ -5237,6 +5274,7 @@
   return "<d><insn>\t%0,%1,%2";
 }
   [(set_attr "type" "shift")
+   (set_attr "compression" "<shift_compression>,none")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*<optab>si3_extend"
Index: mips-protos.h
===================================================================
--- mips-protos.h	(revision 196638)
+++ mips-protos.h	(working copy)
@@ -350,12 +350,16 @@
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern bool mips_signed_immediate_p (unsigned HOST_WIDE_INT, int, int);
+extern bool mips_unsigned_immediate_p (unsigned HOST_WIDE_INT, int, int);
 extern const char *umips_output_save_restore (bool, rtx);
 extern bool umips_save_restore_pattern_p (bool, rtx);
 extern bool umips_load_store_pair_p (bool, rtx *);
 extern void umips_output_load_store_pair (bool, rtx *);
 extern bool umips_movep_target_p (rtx, rtx);
 extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
+extern bool lwsp_swsp_address_p (rtx, enum machine_mode);
+extern bool m16_based_address_p (rtx, enum machine_mode, int (*)(rtx_def*, machine_mode)); 
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: mips.c
===================================================================
--- mips.c	(revision 196638)
+++ mips.c	(working copy)
@@ -2377,6 +2377,56 @@
   return 0;
 }
 
+/* Return true if X fits within an unsigned field of BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_unsigned_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+  return (x & ((1 << shift) - 1)) == 0 && x < ((unsigned) 1 << (shift + bits));
+}
+
+/* Return true if X fits within a signed field of  BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+ x += 1 << (bits + shift - 1);
+ return mips_unsigned_immediate_p (x, bits, shift);
+}
+
+/* Return true if X is legitimate for accessing values of mode MODE,
+   if it is based on a MIPS16 register, and if the offset satisfies
+   OFFSET_PREDICATE.  */
+
+bool
+m16_based_address_p (rtx x, enum machine_mode mode,
+		     insn_operand_predicate_fn offset_predicate)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && M16_REG_P (REGNO (addr.reg))
+	  && offset_predicate (addr.offset, mode));
+}
+
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for a microMIPS LWSP or SWSP insn.  */
+
+bool
+lwsp_swsp_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
+	  && uw5_operand (addr.offset, mode));
+}
+
 /* Return true if X is a legitimate address with a 12-bit offset.
    MODE is the mode of the value being accessed.  */
 
@@ -8009,9 +8059,10 @@
       break;
 
     case '!':
-      /* When final_sequence is 0, the delay slot will be a nop.  We can
-	 a 16-bit delay slot for microMIPS.  */
-      if (final_sequence == 0)
+      /* If the delay slot instruction is short, then use the
+	 compact version.  */
+      if (final_sequence == 0
+	  || get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
 	putc ('s', file);
       break;
 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-20 22:02                             ` Moore, Catherine
@ 2013-03-21  8:05                               ` Richard Sandiford
  2013-03-21 23:04                                 ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-21  8:05 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> I'm sorry for wasting your time.  I accidentally posted an older version
> of the patch earlier this afternoon.
> This is the version that I meant to post and is hopefully a lot closer
> to what you are looking for.
> I named some of the predicates/constraints differently than your current
> suggestions, but hopefully they will be OK.

Yeah, that's fine.

I'll fold my comments from yesterday into the reply to this patch.

> Index: constraints.md
> ===================================================================
> --- constraints.md	(revision 196638)
> +++ constraints.md	(working copy)
> @@ -43,6 +43,9 @@
>  (define_register_constraint "b" "ALL_REGS"
>    "@internal")
>  
> +(define_register_constraint "u" "M16_REGS"
> +  "@internal")
> +
>  ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
>  ;; for details.
>  (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
> @@ -170,6 +173,41 @@
>    (and (match_operand 0 "call_insn_operand")
>         (match_test "CONSTANT_P (op)")))
>  
> +(define_constraint "Udb7"
> +  "@internal
> +   A decremented unsigned constant of 7 bits."
> +  (match_operand 0 "db7_operand"))
> +
> +(define_constraint "Uead"
> +  "@internal
> +   A microMIPS encoded ADDIUR2 immediate operand."
> +  (match_operand 0 "addiur2_operand"))
> +  
> +(define_constraint "Uean"
> +  "@internal
> +   A microMIPS encoded andi operand."
> +  (match_operand 0 "andi16_operand"))

s/andi/ANDI/

> +(define_constraint "Uesp"
> +  "@internal
> +   A microMIPS encoded ADDIUR1SP operand."
> +  (match_operand 0 "addiur1sp_operand"))

This is "6 bits zero extended and shifted left twice", so the constraint
should be "Uuw6" and the predicate should be "uw6_operand".  Redundant "".

That frees up "Uesp" for something else, so it might be worth using "Uesp"
(instead of "Ueim") for ADDIUSP.

> +(define_memory_constraint "ZS"
> +  "@internal
> +   A microMIPS memory operand for use with the LWSP/SWSP insns."
> +  (and (match_code "mem")
> +       (match_operand 0 "lwsp_swsp_operand")))
> +
> +(define_memory_constraint "ZT"
> +  "@internal
> +   A microMIPS memory operand for use with the LW16 insn."
> +  (and (match_code "mem")
> +       (match_operand 0 "lw16_operand")))

As with LWSP/SWSP, we shouldn't need to split the LW16 and SW16 cases.
One constraint is enough for both.  We only need different constraints
if the offsets have different ranges.  I think that means one for
LW16/SW16, one for LH16/SH16, one for LB16 and one for SB16.

> +(define_predicate "sw16_operand"
> +  (ior (and (match_code "mem")
> +       	    (match_test "m16_based_address_p (XEXP (op, 0), mode, uw4_operand)"))
> +       (and (match_code "reg")
> +	    (match_test "REGNO (op) == GP_REG_FIRST"))))

I don't understand the "reg" case.  The operand is used to match the
destination of a store, so it really should be a "mem" in all cases.
Same for the other stores.

> +(define_predicate "db4_operand"
> +  (and (match_code "const_int")
> +       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 4, 0)")))

+1 rather than -1.

> +(define_predicate "addiur1sp_operand"
> +  (and (match_code "const_int")
> +       (match_test "mips_unsigned_immediate_p (INTVAL (op), 8, 2)")))

Watch out when renaming this to uw6_operand.  It should be "6, 2" rather
than "8, 2".

> @@ -1131,14 +1151,19 @@
>    "")
>  
>  (define_insn "*add<mode>3"
> -  [(set (match_operand:GPR 0 "register_operand" "=d,d")
> -	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
> -		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
> +  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!ks,d,d,d")
> +	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,0,!ks,!ks,d")
> +		  (match_operand:GPR 2 "arith_operand" "!u,d,Uead,Usb3,Ueim,Uesp,Q")))]

Hmm, not sure about these alternatives.  Two have the form d/ks/U...
(the last two) and I'm not sure which instruction Usb3 corresponds to.

My guess from the manual would be:

  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!u,!ks,!d,d")
	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,!ks,!ks,0,d")
		  (match_operand:GPR 2 "arith_operand"
		     "!u,d,Uead,Uuw6,Ueim,Usb4,Q")))]

> @@ -1347,12 +1372,13 @@
>     (set_attr "mode" "<UNITMODE>")])
>  
>  (define_insn "sub<mode>3"
> -  [(set (match_operand:GPR 0 "register_operand" "=d")
> -	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
> -		   (match_operand:GPR 2 "register_operand" "d")))]
> +  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
> +	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
> +		   (match_operand:GPR 2 "register_operand" "!u,d")))]
>    ""
> -  "<d>subu\t%0,%1,%2"
> +{ return "<d>subu\t%0,%1,%2"; }

The change to the last line shouldn't be needed.  (Plain "..."
is better than { return "...."; } where possible, because the
generator doesn't need to create a separate output function.)

> @@ -4362,13 +4398,14 @@
>  ;; in FP registers (off by default, use -mdebugh to enable).
>  
>  (define_insn "*mov<mode>_internal"
> -  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> -	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
> +  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,d,e,!u,!u,d,d,ZS,ZU,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> +	(match_operand:IMOVE32 1 "move_operand" "d,J,Yd,Yf,Udb7,ZT,ZS,m,ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]

The d <- ZS alternative (the 7th) should be !ks <- ZS instead.

>    "!TARGET_MIPS16
>     && (register_operand (operands[0], <MODE>mode)
>         || reg_or_0_operand (operands[1], <MODE>mode))"
>    { return mips_output_move (operands[0], operands[1]); }
> -  [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
> +  [(set_attr "move_type" "move,move,const,const,load,load,load,load,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")

I think the 5th alternative (!u <- Udb7) should be "const" rather than "load".

> +/* Return true if X fits within a signed field of  BITS bits that is
> +   shifted left SHIFT bits before being used.  */

Too many spaces before "BITS".

> +bool
> +mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
> +{
> + x += 1 << (bits + shift - 1);
> + return mips_unsigned_immediate_p (x, bits, shift);
> +}

Formatting: there should be one extra space of indentantion.

> +}
> +
> +
> +/* Return true if X is a legitimate address that conforms to the requirements
> +   for a microMIPS LWSP or SWSP insn.  */

Only one blank line rather than two.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-21  8:05                               ` Richard Sandiford
@ 2013-03-21 23:04                                 ` Moore, Catherine
  2013-03-22  0:05                                   ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-21 23:04 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 8101 bytes --]



> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Thursday, March 21, 2013 4:05 AM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> > I'm sorry for wasting your time.  I accidentally posted an older
> > version of the patch earlier this afternoon.
> > This is the version that I meant to post and is hopefully a lot closer
> > to what you are looking for.
> > I named some of the predicates/constraints differently than your
> > current suggestions, but hopefully they will be OK.
> 
> Yeah, that's fine.
> 
> I'll fold my comments from yesterday into the reply to this patch.

Okay, thanks.  Updated patch attached.  I'm still testing, but initial results are good.
Catherine

> 
> > Index: constraints.md
> >
> ==========================================================
> =========
> > --- constraints.md	(revision 196638)
> > +++ constraints.md	(working copy)
> > @@ -43,6 +43,9 @@
> >  (define_register_constraint "b" "ALL_REGS"
> >    "@internal")
> >
> > +(define_register_constraint "u" "M16_REGS"
> > +  "@internal")
> > +
> >  ;; MIPS16 code always calls through a MIPS16 register; see
> > mips_emit_call_insn  ;; for details.
> >  (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS @@ -170,6
> > +173,41 @@
> >    (and (match_operand 0 "call_insn_operand")
> >         (match_test "CONSTANT_P (op)")))
> >
> > +(define_constraint "Udb7"
> > +  "@internal
> > +   A decremented unsigned constant of 7 bits."
> > +  (match_operand 0 "db7_operand"))
> > +
> > +(define_constraint "Uead"
> > +  "@internal
> > +   A microMIPS encoded ADDIUR2 immediate operand."
> > +  (match_operand 0 "addiur2_operand"))
> > +
> > +(define_constraint "Uean"
> > +  "@internal
> > +   A microMIPS encoded andi operand."
> > +  (match_operand 0 "andi16_operand"))
> 
> s/andi/ANDI/
> 
> > +(define_constraint "Uesp"
> > +  "@internal
> > +   A microMIPS encoded ADDIUR1SP operand."
> > +  (match_operand 0 "addiur1sp_operand"))
> 
> This is "6 bits zero extended and shifted left twice", so the constraint should
> be "Uuw6" and the predicate should be "uw6_operand".  Redundant "".

I couldn' t find the redundant "".  I'm sure you'll let me know if it's still there.
> 
> That frees up "Uesp" for something else, so it might be worth using "Uesp"
> (instead of "Ueim") for ADDIUSP.
> 
> > +(define_memory_constraint "ZS"
> > +  "@internal
> > +   A microMIPS memory operand for use with the LWSP/SWSP insns."
> > +  (and (match_code "mem")
> > +       (match_operand 0 "lwsp_swsp_operand")))
> > +
> > +(define_memory_constraint "ZT"
> > +  "@internal
> > +   A microMIPS memory operand for use with the LW16 insn."
> > +  (and (match_code "mem")
> > +       (match_operand 0 "lw16_operand")))
> 
> As with LWSP/SWSP, we shouldn't need to split the LW16 and SW16 cases.
> One constraint is enough for both.  We only need different constraints if the
> offsets have different ranges.  I think that means one for LW16/SW16, one
> for LH16/SH16, one for LB16 and one for SB16.
> 
> > +(define_predicate "sw16_operand"
> > +  (ior (and (match_code "mem")
> > +       	    (match_test "m16_based_address_p (XEXP (op, 0), mode,
> uw4_operand)"))
> > +       (and (match_code "reg")
> > +	    (match_test "REGNO (op) == GP_REG_FIRST"))))
> 
> I don't understand the "reg" case.  The operand is used to match the
> destination of a store, so it really should be a "mem" in all cases.
> Same for the other stores.
> 
This was a thinko on my part (and the reason why the LW16/SW16 cases had separate constraints).  Now fixed.

> > +(define_predicate "db4_operand"
> > +  (and (match_code "const_int")
> > +       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 4,
> > +0)")))
> 
> +1 rather than -1.
> 
> > +(define_predicate "addiur1sp_operand"
> > +  (and (match_code "const_int")
> > +       (match_test "mips_unsigned_immediate_p (INTVAL (op), 8, 2)")))
> 
> Watch out when renaming this to uw6_operand.  It should be "6, 2" rather
> than "8, 2".
> 
> > @@ -1131,14 +1151,19 @@
> >    "")
> >
> >  (define_insn "*add<mode>3"
> > -  [(set (match_operand:GPR 0 "register_operand" "=d,d")
> > -	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
> > -		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
> > +  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!ks,d,d,d")
> > +	(plus:GPR (match_operand:GPR 1 "register_operand"
> "!u,d,!u,0,!ks,!ks,d")
> > +		  (match_operand:GPR 2 "arith_operand"
> > +"!u,d,Uead,Usb3,Ueim,Uesp,Q")))]
> 
> Hmm, not sure about these alternatives.  Two have the form d/ks/U...
> (the last two) and I'm not sure which instruction Usb3 corresponds to.
> 
> My guess from the manual would be:
> 
>   [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!u,!ks,!d,d")
> 	(plus:GPR (match_operand:GPR 1 "register_operand"
> "!u,d,!u,!ks,!ks,0,d")
> 		  (match_operand:GPR 2 "arith_operand"
> 		     "!u,d,Uead,Uuw6,Ueim,Usb4,Q")))]

Yes, looks right.  Usb3 should be Usb4.
> 
> > @@ -1347,12 +1372,13 @@
> >     (set_attr "mode" "<UNITMODE>")])
> >
> >  (define_insn "sub<mode>3"
> > -  [(set (match_operand:GPR 0 "register_operand" "=d")
> > -	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
> > -		   (match_operand:GPR 2 "register_operand" "d")))]
> > +  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
> > +	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
> > +		   (match_operand:GPR 2 "register_operand" "!u,d")))]
> >    ""
> > -  "<d>subu\t%0,%1,%2"
> > +{ return "<d>subu\t%0,%1,%2"; }
> 
> The change to the last line shouldn't be needed.  (Plain "..."
> is better than { return "...."; } where possible, because the generator doesn't
> need to create a separate output function.)
> 
> > @@ -4362,13 +4398,14 @@
> >  ;; in FP registers (off by default, use -mdebugh to enable).
> >
> >  (define_insn "*mov<mode>_internal"
> > -  [(set (match_operand:IMOVE32 0 "nonimmediate_operand"
> "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> > -	(match_operand:IMOVE32 1 "move_operand"
> "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
> > +  [(set (match_operand:IMOVE32 0 "nonimmediate_operand"
> "=d,!u,d,e,!u,!u,d,d,ZS,ZU,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*
> m")
> > +	(match_operand:IMOVE32 1 "move_operand"
> > +"d,J,Yd,Yf,Udb7,ZT,ZS,m,ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B
> > +*C*D,*B*C*D"))]
> 
> The d <- ZS alternative (the 7th) should be !ks <- ZS instead.
Now fixed.
Plus the new constraints have been added to the pattern.

> 
> >    "!TARGET_MIPS16
> >     && (register_operand (operands[0], <MODE>mode)
> >         || reg_or_0_operand (operands[1], <MODE>mode))"
> >    { return mips_output_move (operands[0], operands[1]); }
> > -  [(set_attr "move_type"
> > "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,
> > mtc,fpload,mfc,fpstore")
> > +  [(set_attr "move_type"
> > + "move,move,const,const,load,load,load,load,store,store,store,mtc,fpl
> > + oad,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
> 
> I think the 5th alternative (!u <- Udb7) should be "const" rather than "load".
Now fixed.
> 
> > +/* Return true if X fits within a signed field of  BITS bits that is
> > +   shifted left SHIFT bits before being used.  */
> 
> Too many spaces before "BITS".
> 
> > +bool
> > +mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int
> > +shift = 0) {  x += 1 << (bits + shift - 1);  return
> > +mips_unsigned_immediate_p (x, bits, shift); }
> 
> Formatting: there should be one extra space of indentantion.
> 
> > +}
> > +
> > +
> > +/* Return true if X is a legitimate address that conforms to the
> requirements
> > +   for a microMIPS LWSP or SWSP insn.  */
> 
> Only one blank line rather than two.
> 
> Richard

[-- Attachment #2: short-delay-03-21.cl --]
[-- Type: application/octet-stream, Size: 1624 bytes --]

2013-03-21  Catherine Moore  <clm@codesourcery.com>

	* config/mips/constraints.md (u, Udb7 Uead, Uean, Uesp, Uib3,
	Uuw6, Usb4, ZS, ZT, ZU, ZV, ZW): New constraints.
	* config/mip/predicates.md (lwsp_swsp_operand,
	lw16_sw16_operand, lhu16_sh16_operand, lbu16_operand,
	sb16_operand, db4_operand, db7_operand, ib3_operand,
	sb4_operand, ub4_operand, uh4_operand, uw4_operand,
	uw5_operand, uw6_operand, addiur2_operand, addiusp_operand,
	andi16_operand): New predicates.
	* config/mips/mips.md (compression): New attribute.
	(enabled): New attribute.
	(length): Consider compression in computing length.
	(shift_compression): New code attribute.
	(*add<mode>3): New operands. Record compression.
	(sub<mode>3): Likewise.
	(one_cmpl<mode>2): Likewise.
	(*and<mode>3): Likewise.
	(*ior<mode>3): Likewise.
	(unnamed pattern for xor): Likewise.
	(*zero_extend<SHORT:mode><GPR:mode>2): Likewise.
	(*<optab><mode>3): Likewise.
	(*mov<mode>_internal: Likewise.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New.
	(mips_unsigned_immediate_p): New.
	(umips_lwsp_swsp_address_p): New.
	(m16_based_address_p): New.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New prototype.
	(mips_unsigned_immediate_p): New prototype.
	(lwsp_swsp_address_p): New prototype.
	(m16_based_address_p): New prototype.
	* config/mips/mips.c (mips_unsigned_immediate_p): New function.
	(mips_signed_immediate_p): New function.
	(m16_based_address_p): New function.
	(lwsp_swsp_address_p): New function.
	(mips_print_operand_punctuation): Recognize short delay slot insns
	for microMIPS.add<mode>3"

[-- Attachment #3: short-delay-03-21.patch --]
[-- Type: application/octet-stream, Size: 18765 bytes --]

Index: constraints.md
===================================================================
--- constraints.md	(revision 196638)
+++ constraints.md	(working copy)
@@ -43,6 +43,9 @@
 (define_register_constraint "b" "ALL_REGS"
   "@internal")
 
+(define_register_constraint "u" "M16_REGS"
+  "@internal")
+
 ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
 ;; for details.
 (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
@@ -170,6 +173,41 @@
   (and (match_operand 0 "call_insn_operand")
        (match_test "CONSTANT_P (op)")))
 
+(define_constraint "Udb7"
+  "@internal
+   A decremented unsigned constant of 7 bits."
+  (match_operand 0 "db7_operand"))
+
+(define_constraint "Uead"
+  "@internal
+   A microMIPS encoded ADDIUR2 immediate operand."
+  (match_operand 0 "addiur2_operand"))
+  
+(define_constraint "Uean"
+  "@internal
+   A microMIPS encoded ANDI operand."
+  (match_operand 0 "andi16_operand"))
+
+(define_constraint "Uesp"
+  "@internal
+   A microMIPS encoded ADDIUSP operand."
+  (match_operand 0 "addiusp_operand"))
+
+(define_constraint "Uib3"
+  "@internal
+   An unsigned, incremented constant of 3 bits."
+  (match_operand 0 "ib3_operand"))
+
+(define_constraint "Uuw6"
+  "@internal
+   An unsigned constant of 6 bits."
+  (match_operand 0 "uw6_operand"))
+
+(define_constraint "Usb4"
+  "@internal
+   A signed constant of 4 bits."
+  (match_operand 0 "sb4_operand"))
+
 (define_memory_constraint "W"
   "@internal
    A memory address based on a member of @code{BASE_REG_CLASS}.  This is
@@ -257,3 +295,34 @@
  "@internal
   An address valid for loading/storing register exclusive"
  (match_operand 0 "mem_noofs_operand"))
+
+(define_memory_constraint "ZS"
+  "@internal
+   A microMIPS memory operand for use with the LWSP/SWSP insns."
+  (and (match_code "mem")
+       (match_operand 0 "lwsp_swsp_operand")))
+
+(define_memory_constraint "ZT"
+  "@internal
+   A microMIPS memory operand for use with the LW16/SW16 insns."
+  (and (match_code "mem")
+       (match_operand 0 "lw16_sw16_operand")))
+
+(define_memory_constraint "ZU"
+  "@internal
+   A microMIPS memory operand for use with the LHU16/SH16 insns."
+  (and (match_code "mem")
+       (match_operand 0 "lhu16_sh16_operand")))
+
+(define_memory_constraint "ZV"
+  "@internal
+   A microMIPS memory operand for use with the SB16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "sb16_operand")))
+
+(define_memory_constraint "ZW"
+  "@internal
+   A microMIPS memory operand for use with the LBU16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "lbu16_operand")))
+
Index: predicates.md
===================================================================
--- predicates.md	(revision 196638)
+++ predicates.md	(working copy)
@@ -122,6 +122,89 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "lwsp_swsp_operand"
+  (and (match_code "mem")
+       (match_test "lwsp_swsp_address_p (XEXP (op, 0), mode)")))
+
+(define_predicate "lw16_sw16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, uw4_operand)")))
+
+(define_predicate "lhu16_sh16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, uh4_operand)")))
+
+(define_predicate "lbu16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, db4_operand)")))
+
+(define_predicate "sb16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, ub4_operand)")))
+
+(define_predicate "db4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 4, 0)")))
+
+(define_predicate "db7_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7, 0)")))
+
+(define_predicate "ib3_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 3, 0)")))
+
+(define_predicate "sb4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_signed_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "ub4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "uh4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 1)")))
+
+(define_predicate "uw4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 2)")))
+
+(define_predicate "uw5_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 5, 2)")))
+
+(define_predicate "uw6_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 6, 2)")))
+
+(define_predicate "addiur2_operand"
+  (and (match_code "const_int")
+	(ior (match_test "INTVAL (op) == -1")
+	     (match_test "INTVAL (op) == 1")
+	     (match_test "INTVAL (op) == 4")
+	     (match_test "INTVAL (op) == 8")
+	     (match_test "INTVAL (op) == 12")
+	     (match_test "INTVAL (op) == 16")
+	     (match_test "INTVAL (op) == 20")
+	     (match_test "INTVAL (op) == 24"))))
+
+(define_predicate "addiusp_operand"
+  (and (match_code "const_int")
+       (ior (match_test "(IN_RANGE (INTVAL (op), 2, 257))")
+	    (match_test "(IN_RANGE (INTVAL (op), -258, -3))"))))
+
+(define_predicate "andi16_operand"
+  (and (match_code "const_int")
+	(ior (match_test "IN_RANGE (INTVAL (op), 1, 4)")
+	     (match_test "IN_RANGE (INTVAL (op), 7, 8)")
+	     (match_test "IN_RANGE (INTVAL (op), 15, 16)")
+	     (match_test "IN_RANGE (INTVAL (op), 31, 32)")
+	     (match_test "IN_RANGE (INTVAL (op), 63, 64)")
+	     (match_test "INTVAL (op) == 255")
+	     (match_test "INTVAL (op) == 32768")
+	     (match_test "INTVAL (op) == 65535"))))
+
 (define_predicate "movep_src_register"
   (and (match_code "reg")
        (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
Index: mips.md
===================================================================
--- mips.md	(revision 196638)
+++ mips.md	(working copy)
@@ -412,12 +412,28 @@
 		(const_string "yes")
 		(const_string "no")))
 
+(define_attr "compression" "none,all,micromips"
+  (const_string "none"))
+
+(define_attr "enabled" "no,yes"
+  (if_then_else (ior (eq_attr "compression" "all,none")
+		     (and (eq_attr "compression" "micromips")
+	                  (match_test "TARGET_MICROMIPS")))
+	        (const_string "yes")
+	        (const_string "no")))
+  
 ;; Length of instruction in bytes.
 (define_attr "length" ""
    (cond [(and (eq_attr "extended_mips16" "yes")
 	       (match_test "TARGET_MIPS16"))
 	  (const_int 8)
 
+	  (and (ior (eq_attr "compression" "micromips")
+		    (eq_attr "compression" "all"))
+	       (eq_attr "dword_mode" "no")
+	       (match_test "TARGET_MICROMIPS"))
+	  (const_int 2)
+
 	  ;; Direct microMIPS branch instructions have a range of
 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
 	  ;; If a branch is outside this range, we have a choice of two
@@ -964,6 +980,10 @@
 				  (xor "xori")
 				  (and "andi")])
 
+(define_code_attr shift_compression [(ashift "micromips")
+				     (lshiftrt "micromips")
+				     (ashiftrt "none")])
+
 ;; <fcond> is the c.cond.fmt condition associated with a particular code.
 (define_code_attr fcond [(unordered "un")
 			 (uneq "ueq")
@@ -1131,14 +1151,19 @@
   "")
 
 (define_insn "*add<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
-		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!u,!ks,!d,d")
+	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,!ks,!ks,0,d")
+		  (match_operand:GPR 2 "arith_operand" "!u,d,Uead,Uuw6,Uesp,Usb4,Q")))]
   "!TARGET_MIPS16"
-  "@
-    <d>addu\t%0,%1,%2
-    <d>addiu\t%0,%1,%2"
+{
+  if (which_alternative == 0 
+      || which_alternative == 1)
+    return "<d>addu\t%0,%1,%2";
+  else
+    return "<d>addiu\t%0,%1,%2";
+}
   [(set_attr "alu_type" "add")
+   (set_attr "compression" "micromips,*,micromips,micromips,micromips,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*add<mode>3_mips16"
@@ -1347,12 +1372,15 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "sub<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
-		   (match_operand:GPR 2 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		   (match_operand:GPR 2 "register_operand" "!u,d")))]
   ""
-  "<d>subu\t%0,%1,%2"
+  "@
+   <d>subu\t%0,%1,%2
+   <d>subu\t%0,%1,%2"
   [(set_attr "alu_type" "sub")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*subsi3_extended"
@@ -2828,8 +2856,8 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "one_cmpl<mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(not:GPR (match_operand:GPR 1 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(not:GPR (match_operand:GPR 1 "register_operand" "!u,d")))]
   ""
 {
   if (TARGET_MIPS16)
@@ -2838,6 +2866,7 @@
     return "nor\t%0,%.,%1";
 }
   [(set_attr "alu_type" "not")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 \f
 ;;
@@ -2878,9 +2907,9 @@
 ;;  register =op1                      x
 
 (define_insn "*and<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
-	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
-		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
+	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
+		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
   "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
 {
   int len;
@@ -2897,20 +2926,23 @@
       operands[1] = gen_lowpart (SImode, operands[1]);
       return "lwu\t%0,%1";
     case 3:
+    case 4:
       return "andi\t%0,%1,%x2";
-    case 4:
+    case 5:
       len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
       operands[2] = GEN_INT (len);
       return "<d>ext\t%0,%1,0,%2";
-    case 5:
+    case 6:
       return "#";
-    case 6:
+    case 7:
+    case 8:
       return "and\t%0,%1,%2";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
+  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
+   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*and<mode>3_mips16"
@@ -2952,14 +2984,16 @@
 })
 
 (define_insn "*ior<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(ior:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    or\t%0,%1,%2
+   or\t%0,%1,%2
    ori\t%0,%1,%x2"
   [(set_attr "alu_type" "or")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*ior<mode>3_mips16"
@@ -2979,14 +3013,16 @@
   "")
 
 (define_insn ""
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    xor\t%0,%1,%2
+   xor\t%0,%1,%2
    xori\t%0,%1,%x2"
   [(set_attr "alu_type" "xor")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn ""
@@ -3162,14 +3198,16 @@
 })
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
         (zero_extend:GPR
-	     (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
+	     (match_operand:SHORT 1 "nonimmediate_operand" "!u,d,m")))]
   "!TARGET_MIPS16"
   "@
    andi\t%0,%1,<SHORT:mask>
+   andi\t%0,%1,<SHORT:mask>
    l<SHORT:size>u\t%0,%1"
-  [(set_attr "move_type" "andi,load")
+  [(set_attr "move_type" "andi,andi,load")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<GPR:MODE>")])
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e"
@@ -4362,13 +4400,14 @@
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "*mov<mode>_internal"
-  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
-	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,d,e,!u,!u,!u,!u,!ks,d,ZS,ZV,ZU,ZT,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
+	(match_operand:IMOVE32 1 "move_operand" "d,J,Yd,Yf,Udb7,ZW,ZU,ZT,ZS,m,!ks,!u,!u,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+  [(set_attr "move_type" "move,move,const,const,const,load,load,load,load,load,store,store,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+   (set_attr "compression" "all,micromips,*,*,micromips,micromips,micromips,micromips,micromips,*,micromips,micromips,micromips,micromips,*,*,*,*,*,*,*,*,*,*,*,*,*")
    (set_attr "mode" "SI")])
 
 (define_insn "*mov<mode>_mips16"
@@ -5225,9 +5264,9 @@
 })
 
 (define_insn "*<optab><mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
-		       (match_operand:SI 2 "arith_operand" "dI")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(any_shift:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		       (match_operand:SI 2 "arith_operand" "Uib3,dI")))]
   "!TARGET_MIPS16"
 {
   if (CONST_INT_P (operands[2]))
@@ -5237,6 +5276,7 @@
   return "<d><insn>\t%0,%1,%2";
 }
   [(set_attr "type" "shift")
+   (set_attr "compression" "<shift_compression>,none")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*<optab>si3_extend"
Index: mips-protos.h
===================================================================
--- mips-protos.h	(revision 196638)
+++ mips-protos.h	(working copy)
@@ -350,12 +350,16 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern bool mips_signed_immediate_p (unsigned HOST_WIDE_INT, int, int);
+extern bool mips_unsigned_immediate_p (unsigned HOST_WIDE_INT, int, int);
 extern const char *umips_output_save_restore (bool, rtx);
 extern bool umips_save_restore_pattern_p (bool, rtx);
 extern bool umips_load_store_pair_p (bool, rtx *);
 extern void umips_output_load_store_pair (bool, rtx *);
 extern bool umips_movep_target_p (rtx, rtx);
 extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
+extern bool lwsp_swsp_address_p (rtx, enum machine_mode);
+extern bool m16_based_address_p (rtx, enum machine_mode, int (*)(rtx_def*, machine_mode)); 
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: mips.c
===================================================================
--- mips.c	(revision 196638)
+++ mips.c	(working copy)
@@ -2377,6 +2377,55 @@ mips_address_insns (rtx x, enum machine_mode mode,
   return 0;
 }
 
+/* Return true if X fits within an unsigned field of BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_unsigned_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+  return (x & ((1 << shift) - 1)) == 0 && x < ((unsigned) 1 << (shift + bits));
+}
+
+/* Return true if X fits within a signed field of BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+  x += 1 << (bits + shift - 1);
+  return mips_unsigned_immediate_p (x, bits, shift);
+}
+
+/* Return true if X is legitimate for accessing values of mode MODE,
+   if it is based on a MIPS16 register, and if the offset satisfies
+   OFFSET_PREDICATE.  */
+
+bool
+m16_based_address_p (rtx x, enum machine_mode mode,
+		     insn_operand_predicate_fn offset_predicate)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && M16_REG_P (REGNO (addr.reg))
+	  && offset_predicate (addr.offset, mode));
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for a microMIPS LWSP or SWSP insn.  */
+
+bool
+lwsp_swsp_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
+	  && uw5_operand (addr.offset, mode));
+}
+
 /* Return true if X is a legitimate address with a 12-bit offset.
    MODE is the mode of the value being accessed.  */
 
@@ -8009,9 +8058,10 @@ mips_print_operand_punctuation (FILE *file, int ch
       break;
 
     case '!':
-      /* When final_sequence is 0, the delay slot will be a nop.  We can
-	 a 16-bit delay slot for microMIPS.  */
-      if (final_sequence == 0)
+      /* If the delay slot instruction is short, then use the
+	 compact version.  */
+      if (final_sequence == 0
+	  || get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
 	putc ('s', file);
       break;
 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-21 23:04                                 ` Moore, Catherine
@ 2013-03-22  0:05                                   ` Richard Sandiford
  2013-03-22 18:31                                     ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-22  0:05 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

Thanks, this is almost there now.  It was only the problem with the new
version of the move pattern (see below) that stopped this from being
"OK with...".  The next round should be a formality though.

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> +(define_constraint "Uuw6"
> +  "@internal
> +   An unsigned constant of 6 bits."
> +  (match_operand 0 "uw6_operand"))

", shifted left two places".

> +	  (and (ior (eq_attr "compression" "micromips")
> +		    (eq_attr "compression" "all"))

Please use (eq_attr "compression" "micromips,all") instead.

>  (define_insn "sub<mode>3"
> -  [(set (match_operand:GPR 0 "register_operand" "=d")
> -	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
> -		   (match_operand:GPR 2 "register_operand" "d")))]
> +  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
> +	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
> +		   (match_operand:GPR 2 "register_operand" "!u,d")))]
>    ""
> -  "<d>subu\t%0,%1,%2"
> +  "@
> +   <d>subu\t%0,%1,%2
> +   <d>subu\t%0,%1,%2"

This change isn't needed.  It's OK (and IMO better) to keep a single asm
string when the string is the same for all alternatives.

> @@ -4362,13 +4400,14 @@
>  ;; in FP registers (off by default, use -mdebugh to enable).
>  
>  (define_insn "*mov<mode>_internal"
> -  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> -	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
> +  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,d,e,!u,!u,!u,!u,!ks,d,ZS,ZV,ZU,ZT,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> +	(match_operand:IMOVE32 1 "move_operand" "d,J,Yd,Yf,Udb7,ZW,ZU,ZT,ZS,m,!ks,!u,!u,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]

This pattern is only for 32-bit moves, so should only use ZS and ZT.
(I don't mind keeping the definitions of the ZU...ZW constraints in this
patch -- even though they start out unused -- because it's obvious they'll
be needed eventually.  I'd prefer leaving the 8-bit and 16-move patterns
themselves to a different patch though.)

Sorry, I should have noticed last time, but alternative 5 (u<-Udb7) should
come before alternative 3 (d<-Yd), because d<-Yd includes everything that
u<-Udb7 does.

> +extern bool m16_based_address_p (rtx, enum machine_mode, int (*)(rtx_def*, machine_mode)); 

Line too long: should be split after the first enum machine_mode.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-22  0:05                                   ` Richard Sandiford
@ 2013-03-22 18:31                                     ` Moore, Catherine
  2013-03-23  9:07                                       ` Richard Sandiford
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-03-22 18:31 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: gcc-patches, Rozycki, Maciej

[-- Attachment #1: Type: text/plain, Size: 3024 bytes --]



> -----Original Message-----
> From: Richard Sandiford [mailto:rdsandiford@googlemail.com]
> Sent: Thursday, March 21, 2013 8:04 PM
> To: Moore, Catherine
> Cc: gcc-patches@gcc.gnu.org; Rozycki, Maciej
> Subject: Re: FW: [PATCH] [MIPS] microMIPS gcc support
> 
> Thanks, this is almost there now.  It was only the problem with the new
> version of the move pattern (see below) that stopped this from being "OK
> with...".  The next round should be a formality though.
> 
Okay, modifications now made and patch attached.

> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> > +(define_constraint "Uuw6"
> > +  "@internal
> > +   An unsigned constant of 6 bits."
> > +  (match_operand 0 "uw6_operand"))
> 
> ", shifted left two places".
> 
> > +	  (and (ior (eq_attr "compression" "micromips")
> > +		    (eq_attr "compression" "all"))
> 
> Please use (eq_attr "compression" "micromips,all") instead.
> 
> >  (define_insn "sub<mode>3"
> > -  [(set (match_operand:GPR 0 "register_operand" "=d")
> > -	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
> > -		   (match_operand:GPR 2 "register_operand" "d")))]
> > +  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
> > +	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
> > +		   (match_operand:GPR 2 "register_operand" "!u,d")))]
> >    ""
> > -  "<d>subu\t%0,%1,%2"
> > +  "@
> > +   <d>subu\t%0,%1,%2
> > +   <d>subu\t%0,%1,%2"
> 
> This change isn't needed.  It's OK (and IMO better) to keep a single asm string
> when the string is the same for all alternatives.
> 
> > @@ -4362,13 +4400,14 @@
> >  ;; in FP registers (off by default, use -mdebugh to enable).
> >
> >  (define_insn "*mov<mode>_internal"
> > -  [(set (match_operand:IMOVE32 0 "nonimmediate_operand"
> "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
> > -	(match_operand:IMOVE32 1 "move_operand"
> "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
> > +  [(set (match_operand:IMOVE32 0 "nonimmediate_operand"
> "=d,!u,d,e,!u,!u,!u,!u,!ks,d,ZS,ZV,ZU,ZT,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,
> *B*C*D,*d,*m")
> > +	(match_operand:IMOVE32 1 "move_operand"
> > +"d,J,Yd,Yf,Udb7,ZW,ZU,ZT,ZS,m,!ks,!u,!u,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*
> > +d,*a,*d,*m,*B*C*D,*B*C*D"))]
> 
> This pattern is only for 32-bit moves, so should only use ZS and ZT.
> (I don't mind keeping the definitions of the ZU...ZW constraints in this patch -
> - even though they start out unused -- because it's obvious they'll be needed
> eventually.  I'd prefer leaving the 8-bit and 16-move patterns themselves to a
> different patch though.)
> 
> Sorry, I should have noticed last time, but alternative 5 (u<-Udb7) should
> come before alternative 3 (d<-Yd), because d<-Yd includes everything that
> u<-Udb7 does.
> 
> > +extern bool m16_based_address_p (rtx, enum machine_mode, int
> > +(*)(rtx_def*, machine_mode));
> 
> Line too long: should be split after the first enum machine_mode.
> 
> Thanks,
> Richard

[-- Attachment #2: short-delay-03-22.cl --]
[-- Type: application/octet-stream, Size: 1624 bytes --]

2013-03-21  Catherine Moore  <clm@codesourcery.com>

	* config/mips/constraints.md (u, Udb7 Uead, Uean, Uesp, Uib3,
	Uuw6, Usb4, ZS, ZT, ZU, ZV, ZW): New constraints.
	* config/mip/predicates.md (lwsp_swsp_operand,
	lw16_sw16_operand, lhu16_sh16_operand, lbu16_operand,
	sb16_operand, db4_operand, db7_operand, ib3_operand,
	sb4_operand, ub4_operand, uh4_operand, uw4_operand,
	uw5_operand, uw6_operand, addiur2_operand, addiusp_operand,
	andi16_operand): New predicates.
	* config/mips/mips.md (compression): New attribute.
	(enabled): New attribute.
	(length): Consider compression in computing length.
	(shift_compression): New code attribute.
	(*add<mode>3): New operands. Record compression.
	(sub<mode>3): Likewise.
	(one_cmpl<mode>2): Likewise.
	(*and<mode>3): Likewise.
	(*ior<mode>3): Likewise.
	(unnamed pattern for xor): Likewise.
	(*zero_extend<SHORT:mode><GPR:mode>2): Likewise.
	(*<optab><mode>3): Likewise.
	(*mov<mode>_internal: Likewise.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New.
	(mips_unsigned_immediate_p): New.
	(umips_lwsp_swsp_address_p): New.
	(m16_based_address_p): New.
	* config/mips/mips-protos.h (mips_signed_immediate_p): New prototype.
	(mips_unsigned_immediate_p): New prototype.
	(lwsp_swsp_address_p): New prototype.
	(m16_based_address_p): New prototype.
	* config/mips/mips.c (mips_unsigned_immediate_p): New function.
	(mips_signed_immediate_p): New function.
	(m16_based_address_p): New function.
	(lwsp_swsp_address_p): New function.
	(mips_print_operand_punctuation): Recognize short delay slot insns
	for microMIPS.add<mode>3"

[-- Attachment #3: short-delay-03-22.patch --]
[-- Type: application/octet-stream, Size: 18711 bytes --]

Index: gcc/config/mips/constraints.md
===================================================================
--- gcc/config/mips/constraints.md	(revision 196638)
+++ gcc/config/mips/constraints.md	(working copy)
@@ -43,6 +43,9 @@
 (define_register_constraint "b" "ALL_REGS"
   "@internal")
 
+(define_register_constraint "u" "M16_REGS"
+  "@internal")
+
 ;; MIPS16 code always calls through a MIPS16 register; see mips_emit_call_insn
 ;; for details.
 (define_register_constraint "c" "TARGET_MIPS16 ? M16_REGS
@@ -170,6 +173,41 @@
   (and (match_operand 0 "call_insn_operand")
        (match_test "CONSTANT_P (op)")))
 
+(define_constraint "Udb7"
+  "@internal
+   A decremented unsigned constant of 7 bits."
+  (match_operand 0 "db7_operand"))
+
+(define_constraint "Uead"
+  "@internal
+   A microMIPS encoded ADDIUR2 immediate operand."
+  (match_operand 0 "addiur2_operand"))
+  
+(define_constraint "Uean"
+  "@internal
+   A microMIPS encoded ANDI operand."
+  (match_operand 0 "andi16_operand"))
+
+(define_constraint "Uesp"
+  "@internal
+   A microMIPS encoded ADDIUSP operand."
+  (match_operand 0 "addiusp_operand"))
+
+(define_constraint "Uib3"
+  "@internal
+   An unsigned, incremented constant of 3 bits."
+  (match_operand 0 "ib3_operand"))
+
+(define_constraint "Uuw6"
+  "@internal
+   An unsigned constant of 6 bits, shifted left two places."
+  (match_operand 0 "uw6_operand"))
+
+(define_constraint "Usb4"
+  "@internal
+   A signed constant of 4 bits."
+  (match_operand 0 "sb4_operand"))
+
 (define_memory_constraint "W"
   "@internal
    A memory address based on a member of @code{BASE_REG_CLASS}.  This is
@@ -257,3 +295,34 @@
  "@internal
   An address valid for loading/storing register exclusive"
  (match_operand 0 "mem_noofs_operand"))
+
+(define_memory_constraint "ZS"
+  "@internal
+   A microMIPS memory operand for use with the LWSP/SWSP insns."
+  (and (match_code "mem")
+       (match_operand 0 "lwsp_swsp_operand")))
+
+(define_memory_constraint "ZT"
+  "@internal
+   A microMIPS memory operand for use with the LW16/SW16 insns."
+  (and (match_code "mem")
+       (match_operand 0 "lw16_sw16_operand")))
+
+(define_memory_constraint "ZU"
+  "@internal
+   A microMIPS memory operand for use with the LHU16/SH16 insns."
+  (and (match_code "mem")
+       (match_operand 0 "lhu16_sh16_operand")))
+
+(define_memory_constraint "ZV"
+  "@internal
+   A microMIPS memory operand for use with the SB16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "sb16_operand")))
+
+(define_memory_constraint "ZW"
+  "@internal
+   A microMIPS memory operand for use with the LBU16 insn."
+  (and (match_code "mem")
+       (match_operand 0 "lbu16_operand")))
+
Index: gcc/config/mips/predicates.md
===================================================================
--- gcc/config/mips/predicates.md	(revision 196638)
+++ gcc/config/mips/predicates.md	(working copy)
@@ -122,6 +122,89 @@
 		    ? M16_REG_P (REGNO (op))
 		    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "lwsp_swsp_operand"
+  (and (match_code "mem")
+       (match_test "lwsp_swsp_address_p (XEXP (op, 0), mode)")))
+
+(define_predicate "lw16_sw16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, uw4_operand)")))
+
+(define_predicate "lhu16_sh16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, uh4_operand)")))
+
+(define_predicate "lbu16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, db4_operand)")))
+
+(define_predicate "sb16_operand"
+  (and (match_code "mem")
+       (match_test "m16_based_address_p (XEXP (op, 0), mode, ub4_operand)")))
+
+(define_predicate "db4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 4, 0)")))
+
+(define_predicate "db7_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) + 1, 7, 0)")))
+
+(define_predicate "ib3_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op) - 1, 3, 0)")))
+
+(define_predicate "sb4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_signed_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "ub4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 0)")))
+
+(define_predicate "uh4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 1)")))
+
+(define_predicate "uw4_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 4, 2)")))
+
+(define_predicate "uw5_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 5, 2)")))
+
+(define_predicate "uw6_operand"
+  (and (match_code "const_int")
+       (match_test "mips_unsigned_immediate_p (INTVAL (op), 6, 2)")))
+
+(define_predicate "addiur2_operand"
+  (and (match_code "const_int")
+	(ior (match_test "INTVAL (op) == -1")
+	     (match_test "INTVAL (op) == 1")
+	     (match_test "INTVAL (op) == 4")
+	     (match_test "INTVAL (op) == 8")
+	     (match_test "INTVAL (op) == 12")
+	     (match_test "INTVAL (op) == 16")
+	     (match_test "INTVAL (op) == 20")
+	     (match_test "INTVAL (op) == 24"))))
+
+(define_predicate "addiusp_operand"
+  (and (match_code "const_int")
+       (ior (match_test "(IN_RANGE (INTVAL (op), 2, 257))")
+	    (match_test "(IN_RANGE (INTVAL (op), -258, -3))"))))
+
+(define_predicate "andi16_operand"
+  (and (match_code "const_int")
+	(ior (match_test "IN_RANGE (INTVAL (op), 1, 4)")
+	     (match_test "IN_RANGE (INTVAL (op), 7, 8)")
+	     (match_test "IN_RANGE (INTVAL (op), 15, 16)")
+	     (match_test "IN_RANGE (INTVAL (op), 31, 32)")
+	     (match_test "IN_RANGE (INTVAL (op), 63, 64)")
+	     (match_test "INTVAL (op) == 255")
+	     (match_test "INTVAL (op) == 32768")
+	     (match_test "INTVAL (op) == 65535"))))
+
 (define_predicate "movep_src_register"
   (and (match_code "reg")
        (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
Index: gcc/config/mips/mips.md
===================================================================
--- gcc/config/mips/mips.md	(revision 196966)
+++ gcc/config/mips/mips.md	(working copy)
@@ -412,12 +412,27 @@
 		(const_string "yes")
 		(const_string "no")))
 
+(define_attr "compression" "none,all,micromips"
+  (const_string "none"))
+
+(define_attr "enabled" "no,yes"
+  (if_then_else (ior (eq_attr "compression" "all,none")
+		     (and (eq_attr "compression" "micromips")
+	                  (match_test "TARGET_MICROMIPS")))
+	        (const_string "yes")
+	        (const_string "no")))
+  
 ;; Length of instruction in bytes.
 (define_attr "length" ""
    (cond [(and (eq_attr "extended_mips16" "yes")
 	       (match_test "TARGET_MIPS16"))
 	  (const_int 8)
 
+	  (and (eq_attr "compression" "micromips,all")
+	       (eq_attr "dword_mode" "no")
+	       (match_test "TARGET_MICROMIPS"))
+	  (const_int 2)
+
 	  ;; Direct microMIPS branch instructions have a range of
 	  ;; [-0x10000,0xfffe], otherwise the range is [-0x20000,0x1fffc].
 	  ;; If a branch is outside this range, we have a choice of two
@@ -964,6 +979,10 @@
 				  (xor "xori")
 				  (and "andi")])
 
+(define_code_attr shift_compression [(ashift "micromips")
+				     (lshiftrt "micromips")
+				     (ashiftrt "none")])
+
 ;; <fcond> is the c.cond.fmt condition associated with a particular code.
 (define_code_attr fcond [(unordered "un")
 			 (uneq "ueq")
@@ -1131,14 +1150,19 @@
   "")
 
 (define_insn "*add<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(plus:GPR (match_operand:GPR 1 "register_operand" "d,d")
-		  (match_operand:GPR 2 "arith_operand" "d,Q")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,!u,!u,!ks,!d,d")
+	(plus:GPR (match_operand:GPR 1 "register_operand" "!u,d,!u,!ks,!ks,0,d")
+		  (match_operand:GPR 2 "arith_operand" "!u,d,Uead,Uuw6,Uesp,Usb4,Q")))]
   "!TARGET_MIPS16"
-  "@
-    <d>addu\t%0,%1,%2
-    <d>addiu\t%0,%1,%2"
+{
+  if (which_alternative == 0 
+      || which_alternative == 1)
+    return "<d>addu\t%0,%1,%2";
+  else
+    return "<d>addiu\t%0,%1,%2";
+}
   [(set_attr "alu_type" "add")
+   (set_attr "compression" "micromips,*,micromips,micromips,micromips,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*add<mode>3_mips16"
@@ -1347,12 +1371,13 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "sub<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(minus:GPR (match_operand:GPR 1 "register_operand" "d")
-		   (match_operand:GPR 2 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(minus:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		   (match_operand:GPR 2 "register_operand" "!u,d")))]
   ""
   "<d>subu\t%0,%1,%2"
   [(set_attr "alu_type" "sub")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*subsi3_extended"
@@ -2828,8 +2853,8 @@
    (set_attr "mode" "<UNITMODE>")])
 
 (define_insn "one_cmpl<mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(not:GPR (match_operand:GPR 1 "register_operand" "d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(not:GPR (match_operand:GPR 1 "register_operand" "!u,d")))]
   ""
 {
   if (TARGET_MIPS16)
@@ -2838,6 +2863,7 @@
     return "nor\t%0,%.,%1";
 }
   [(set_attr "alu_type" "not")
+   (set_attr "compression" "micromips,*")
    (set_attr "mode" "<MODE>")])
 \f
 ;;
@@ -2878,9 +2904,9 @@
 ;;  register =op1                      x
 
 (define_insn "*and<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,d,d,d,d")
-	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,d,d,d,d")
-		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,K,Yx,Yw,d")))]
+  [(set (match_operand:GPR 0 "register_operand" "=d,d,d,!u,d,d,d,!u,d")
+	(and:GPR (match_operand:GPR 1 "nonimmediate_operand" "o,o,W,!u,d,d,d,0,d")
+		 (match_operand:GPR 2 "and_operand" "Yb,Yh,Yw,Uean,K,Yx,Yw,!u,d")))]
   "!TARGET_MIPS16 && and_operands_ok (<MODE>mode, operands[1], operands[2])"
 {
   int len;
@@ -2897,20 +2923,23 @@
       operands[1] = gen_lowpart (SImode, operands[1]);
       return "lwu\t%0,%1";
     case 3:
+    case 4:
       return "andi\t%0,%1,%x2";
-    case 4:
+    case 5:
       len = low_bitmask_len (<MODE>mode, INTVAL (operands[2]));
       operands[2] = GEN_INT (len);
       return "<d>ext\t%0,%1,0,%2";
-    case 5:
+    case 6:
       return "#";
-    case 6:
+    case 7:
+    case 8:
       return "and\t%0,%1,%2";
     default:
       gcc_unreachable ();
     }
 }
-  [(set_attr "move_type" "load,load,load,andi,ext_ins,shift_shift,logical")
+  [(set_attr "move_type" "load,load,load,andi,andi,ext_ins,shift_shift,logical,logical")
+   (set_attr "compression" "*,*,*,micromips,*,*,*,micromips,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*and<mode>3_mips16"
@@ -2952,14 +2981,16 @@
 })
 
 (define_insn "*ior<mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(ior:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(ior:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    or\t%0,%1,%2
+   or\t%0,%1,%2
    ori\t%0,%1,%x2"
   [(set_attr "alu_type" "or")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*ior<mode>3_mips16"
@@ -2979,14 +3010,16 @@
   "")
 
 (define_insn ""
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
-	(xor:GPR (match_operand:GPR 1 "register_operand" "%d,d")
-		 (match_operand:GPR 2 "uns_arith_operand" "d,K")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
+	(xor:GPR (match_operand:GPR 1 "register_operand" "%0,d,d")
+		 (match_operand:GPR 2 "uns_arith_operand" "!u,d,K")))]
   "!TARGET_MIPS16"
   "@
    xor\t%0,%1,%2
+   xor\t%0,%1,%2
    xori\t%0,%1,%x2"
   [(set_attr "alu_type" "xor")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<MODE>")])
 
 (define_insn ""
@@ -3162,14 +3195,16 @@
 })
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2"
-  [(set (match_operand:GPR 0 "register_operand" "=d,d")
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d,d")
         (zero_extend:GPR
-	     (match_operand:SHORT 1 "nonimmediate_operand" "d,m")))]
+	     (match_operand:SHORT 1 "nonimmediate_operand" "!u,d,m")))]
   "!TARGET_MIPS16"
   "@
    andi\t%0,%1,<SHORT:mask>
+   andi\t%0,%1,<SHORT:mask>
    l<SHORT:size>u\t%0,%1"
-  [(set_attr "move_type" "andi,load")
+  [(set_attr "move_type" "andi,andi,load")
+   (set_attr "compression" "micromips,*,*")
    (set_attr "mode" "<GPR:MODE>")])
 
 (define_insn "*zero_extend<SHORT:mode><GPR:mode>2_mips16e"
@@ -4362,13 +4397,14 @@
 ;; in FP registers (off by default, use -mdebugh to enable).
 
 (define_insn "*mov<mode>_internal"
-  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,d,e,d,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
-	(match_operand:IMOVE32 1 "move_operand" "d,Yd,Yf,m,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
+  [(set (match_operand:IMOVE32 0 "nonimmediate_operand" "=d,!u,!u,d,e,!u,!ks,d,ZS,ZT,m,*f,*f,*d,*m,*d,*z,*a,*d,*B*C*D,*B*C*D,*d,*m")
+	(match_operand:IMOVE32 1 "move_operand" "d,J,Udb7,Yd,Yf,ZT,ZS,m,!ks,!u,dJ,*d*J,*m,*f,*f,*z,*d,*J*d,*a,*d,*m,*B*C*D,*B*C*D"))]
   "!TARGET_MIPS16
    && (register_operand (operands[0], <MODE>mode)
        || reg_or_0_operand (operands[1], <MODE>mode))"
   { return mips_output_move (operands[0], operands[1]); }
-  [(set_attr "move_type" "move,const,const,load,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+  [(set_attr "move_type" "move,move,const,const,const,load,load,load,store,store,store,mtc,fpload,mfc,fpstore,mfc,mtc,mtlo,mflo,mtc,fpload,mfc,fpstore")
+   (set_attr "compression" "all,micromips,micromips,*,*,micromips,micromips,*,micromips,micromips,*,*,*,*,*,*,*,*,*,*,*,*,*")
    (set_attr "mode" "SI")])
 
 (define_insn "*mov<mode>_mips16"
@@ -5225,9 +5261,9 @@
 })
 
 (define_insn "*<optab><mode>3"
-  [(set (match_operand:GPR 0 "register_operand" "=d")
-	(any_shift:GPR (match_operand:GPR 1 "register_operand" "d")
-		       (match_operand:SI 2 "arith_operand" "dI")))]
+  [(set (match_operand:GPR 0 "register_operand" "=!u,d")
+	(any_shift:GPR (match_operand:GPR 1 "register_operand" "!u,d")
+		       (match_operand:SI 2 "arith_operand" "Uib3,dI")))]
   "!TARGET_MIPS16"
 {
   if (CONST_INT_P (operands[2]))
@@ -5237,6 +5273,7 @@
   return "<d><insn>\t%0,%1,%2";
 }
   [(set_attr "type" "shift")
+   (set_attr "compression" "<shift_compression>,none")
    (set_attr "mode" "<MODE>")])
 
 (define_insn "*<optab>si3_extend"
Index: gcc/config/mips/mips-protos.h
===================================================================
--- gcc/config/mips/mips-protos.h	(revision 196638)
+++ gcc/config/mips/mips-protos.h	(working copy)
@@ -350,12 +350,17 @@
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
 				    rtx (*) (rtx, rtx, rtx), bool);
 
+extern bool mips_signed_immediate_p (unsigned HOST_WIDE_INT, int, int);
+extern bool mips_unsigned_immediate_p (unsigned HOST_WIDE_INT, int, int);
 extern const char *umips_output_save_restore (bool, rtx);
 extern bool umips_save_restore_pattern_p (bool, rtx);
 extern bool umips_load_store_pair_p (bool, rtx *);
 extern void umips_output_load_store_pair (bool, rtx *);
 extern bool umips_movep_target_p (rtx, rtx);
 extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
+extern bool lwsp_swsp_address_p (rtx, enum machine_mode);
+extern bool m16_based_address_p (rtx, enum machine_mode,
+			         int (*)(rtx_def*, machine_mode)); 
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
Index: gcc/config/mips/mips.c
===================================================================
--- gcc/config/mips/mips.c	(revision 196638)
+++ gcc/config/mips/mips.c	(working copy)
@@ -2377,6 +2377,55 @@
   return 0;
 }
 
+/* Return true if X fits within an unsigned field of BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_unsigned_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+  return (x & ((1 << shift) - 1)) == 0 && x < ((unsigned) 1 << (shift + bits));
+}
+
+/* Return true if X fits within a signed field of BITS bits that is
+   shifted left SHIFT bits before being used.  */
+
+bool
+mips_signed_immediate_p (unsigned HOST_WIDE_INT x, int bits, int shift = 0)
+{
+  x += 1 << (bits + shift - 1);
+  return mips_unsigned_immediate_p (x, bits, shift);
+}
+
+/* Return true if X is legitimate for accessing values of mode MODE,
+   if it is based on a MIPS16 register, and if the offset satisfies
+   OFFSET_PREDICATE.  */
+
+bool
+m16_based_address_p (rtx x, enum machine_mode mode,
+		     insn_operand_predicate_fn offset_predicate)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && M16_REG_P (REGNO (addr.reg))
+	  && offset_predicate (addr.offset, mode));
+}
+
+/* Return true if X is a legitimate address that conforms to the requirements
+   for a microMIPS LWSP or SWSP insn.  */
+
+bool
+lwsp_swsp_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+	  && addr.type == ADDRESS_REG
+	  && REGNO (addr.reg) == STACK_POINTER_REGNUM
+	  && uw5_operand (addr.offset, mode));
+}
+
 /* Return true if X is a legitimate address with a 12-bit offset.
    MODE is the mode of the value being accessed.  */
 
@@ -8009,9 +8058,10 @@
       break;
 
     case '!':
-      /* When final_sequence is 0, the delay slot will be a nop.  We can
-	 a 16-bit delay slot for microMIPS.  */
-      if (final_sequence == 0)
+      /* If the delay slot instruction is short, then use the
+	 compact version.  */
+      if (final_sequence == 0
+	  || get_attr_length (XVECEXP (final_sequence, 0, 1)) == 2)
 	putc ('s', file);
       break;
 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: FW: [PATCH] [MIPS] microMIPS gcc support
  2013-03-22 18:31                                     ` Moore, Catherine
@ 2013-03-23  9:07                                       ` Richard Sandiford
  2013-04-12 18:38                                         ` Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS gcc support) David Daney
  0 siblings, 1 reply; 41+ messages in thread
From: Richard Sandiford @ 2013-03-23  9:07 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: gcc-patches, Rozycki, Maciej

"Moore, Catherine" <Catherine_Moore@mentor.com> writes:
> 2013-03-21  Catherine Moore  <clm@codesourcery.com>
> 
> 	* config/mips/constraints.md (u, Udb7 Uead, Uean, Uesp, Uib3,
> 	Uuw6, Usb4, ZS, ZT, ZU, ZV, ZW): New constraints.
> 	* config/mip/predicates.md (lwsp_swsp_operand,
> 	lw16_sw16_operand, lhu16_sh16_operand, lbu16_operand,
> 	sb16_operand, db4_operand, db7_operand, ib3_operand,
> 	sb4_operand, ub4_operand, uh4_operand, uw4_operand,
> 	uw5_operand, uw6_operand, addiur2_operand, addiusp_operand,
> 	andi16_operand): New predicates.
> 	* config/mips/mips.md (compression): New attribute.
> 	(enabled): New attribute.
> 	(length): Consider compression in computing length.
> 	(shift_compression): New code attribute.
> 	(*add<mode>3): New operands. Record compression.
> 	(sub<mode>3): Likewise.
> 	(one_cmpl<mode>2): Likewise.
> 	(*and<mode>3): Likewise.
> 	(*ior<mode>3): Likewise.
> 	(unnamed pattern for xor): Likewise.
> 	(*zero_extend<SHORT:mode><GPR:mode>2): Likewise.
> 	(*<optab><mode>3): Likewise.
> 	(*mov<mode>_internal: Likewise.
> 	* config/mips/mips-protos.h (mips_signed_immediate_p): New.
> 	(mips_unsigned_immediate_p): New.
> 	(umips_lwsp_swsp_address_p): New.
> 	(m16_based_address_p): New.
> 	* config/mips/mips-protos.h (mips_signed_immediate_p): New prototype.
> 	(mips_unsigned_immediate_p): New prototype.
> 	(lwsp_swsp_address_p): New prototype.
> 	(m16_based_address_p): New prototype.
> 	* config/mips/mips.c (mips_unsigned_immediate_p): New function.
> 	(mips_signed_immediate_p): New function.
> 	(m16_based_address_p): New function.
> 	(lwsp_swsp_address_p): New function.
> 	(mips_print_operand_punctuation): Recognize short delay slot insns
> 	for microMIPS.add<mode>3"

OK.  Thanks for your patience through all this.  Now the framework's
been sorted out, the review process for future encoding patches should
be much less painful.

Richard

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS gcc support)
  2013-03-23  9:07                                       ` Richard Sandiford
@ 2013-04-12 18:38                                         ` David Daney
  2013-04-12 20:35                                           ` Maciej W. Rozycki
  0 siblings, 1 reply; 41+ messages in thread
From: David Daney @ 2013-04-12 18:38 UTC (permalink / raw)
  To: Moore, Catherine, gcc-patches, Rozycki, Maciej, rdsandiford

On 03/23/2013 02:07 AM, Richard Sandiford wrote:
> "Moore, Catherine" <Catherine_Moore@mentor.com> writes:
>> 2013-03-21  Catherine Moore  <clm@codesourcery.com>
>>
>> 	* config/mips/constraints.md (u, Udb7 Uead, Uean, Uesp, Uib3,
>> 	Uuw6, Usb4, ZS, ZT, ZU, ZV, ZW): New constraints.
>> 	* config/mip/predicates.md (lwsp_swsp_operand,
>> 	lw16_sw16_operand, lhu16_sh16_operand, lbu16_operand,
>> 	sb16_operand, db4_operand, db7_operand, ib3_operand,
>> 	sb4_operand, ub4_operand, uh4_operand, uw4_operand,
>> 	uw5_operand, uw6_operand, addiur2_operand, addiusp_operand,
>> 	andi16_operand): New predicates.
>> 	* config/mips/mips.md (compression): New attribute.
>> 	(enabled): New attribute.
>> 	(length): Consider compression in computing length.
>> 	(shift_compression): New code attribute.
>> 	(*add<mode>3): New operands. Record compression.
>> 	(sub<mode>3): Likewise.
>> 	(one_cmpl<mode>2): Likewise.
>> 	(*and<mode>3): Likewise.
>> 	(*ior<mode>3): Likewise.
>> 	(unnamed pattern for xor): Likewise.
>> 	(*zero_extend<SHORT:mode><GPR:mode>2): Likewise.
>> 	(*<optab><mode>3): Likewise.
>> 	(*mov<mode>_internal: Likewise.
>> 	* config/mips/mips-protos.h (mips_signed_immediate_p): New.
>> 	(mips_unsigned_immediate_p): New.
>> 	(umips_lwsp_swsp_address_p): New.
>> 	(m16_based_address_p): New.
>> 	* config/mips/mips-protos.h (mips_signed_immediate_p): New prototype.
>> 	(mips_unsigned_immediate_p): New prototype.
>> 	(lwsp_swsp_address_p): New prototype.
>> 	(m16_based_address_p): New prototype.
>> 	* config/mips/mips.c (mips_unsigned_immediate_p): New function.
>> 	(mips_signed_immediate_p): New function.
>> 	(m16_based_address_p): New function.
>> 	(lwsp_swsp_address_p): New function.
>> 	(mips_print_operand_punctuation): Recognize short delay slot insns
>> 	for microMIPS.add<mode>3"
>
> OK.  Thanks for your patience through all this.  Now the framework's
> been sorted out, the review process for future encoding patches should
> be much less painful.
>
> Richard

I just tried to bootstrap on o32 Debian.  This system has binutils 2.20.1.

Here is a sample of the resulting failure when building the libjava 
target libs:
.
.
.
  /home/daney/gccsvn/build/./gcc/xgcc -B/home/daney/gccsvn/build/./gcc/ 
-B/usr/local/mips-unknown-linux-gnu/bin/ 
-B/usr/local/mips-unknown-linux-gnu/lib/ -isystem 
/usr/local/mips-unknown-linux-gnu/include -isystem 
/usr/local/mips-unknown-linux-gnu/sys-include -DHAVE_CONFIG_H -I. 
-I../../../../trunk/libjava/libltdl -g -O2 -minterlink-mips16 -c 
../../../../trunk/libjava/libltdl/ltdl.c  -fPIC -DPIC -o .libs/ltdl.o
/tmp/cckECtVQ.s: Assembler messages:
/tmp/cckECtVQ.s:12: Warning: Tried to set unrecognized symbol: nomicromips

/tmp/cckECtVQ.s:115: Warning: Tried to set unrecognized symbol: nomicromips

/tmp/cckECtVQ.s:161: Warning: Tried to set unrecognized symbol: nomicromips
.
.
.

There are literally thousands and thousands of these warnings.

David Daney

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS gcc support)
  2013-04-12 18:38                                         ` Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS gcc support) David Daney
@ 2013-04-12 20:35                                           ` Maciej W. Rozycki
  2013-04-12 22:08                                             ` Moore, Catherine
  0 siblings, 1 reply; 41+ messages in thread
From: Maciej W. Rozycki @ 2013-04-12 20:35 UTC (permalink / raw)
  To: David Daney; +Cc: Moore, Catherine, gcc-patches, Richard Sandiford

On Fri, 12 Apr 2013, David Daney wrote:

> I just tried to bootstrap on o32 Debian.  This system has binutils 2.20.1.
> 
> Here is a sample of the resulting failure when building the libjava target
> libs:
> .
> .
> .
>  /home/daney/gccsvn/build/./gcc/xgcc -B/home/daney/gccsvn/build/./gcc/
> -B/usr/local/mips-unknown-linux-gnu/bin/
> -B/usr/local/mips-unknown-linux-gnu/lib/ -isystem
> /usr/local/mips-unknown-linux-gnu/include -isystem
> /usr/local/mips-unknown-linux-gnu/sys-include -DHAVE_CONFIG_H -I.
> -I../../../../trunk/libjava/libltdl -g -O2 -minterlink-mips16 -c
> ../../../../trunk/libjava/libltdl/ltdl.c  -fPIC -DPIC -o .libs/ltdl.o
> /tmp/cckECtVQ.s: Assembler messages:
> /tmp/cckECtVQ.s:12: Warning: Tried to set unrecognized symbol: nomicromips
> 
> /tmp/cckECtVQ.s:115: Warning: Tried to set unrecognized symbol: nomicromips
> 
> /tmp/cckECtVQ.s:161: Warning: Tried to set unrecognized symbol: nomicromips
> .
> .
> .
> 
> There are literally thousands and thousands of these warnings.

 Thanks for the report, I guess GCC should:

1. Detect in its `configure' script if GAS supports the pseudo-op and 
   refrain from producing it if it does not (or actually perhaps it may 
   never produce it by default as GAS defaults to the nomicromips mode 
   anyway); we have precedents for that already.

2. Refuse the -mmicromips option and terminate if GAS does not support the 
   micromips mode; we have precedents for that too.

3. If support for pure-microMIPS processors is added in the future, then
   refuse to select that processor (with -march=) or being configured for 
   that processor by default (with a `configure' option) altogether unless 
   GAS supports the micromips mode.

 Thoughts?

  Maciej

^ permalink raw reply	[flat|nested] 41+ messages in thread

* RE: Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS gcc support)
  2013-04-12 20:35                                           ` Maciej W. Rozycki
@ 2013-04-12 22:08                                             ` Moore, Catherine
  2013-04-13  6:36                                               ` David Daney
  0 siblings, 1 reply; 41+ messages in thread
From: Moore, Catherine @ 2013-04-12 22:08 UTC (permalink / raw)
  To: Rozycki, Maciej, David Daney; +Cc: gcc-patches, Richard Sandiford



> -----Original Message-----
> From: Maciej W. Rozycki [mailto:macro@codesourcery.com]
> Sent: Friday, April 12, 2013 1:03 PM
> To: David Daney
> Cc: Moore, Catherine; gcc-patches@gcc.gnu.org; Richard Sandiford
> Subject: Re: Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS
> gcc support)
> 
> On Fri, 12 Apr 2013, David Daney wrote:
> 
> > I just tried to bootstrap on o32 Debian.  This system has binutils 2.20.1.
> >
> > Here is a sample of the resulting failure when building the libjava
> > target
> > libs:
> > .
> > .
> > .
> >  /home/daney/gccsvn/build/./gcc/xgcc -
> B/home/daney/gccsvn/build/./gcc/
> > -B/usr/local/mips-unknown-linux-gnu/bin/
> > -B/usr/local/mips-unknown-linux-gnu/lib/ -isystem
> > /usr/local/mips-unknown-linux-gnu/include -isystem
> > /usr/local/mips-unknown-linux-gnu/sys-include -DHAVE_CONFIG_H -I.
> > -I../../../../trunk/libjava/libltdl -g -O2 -minterlink-mips16 -c
> > ../../../../trunk/libjava/libltdl/ltdl.c  -fPIC -DPIC -o .libs/ltdl.o
> > /tmp/cckECtVQ.s: Assembler messages:
> > /tmp/cckECtVQ.s:12: Warning: Tried to set unrecognized symbol:
> > nomicromips
> >
> > /tmp/cckECtVQ.s:115: Warning: Tried to set unrecognized symbol:
> > nomicromips
> >
> > /tmp/cckECtVQ.s:161: Warning: Tried to set unrecognized symbol:
> > nomicromips .
> > .
> > .
> >
> > There are literally thousands and thousands of these warnings.
> 
>  Thanks for the report, I guess GCC should:
> 
> 1. Detect in its `configure' script if GAS supports the pseudo-op and
>    refrain from producing it if it does not (or actually perhaps it may
>    never produce it by default as GAS defaults to the nomicromips mode
>    anyway); we have precedents for that already.

Configure was modified as part of the micromips patch to detect support for the .set <no>micromips pseudo op.
Do you have a configure log?

> 

^ permalink raw reply	[flat|nested] 41+ messages in thread

* Re: Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS gcc support)
  2013-04-12 22:08                                             ` Moore, Catherine
@ 2013-04-13  6:36                                               ` David Daney
  0 siblings, 0 replies; 41+ messages in thread
From: David Daney @ 2013-04-13  6:36 UTC (permalink / raw)
  To: Moore, Catherine; +Cc: Rozycki, Maciej, gcc-patches, Richard Sandiford

On 04/12/2013 10:55 AM, Moore, Catherine wrote:
>
>
>> -----Original Message-----
>> From: Maciej W. Rozycki [mailto:macro@codesourcery.com]
>> Sent: Friday, April 12, 2013 1:03 PM
>> To: David Daney
>> Cc: Moore, Catherine; gcc-patches@gcc.gnu.org; Richard Sandiford
>> Subject: Re: Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS
>> gcc support)
>>
>> On Fri, 12 Apr 2013, David Daney wrote:
>>
>>> I just tried to bootstrap on o32 Debian.  This system has binutils 2.20.1.
>>>
>>> Here is a sample of the resulting failure when building the libjava
>>> target
>>> libs:
>>> .
>>> .
>>> .
>>>   /home/daney/gccsvn/build/./gcc/xgcc -
>> B/home/daney/gccsvn/build/./gcc/
>>> -B/usr/local/mips-unknown-linux-gnu/bin/
>>> -B/usr/local/mips-unknown-linux-gnu/lib/ -isystem
>>> /usr/local/mips-unknown-linux-gnu/include -isystem
>>> /usr/local/mips-unknown-linux-gnu/sys-include -DHAVE_CONFIG_H -I.
>>> -I../../../../trunk/libjava/libltdl -g -O2 -minterlink-mips16 -c
>>> ../../../../trunk/libjava/libltdl/ltdl.c  -fPIC -DPIC -o .libs/ltdl.o
>>> /tmp/cckECtVQ.s: Assembler messages:
>>> /tmp/cckECtVQ.s:12: Warning: Tried to set unrecognized symbol:
>>> nomicromips
>>>
>>> /tmp/cckECtVQ.s:115: Warning: Tried to set unrecognized symbol:
>>> nomicromips
>>>
>>> /tmp/cckECtVQ.s:161: Warning: Tried to set unrecognized symbol:
>>> nomicromips .
>>> .
>>> .
>>>
>>> There are literally thousands and thousands of these warnings.
>>
>>   Thanks for the report, I guess GCC should:
>>
>> 1. Detect in its `configure' script if GAS supports the pseudo-op and
>>     refrain from producing it if it does not (or actually perhaps it may
>>     never produce it by default as GAS defaults to the nomicromips mode
>>     anyway); we have precedents for that already.
>
> Configure was modified as part of the micromips patch to detect support for the .set <no>micromips pseudo op.
> Do you have a configure log?

Here is the relevant fragment:
.
.
.
configure:25761: checking assembler for .micromips support
configure:25770: /usr/bin/as    -o conftest.o conftest.s >&5
conftest.s: Assembler messages:
conftest.s:1: Warning: Tried to set unrecognized symbol: micromips

configure:25773: $? = 0
configure:25784: result: yes
.
.
.

Since it is a warning, it succeeds.  I think you need to adjust the test 
so that it fails if there is a warning.








>
>>
>
>
>

^ permalink raw reply	[flat|nested] 41+ messages in thread

end of thread, other threads:[~2013-04-12 19:07 UTC | newest]

Thread overview: 41+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <FD3DCEAC5B03E9408544A1E416F1124211F9CC2E@NA-MBX-04.mgc.mentorg.com>
2012-07-19 18:51 ` FW: [PATCH] [MIPS] microMIPS gcc support Moore, Catherine
2012-07-20  0:46   ` Richard Sandiford
2013-01-22 20:23     ` Moore, Catherine
2013-01-22 20:27       ` Moore, Catherine
2013-01-23 20:05         ` Richard Sandiford
2013-01-26  3:52           ` Maciej W. Rozycki
2013-01-26 10:17             ` Richard Sandiford
2013-01-27 13:58               ` Maciej W. Rozycki
2013-01-28 10:14                 ` Richard Sandiford
2013-02-12 19:00           ` Moore, Catherine
2013-02-13 11:43             ` Richard Sandiford
2013-02-19 16:31               ` Moore, Catherine
2013-02-19 18:25                 ` Richard Sandiford
2013-02-19 22:27                   ` Maciej W. Rozycki
2013-02-21  2:28                   ` Moore, Catherine
2013-02-21 21:20                     ` Richard Sandiford
2013-02-24 23:52                       ` Moore, Catherine
2013-02-25  9:41                         ` Richard Sandiford
2013-02-25 13:55                           ` Moore, Catherine
2013-03-04 19:43     ` Moore, Catherine
2013-03-04 20:54       ` Richard Sandiford
2013-03-04 22:47         ` Moore, Catherine
2013-03-05 21:06           ` Richard Sandiford
2013-03-13 20:30             ` Moore, Catherine
2013-03-14 20:55               ` Richard Sandiford
2013-03-15 18:00                 ` Moore, Catherine
2013-03-19 19:26                   ` Richard Sandiford
2013-03-19 21:23                     ` Moore, Catherine
2013-03-19 21:23                       ` Richard Sandiford
2013-03-20 20:15                         ` Moore, Catherine
2013-03-20 21:48                           ` Richard Sandiford
2013-03-20 22:02                             ` Moore, Catherine
2013-03-21  8:05                               ` Richard Sandiford
2013-03-21 23:04                                 ` Moore, Catherine
2013-03-22  0:05                                   ` Richard Sandiford
2013-03-22 18:31                                     ` Moore, Catherine
2013-03-23  9:07                                       ` Richard Sandiford
2013-04-12 18:38                                         ` Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS gcc support) David Daney
2013-04-12 20:35                                           ` Maciej W. Rozycki
2013-04-12 22:08                                             ` Moore, Catherine
2013-04-13  6:36                                               ` David Daney

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).