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;
 }
 
-/* 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;
 }
 
 /* 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;
+}
 
 /* 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;
 }
 
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 "%/")))
+
+/* 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 "%/")
+
 /* 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
