public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: "Moore, Catherine" <Catherine_Moore@mentor.com>
To: Richard Sandiford <rdsandiford@googlemail.com>
Cc: "gcc-patches@gcc.gnu.org" <gcc-patches@gcc.gnu.org>,
	"Rozycki, Maciej"	<Maciej_Rozycki@mentor.com>
Subject: RE: FW: [PATCH] [MIPS] microMIPS gcc support
Date: Tue, 12 Feb 2013 19:00:00 -0000	[thread overview]
Message-ID: <FD3DCEAC5B03E9408544A1E416F11242987BA154@NA-MBX-01.mgc.mentorg.com> (raw)
In-Reply-To: <87622noebh.fsf@talisman.default>

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

Hi Richard,

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

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

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

As usual, thanks for the thorough review.
Catherine

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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


  parent reply	other threads:[~2013-02-12 19:00 UTC|newest]

Thread overview: 41+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
     [not found] <FD3DCEAC5B03E9408544A1E416F1124211F9CC2E@NA-MBX-04.mgc.mentorg.com>
2012-07-19 18:51 ` Moore, Catherine
2012-07-20  0:46   ` Richard Sandiford
2013-01-22 20:23     ` Moore, Catherine
2013-01-22 20:27       ` Moore, Catherine
2013-01-23 20:05         ` Richard Sandiford
2013-01-26  3:52           ` Maciej W. Rozycki
2013-01-26 10:17             ` Richard Sandiford
2013-01-27 13:58               ` Maciej W. Rozycki
2013-01-28 10:14                 ` Richard Sandiford
2013-02-12 19:00           ` Moore, Catherine [this message]
2013-02-13 11:43             ` Richard Sandiford
2013-02-19 16:31               ` Moore, Catherine
2013-02-19 18:25                 ` Richard Sandiford
2013-02-19 22:27                   ` Maciej W. Rozycki
2013-02-21  2:28                   ` Moore, Catherine
2013-02-21 21:20                     ` Richard Sandiford
2013-02-24 23:52                       ` Moore, Catherine
2013-02-25  9:41                         ` Richard Sandiford
2013-02-25 13:55                           ` Moore, Catherine
2013-03-04 19:43     ` Moore, Catherine
2013-03-04 20:54       ` Richard Sandiford
2013-03-04 22:47         ` Moore, Catherine
2013-03-05 21:06           ` Richard Sandiford
2013-03-13 20:30             ` Moore, Catherine
2013-03-14 20:55               ` Richard Sandiford
2013-03-15 18:00                 ` Moore, Catherine
2013-03-19 19:26                   ` Richard Sandiford
2013-03-19 21:23                     ` Moore, Catherine
2013-03-19 21:23                       ` Richard Sandiford
2013-03-20 20:15                         ` Moore, Catherine
2013-03-20 21:48                           ` Richard Sandiford
2013-03-20 22:02                             ` Moore, Catherine
2013-03-21  8:05                               ` Richard Sandiford
2013-03-21 23:04                                 ` Moore, Catherine
2013-03-22  0:05                                   ` Richard Sandiford
2013-03-22 18:31                                     ` Moore, Catherine
2013-03-23  9:07                                       ` Richard Sandiford
2013-04-12 18:38                                         ` Many warnings in MIPS port (Was: [PATCH] [MIPS] microMIPS gcc support) David Daney
2013-04-12 20:35                                           ` Maciej W. Rozycki
2013-04-12 22:08                                             ` Moore, Catherine
2013-04-13  6:36                                               ` David Daney

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=FD3DCEAC5B03E9408544A1E416F11242987BA154@NA-MBX-01.mgc.mentorg.com \
    --to=catherine_moore@mentor.com \
    --cc=Maciej_Rozycki@mentor.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=rdsandiford@googlemail.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).