]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
mips16.S: Don't build for microMIPS.
authorCatherine Moore <clm@codesourcery.com>
Sun, 24 Feb 2013 23:46:44 +0000 (18:46 -0500)
committerCatherine Moore <clm@gcc.gnu.org>
Sun, 24 Feb 2013 23:46:44 +0000 (18:46 -0500)
libgcc/
2013-02-24  Catherine Moore  <clm@codesourcery.com>
    Joseph Myers  <joseph@codesourcery.com>
    Chao-ying Fu  <fu@mips.com>

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

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

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

gcc/testsuite/
2013-02-24  Catherine Moore  <clm@codesourcery.com>
    Richard Sandiford <rdsandiford@googlemail.com>

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

Co-Authored-By: Chao-ying Fu <fu@mips.com>
Co-Authored-By: Iain Sandoe <iain@codesourcery.com>
Co-Authored-By: Joseph Myers <joseph@codesourcery.com>
Co-Authored-By: Maciej W. Rozycki <macro@codesourcery.com>
Co-Authored-By: Nathan Froyd <froydnj@codesourcery.com>
Co-Authored-By: Nathan Sidwell <nathan@codesourcery.com>
Co-Authored-By: Richard Sandiford <rdsandiford@googlemail.com>
Co-Authored-By: Tom de Vries <tom@codesourcery.com>
From-SVN: r196246

48 files changed:
gcc/ChangeLog
gcc/config.in
gcc/config/mips/constraints.md
gcc/config/mips/micromips.md [new file with mode: 0644]
gcc/config/mips/mips-cpus.def
gcc/config/mips/mips-protos.h
gcc/config/mips/mips-tables.opt
gcc/config/mips/mips.c
gcc/config/mips/mips.h
gcc/config/mips/mips.md
gcc/config/mips/mips.opt
gcc/config/mips/predicates.md
gcc/config/mips/sync.md
gcc/config/mips/t-sde
gcc/configure
gcc/configure.ac
gcc/doc/extend.texi
gcc/doc/invoke.texi
gcc/doc/md.texi
gcc/testsuite/ChangeLog
gcc/testsuite/gcc.target/mips/mips.exp
gcc/testsuite/gcc.target/mips/umips-constraints-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-constraints-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-7.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-8.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-movep-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-movep-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-save-restore-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-save-restore-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-save-restore-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-swp-1.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-swp-2.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-swp-3.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-swp-4.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-swp-5.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-swp-6.c [new file with mode: 0644]
gcc/testsuite/gcc.target/mips/umips-swp-7.c [new file with mode: 0644]
libgcc/ChangeLog
libgcc/config/mips/crtn.S
libgcc/config/mips/linux-unwind.h
libgcc/config/mips/mips16.S

index ca97c8a7be56a06bc025fb410858f424b9e32e92..71abb1c6b5032d94c74a0b84968ad6d89a8f1da8 100644 (file)
@@ -1,3 +1,130 @@
+2013-02-24  Catherine Moore  <clm@codesourcery.com>
+           Maciej W. Rozycki  <macro@codesourcery.com>
+           Tom de Vries  <tom@codesourcery.com>
+           Nathan Sidwell <nathan@codesourcery.com>
+           Iain Sandoe  <iain@codesourcery.com>
+           Nathan Froyd  <froydnj@codesourcery.com>
+           Chao-ying Fu <fu@mips.com>
+
+       * doc/extend.texi: (micromips, nomicromips, nocompression):
+       Document new function attributes. 
+       * doc/invoke.texi (minterlink-compressed, mmicromips,
+       m14k, m14ke, m14kec): Document new options.
+       (minterlink-mips16): Update documentation.
+       * doc/md.texi (ZC, ZD): Document new constraints.
+       * configure.ac (gcc_cv_as_micromips): Check if linker
+       supports the .set micromips directive.
+       * configure: Regenerate.
+       * config.in: Regenerate.
+       * config/mips/mips-tables.opt: Regenerate.
+       * config/mips/micromips.md: New file.
+       * constraints.md (ZC, AD): New constraints.
+       * config/mips/predicates.md (movep_src_register): New predicate.
+       (movep_src_operand): New predicate.
+       (non_volatile_mem_operand): New predicate.
+       * config/mips/mips.md (multimem): New type.
+       (length): Differentiate between 17-bit and 18-bit branch offsets.
+       (MOVEP1, MOVEP2): New mode iterator.
+       (mov_<load>l): Use ZC constraint.
+       (mov_<load>r): Likewise.
+       (mov_<store>l): Likewise.
+       (mov_<store>r): Likewise.
+       (*branch_equality<mode>_inverted): Add microMIPS support.
+       (*branch_equality<mode>): Likewise.
+       (*jump_absolute): Likewise.
+       (indirect_jump_<mode>): Likewise.
+       (tablejump_<mode>): Likewise.
+       (<optab>_internal): Likewise.
+       (sibcall_internal): Likewise.
+       (sibcall_value_internal): Likewise.
+       (prefetch): Use constraint ZD.
+       * config/mips/mips.opt (minterlink-compressed): New option.
+       (minterlink-mips16): Now an alias for minterlink-compressed.
+       (mmicromips): New option.
+       * config/mips/sync.md (sync_compare_and_swap<mode>): Use ZR constraint.
+       (compare_and_swap_12): Likewise.
+       (sync_add<mode>): Likewise.
+       (sync_<optab>_12): Likewise.
+       (sync_old_<optab>_12): Likewise.
+       (sync_new_<optab>_12): Likewise.
+       (sync_nand_12): Likewise.
+       (sync_old_nand_12): Likewise.
+       (sync_new_nand_12): Likewise.
+       (sync_sub<mode>): Likewise.
+       (sync_old_add<mode>): Likewise.
+       (sync_old_sub<mode>): Likewise.
+       (sync_new_add<mode>): Likewise.
+       (sync_new_sub<mode>): Likewise.
+       (sync_<optab><mode>): Likewise.
+       (sync_old_<optab><mode>): Likewise.
+       (sync_new_<optab><mode>): Likewise.
+       (sync_nand<mode>): Likewise.
+       (sync_old_nand<mode>): Likewise.
+       (sync_new_nand<mode>): Likewise.
+       (sync_lock_test_and_set<mode>): Likewise.
+       (test_and_set_12): Likewise.
+       (atomic_compare_and_swap<mode>): Likewise.
+       (atomic_exchange<mode>_llsc): Likewise.
+       (atomic_fetch_add<mode>_llsc): Likewise.
+       * config/mips/mips-cpus.def (m14kc, m14k): New processors.
+       * config/mips/mips-protos.h (umips_output_save_restore): New prototype.
+       (umips_save_restore_pattern_p): Likewise.
+       (umips_load_store_pair_p): Likewise.
+       (umips_output_load_store_pair): Likewise.
+       (umips_movep_target_p): Likewise.
+       (umips_12bit_offset_address_p): Likewise.
+       * config/mips/mips.c (MIPS_MAX_FIRST_STEP): Update for microMIPS.
+       (mips_base_mips16): Rename this...
+       (mips_base_compression_flags): ...to this. Update all uses.
+       (mips_attribute_table): Add micromips, nomicromips and nocompression.
+       (mips_mips16_decl_p): Delete.
+       (mips_nomips16_decl_p): Delete.
+       (mips_get_compress_on_flags): New function.
+       (mips_get_compress_off_flags): New function.
+       (mips_get_compress_mode): New function.
+       (mips_get_compress_on_name): New function.
+       (mips_get_compress_off_name): New function.
+       (mips_insert_attributes): Support multiple compression types.
+       (mips_merge_decl_attributes): Likewise.
+       (umips_12bit_offset_address_p): New function.
+       (mips_start_function_definition): Emit .set micromips directive.
+       (mips_call_may_need_jalx_p): New function.
+       (mips_function_ok_for_sibcall): Add microMIPS support.
+       (mips_print_operand_punctuation): Support short delay slots and
+       compact jumps.
+       (umips_swm_mask, umips_swm_encoding): New.
+       (umips_build_save_restore): New function.
+       (mips_for_each_saved_gpr_and_fpr): Add microMIPS support.
+       (was_mips16_p): Remove.
+       (old_compression_mode): New.
+       (mips_set_compression_mode): New function.
+       (mips_set_current_function): Add microMIPS support.
+       (mips_option_override): Likewise.
+       (umips_save_restore_pattern_p): New function.
+       (umips_output_save_restore): New function.
+       (umips_load_store_pair_p_1): New function.
+       (umips_load_store_pair_p): New function.
+       (umips_output_load_store_pair_1): New function.
+       (umips_output_load_store_pair): New function.
+       (umips_movep_target_p) New function.
+       (mips_prepare_pch_save): Add microMIPS support.
+       * config/mips/mips.h (TARGET_COMPRESSION): New.
+       (TARGET_CPU_CPP_BUILTINS): Update macro
+       to use new compression flags and to support microMIPS.
+       (MIPS_ISA_LEVEL_SPEC): Add m14k processors.
+       (MIPS_ARCH_FLOAT_SPEC): Likewise.
+       (ISA_HAS_LWXS): Include TARGET_MICROMIPS.
+       (ISA_HAS_LOAD_DELAY): Exclude TARGET_MICROMIPS.
+       (ASM_SPEC): Support mmicromips and mno-micromips.
+       (M16STORE_REG_P): New macro.
+       (MIPS_CALL): Support TARGET_MICROMIPS.
+       (MICROMIPS_J): New macro.
+       (mips_base_mips16): Rename this...
+       (mips_base_compression_flags): ...to this.
+       (UMIPS_12BIT_OFFSET_P): New macro.
+       * config/mips/t-sde: (MULTILIB_OPTIONS): Add microMIPS.
+       (MULTILIB_DIRNAMES): Likewise.
+
 2013-02-24  Jakub Jelinek  <jakub@redhat.com>
 
        PR target/52555
index d80fb9f6e11379cb778c2fbe791168e18610e588..f1ab30d0cf98e683eeebd3b991aa6481bb46add4 100644 (file)
 #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 71ec938d85bd8b53630370d71c79a08c8893172f..31f01d35dbc1b189faeed37229397614cb3bafdd 100644 (file)
    "@internal"
    (match_operand 0 "low_bitmask_operand"))
 
+(define_memory_constraint "ZC"
+  "When compiling microMIPS code, this constraint matches a memory operand
+   whose address is formed from a base register and a 12-bit offset.  These
+   operands can be used for microMIPS instructions such as @code{ll} and
+   @code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+   equivalent to @code{R}."
+  (and (match_code "mem")
+       (if_then_else
+        (match_test "TARGET_MICROMIPS")
+        (match_test "umips_12bit_offset_address_p (XEXP (op, 0), mode)")
+        (match_test "mips_address_insns (XEXP (op, 0), mode, false)"))))
+
+(define_address_constraint "ZD"
+  "When compiling microMIPS code, this constraint matches an address operand
+   that is formed from a base register and a 12-bit offset.  These operands
+   can be used for microMIPS instructions such as @code{prefetch}.  When
+   not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}."
+   (if_then_else (match_test "TARGET_MICROMIPS")
+                (match_test "umips_12bit_offset_address_p (op, mode)")
+                (match_test "mips_address_insns (op, mode, false)")))
+
 (define_memory_constraint "ZR"
  "@internal
   An address valid for loading/storing register exclusive"
diff --git a/gcc/config/mips/micromips.md b/gcc/config/mips/micromips.md
new file mode 100644 (file)
index 0000000..4b7a4a7
--- /dev/null
@@ -0,0 +1,125 @@
+;; Copyright (C) 2013 Free Software Foundation, Inc.
+;;
+;; micromips.md   Machine Description for the microMIPS instruction set
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify it
+;; under the terms of the GNU General Public License as published
+;; by the Free Software Foundation; either version 3, or (at your
+;; option) any later version.
+
+;; GCC is distributed in the hope that it will be useful, but WITHOUT
+;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+;; License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_insn "*store_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "memory_operand")
+            (match_operand:SI 2 "register_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (true, operands[0])"
+  { return umips_output_save_restore (true, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+(define_insn "*load_word_multiple"
+  [(match_parallel 0 ""
+       [(set (match_operand:SI 1 "register_operand")
+            (match_operand:SI 2 "memory_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_save_restore_pattern_p (false, operands[0])"
+  { return umips_output_save_restore (false, operands[0]); }
+  [(set_attr "type" "multimem")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For LWP.
+(define_peephole2
+  [(set (match_operand:SI 0 "d_operand" "")
+        (match_operand:SI 1 "non_volatile_mem_operand" ""))
+   (set (match_operand:SI 2 "d_operand" "")
+        (match_operand:SI 3 "non_volatile_mem_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the LWP insn is undefined if placed in a delay slot.
+(define_insn "*lwp"
+  [(parallel [(set (match_operand:SI 0 "d_operand")
+                  (match_operand:SI 1 "non_volatile_mem_operand"))
+             (set (match_operand:SI 2 "d_operand")
+                  (match_operand:SI 3 "non_volatile_mem_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (true, operands)"
+{
+  umips_output_load_store_pair (true, operands);
+  return "";
+}
+  [(set_attr "type" "load")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For SWP.
+(define_peephole2
+  [(set (match_operand:SI 0 "non_volatile_mem_operand" "")
+        (match_operand:SI 1 "d_operand" ""))
+   (set (match_operand:SI 2 "non_volatile_mem_operand" "")
+        (match_operand:SI 3 "d_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the SWP insn is undefined if placed in a delay slot.
+(define_insn "*swp"
+  [(parallel [(set (match_operand:SI 0 "non_volatile_mem_operand")
+                  (match_operand:SI 1 "d_operand"))
+             (set (match_operand:SI 2 "non_volatile_mem_operand")
+                  (match_operand:SI 3 "d_operand"))])]
+
+  "TARGET_MICROMIPS
+   && umips_load_store_pair_p (false, operands)"
+{
+  umips_output_load_store_pair (false, operands);
+  return "";
+}
+  [(set_attr "type" "store")
+   (set_attr "mode" "SI")
+   (set_attr "can_delay" "no")])
+
+;; For MOVEP.
+(define_peephole2
+  [(set (match_operand:MOVEP1 0 "register_operand" "")
+        (match_operand:MOVEP1 1 "movep_src_operand" ""))
+   (set (match_operand:MOVEP2 2 "register_operand" "")
+        (match_operand:MOVEP2 3 "movep_src_operand" ""))]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+  [(parallel [(set (match_dup 0) (match_dup 1))
+              (set (match_dup 2) (match_dup 3))])])
+
+;; The behavior of the MOVEP insn is undefined if placed in a delay slot.
+(define_insn "*movep<MOVEP1:mode><MOVEP2:mode>"
+  [(parallel [(set (match_operand:MOVEP1 0 "register_operand")
+                  (match_operand:MOVEP1 1 "movep_src_operand"))
+             (set (match_operand:MOVEP2 2 "register_operand")
+                  (match_operand:MOVEP2 3 "movep_src_operand"))])]
+  "TARGET_MICROMIPS
+   && umips_movep_target_p (operands[0], operands[2])"
+{
+  if (REGNO (operands[0]) < REGNO (operands[2]))
+    return "movep\t%0,%2,%z1,%z3";
+  else
+    return "movep\t%2,%0,%z3,%z1";
+}
+  [(set_attr "type" "move")
+   (set_attr "mode" "<MODE>")
+   (set_attr "can_delay" "no")])
index 93c305a7c7f5409207961a454f75257a69192a58..1cc1999937346477ca5b51aa736b769fe951038e 100644 (file)
@@ -92,6 +92,8 @@ MIPS_CPU ("4ksc", PROCESSOR_4KC, 32, 0)
 
 /* MIPS32 Release 2 processors.  */
 MIPS_CPU ("m4k", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14kc", PROCESSOR_M4K, 33, 0)
+MIPS_CPU ("m14k", PROCESSOR_M4K, 33, 0)
 MIPS_CPU ("4kec", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kem", PROCESSOR_4KC, 33, 0)
 MIPS_CPU ("4kep", PROCESSOR_4KP, 33, 0)
index 8560bb7e9dd163f7e9550f1218b649ed1e1d4cf7..2d03f5a0656d4af648a2e7e1e9019666d18d80ea 100644 (file)
@@ -350,6 +350,12 @@ extern void mips_expand_vec_reduc (rtx, rtx, rtx (*)(rtx, rtx, rtx));
 extern void mips_expand_vec_minmax (rtx, rtx, rtx,
                                    rtx (*) (rtx, rtx, rtx), bool);
 
+extern const char *umips_output_save_restore (bool, rtx);
+extern bool umips_save_restore_pattern_p (bool, rtx);
+extern bool umips_load_store_pair_p (bool, rtx *);
+extern void umips_output_load_store_pair (bool, rtx *);
+extern bool umips_movep_target_p (rtx, rtx);
+extern bool umips_12bit_offset_address_p (rtx, enum machine_mode);
 extern rtx mips_expand_thread_pointer (rtx);
 
 extern bool mips_eh_uses (unsigned int);
index de9a736452e1d0cf4cd2712bb7e3a4a1ae7f5bd2..0d7fa26510d0ff30eef9316fb3bf43c006c36736 100644 (file)
@@ -373,254 +373,260 @@ EnumValue
 Enum(mips_arch_opt_value) String(m4k) Value(39) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kec) Value(40) Canonical
+Enum(mips_arch_opt_value) String(m14kc) Value(40) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kec) Value(40)
+Enum(mips_arch_opt_value) String(m14k) Value(41) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kem) Value(41) Canonical
+Enum(mips_arch_opt_value) String(4kec) Value(42) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kem) Value(41)
+Enum(mips_arch_opt_value) String(r4kec) Value(42)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4kep) Value(42) Canonical
+Enum(mips_arch_opt_value) String(4kem) Value(43) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4kep) Value(42)
+Enum(mips_arch_opt_value) String(r4kem) Value(43)
 
 EnumValue
-Enum(mips_arch_opt_value) String(4ksd) Value(43) Canonical
+Enum(mips_arch_opt_value) String(4kep) Value(44) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r4ksd) Value(43)
+Enum(mips_arch_opt_value) String(r4kep) Value(44)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kc) Value(44) Canonical
+Enum(mips_arch_opt_value) String(4ksd) Value(45) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kc) Value(44)
+Enum(mips_arch_opt_value) String(r4ksd) Value(45)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf2_1) Value(45) Canonical
+Enum(mips_arch_opt_value) String(24kc) Value(46) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf2_1) Value(45)
+Enum(mips_arch_opt_value) String(r24kc) Value(46)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf) Value(46) Canonical
+Enum(mips_arch_opt_value) String(24kf2_1) Value(47) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf) Value(46)
+Enum(mips_arch_opt_value) String(r24kf2_1) Value(47)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kf1_1) Value(47) Canonical
+Enum(mips_arch_opt_value) String(24kf) Value(48) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kf1_1) Value(47)
+Enum(mips_arch_opt_value) String(r24kf) Value(48)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kfx) Value(48) Canonical
+Enum(mips_arch_opt_value) String(24kf1_1) Value(49) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kfx) Value(48)
+Enum(mips_arch_opt_value) String(r24kf1_1) Value(49)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kx) Value(49) Canonical
+Enum(mips_arch_opt_value) String(24kfx) Value(50) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kx) Value(49)
+Enum(mips_arch_opt_value) String(r24kfx) Value(50)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kec) Value(50) Canonical
+Enum(mips_arch_opt_value) String(24kx) Value(51) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kec) Value(50)
+Enum(mips_arch_opt_value) String(r24kx) Value(51)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef2_1) Value(51) Canonical
+Enum(mips_arch_opt_value) String(24kec) Value(52) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef2_1) Value(51)
+Enum(mips_arch_opt_value) String(r24kec) Value(52)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef) Value(52) Canonical
+Enum(mips_arch_opt_value) String(24kef2_1) Value(53) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef) Value(52)
+Enum(mips_arch_opt_value) String(r24kef2_1) Value(53)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kef1_1) Value(53) Canonical
+Enum(mips_arch_opt_value) String(24kef) Value(54) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kef1_1) Value(53)
+Enum(mips_arch_opt_value) String(r24kef) Value(54)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kefx) Value(54) Canonical
+Enum(mips_arch_opt_value) String(24kef1_1) Value(55) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kefx) Value(54)
+Enum(mips_arch_opt_value) String(r24kef1_1) Value(55)
 
 EnumValue
-Enum(mips_arch_opt_value) String(24kex) Value(55) Canonical
+Enum(mips_arch_opt_value) String(24kefx) Value(56) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r24kex) Value(55)
+Enum(mips_arch_opt_value) String(r24kefx) Value(56)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kc) Value(56) Canonical
+Enum(mips_arch_opt_value) String(24kex) Value(57) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kc) Value(56)
+Enum(mips_arch_opt_value) String(r24kex) Value(57)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf2_1) Value(57) Canonical
+Enum(mips_arch_opt_value) String(34kc) Value(58) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf2_1) Value(57)
+Enum(mips_arch_opt_value) String(r34kc) Value(58)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf) Value(58) Canonical
+Enum(mips_arch_opt_value) String(34kf2_1) Value(59) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf) Value(58)
+Enum(mips_arch_opt_value) String(r34kf2_1) Value(59)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kf1_1) Value(59) Canonical
+Enum(mips_arch_opt_value) String(34kf) Value(60) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kf1_1) Value(59)
+Enum(mips_arch_opt_value) String(r34kf) Value(60)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kfx) Value(60) Canonical
+Enum(mips_arch_opt_value) String(34kf1_1) Value(61) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kfx) Value(60)
+Enum(mips_arch_opt_value) String(r34kf1_1) Value(61)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kx) Value(61) Canonical
+Enum(mips_arch_opt_value) String(34kfx) Value(62) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kx) Value(61)
+Enum(mips_arch_opt_value) String(r34kfx) Value(62)
 
 EnumValue
-Enum(mips_arch_opt_value) String(34kn) Value(62) Canonical
+Enum(mips_arch_opt_value) String(34kx) Value(63) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r34kn) Value(62)
+Enum(mips_arch_opt_value) String(r34kx) Value(63)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kc) Value(63) Canonical
+Enum(mips_arch_opt_value) String(34kn) Value(64) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kc) Value(63)
+Enum(mips_arch_opt_value) String(r34kn) Value(64)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf2_1) Value(64) Canonical
+Enum(mips_arch_opt_value) String(74kc) Value(65) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf2_1) Value(64)
+Enum(mips_arch_opt_value) String(r74kc) Value(65)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf) Value(65) Canonical
+Enum(mips_arch_opt_value) String(74kf2_1) Value(66) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf) Value(65)
+Enum(mips_arch_opt_value) String(r74kf2_1) Value(66)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf1_1) Value(66) Canonical
+Enum(mips_arch_opt_value) String(74kf) Value(67) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf1_1) Value(66)
+Enum(mips_arch_opt_value) String(r74kf) Value(67)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kfx) Value(67) Canonical
+Enum(mips_arch_opt_value) String(74kf1_1) Value(68) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kfx) Value(67)
+Enum(mips_arch_opt_value) String(r74kf1_1) Value(68)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kx) Value(68) Canonical
+Enum(mips_arch_opt_value) String(74kfx) Value(69) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kx) Value(68)
+Enum(mips_arch_opt_value) String(r74kfx) Value(69)
 
 EnumValue
-Enum(mips_arch_opt_value) String(74kf3_2) Value(69) Canonical
+Enum(mips_arch_opt_value) String(74kx) Value(70) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r74kf3_2) Value(69)
+Enum(mips_arch_opt_value) String(r74kx) Value(70)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kc) Value(70) Canonical
+Enum(mips_arch_opt_value) String(74kf3_2) Value(71) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kc) Value(70)
+Enum(mips_arch_opt_value) String(r74kf3_2) Value(71)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf2_1) Value(71) Canonical
+Enum(mips_arch_opt_value) String(1004kc) Value(72) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf2_1) Value(71)
+Enum(mips_arch_opt_value) String(r1004kc) Value(72)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf) Value(72) Canonical
+Enum(mips_arch_opt_value) String(1004kf2_1) Value(73) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf) Value(72)
+Enum(mips_arch_opt_value) String(r1004kf2_1) Value(73)
 
 EnumValue
-Enum(mips_arch_opt_value) String(1004kf1_1) Value(73) Canonical
+Enum(mips_arch_opt_value) String(1004kf) Value(74) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r1004kf1_1) Value(73)
+Enum(mips_arch_opt_value) String(r1004kf) Value(74)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kc) Value(74) Canonical
+Enum(mips_arch_opt_value) String(1004kf1_1) Value(75) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kc) Value(74)
+Enum(mips_arch_opt_value) String(r1004kf1_1) Value(75)
 
 EnumValue
-Enum(mips_arch_opt_value) String(5kf) Value(75) Canonical
+Enum(mips_arch_opt_value) String(5kc) Value(76) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r5kf) Value(75)
+Enum(mips_arch_opt_value) String(r5kc) Value(76)
 
 EnumValue
-Enum(mips_arch_opt_value) String(20kc) Value(76) Canonical
+Enum(mips_arch_opt_value) String(5kf) Value(77) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(r20kc) Value(76)
+Enum(mips_arch_opt_value) String(r5kf) Value(77)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1) Value(77) Canonical
+Enum(mips_arch_opt_value) String(20kc) Value(78) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sb1a) Value(78) Canonical
+Enum(mips_arch_opt_value) String(r20kc) Value(78)
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71000) Value(79) Canonical
+Enum(mips_arch_opt_value) String(sb1) Value(79) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(sr71k) Value(79)
+Enum(mips_arch_opt_value) String(sb1a) Value(80) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlr) Value(80) Canonical
+Enum(mips_arch_opt_value) String(sr71000) Value(81) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(loongson3a) Value(81) Canonical
+Enum(mips_arch_opt_value) String(sr71k) Value(81)
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon) Value(82) Canonical
+Enum(mips_arch_opt_value) String(xlr) Value(82) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon+) Value(83) Canonical
+Enum(mips_arch_opt_value) String(loongson3a) Value(83) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(octeon2) Value(84) Canonical
+Enum(mips_arch_opt_value) String(octeon) Value(84) Canonical
 
 EnumValue
-Enum(mips_arch_opt_value) String(xlp) Value(85) Canonical
+Enum(mips_arch_opt_value) String(octeon+) Value(85) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(octeon2) Value(86) Canonical
+
+EnumValue
+Enum(mips_arch_opt_value) String(xlp) Value(87) Canonical
 
index 252e828480e44ec239b053cff83a6af7a1107f4d..e4ab271fd60974519fa1e80b596cb2add40c7027 100644 (file)
@@ -77,6 +77,9 @@ along with GCC; see the file COPYING3.  If not see
    preserve the maximum stack alignment.  We therefore use a value
    of 0x7ff0 in this case.
 
+   microMIPS LWM and SWM support 12-bit offsets (from -0x800 to 0x7ff),
+   so we use a maximum of 0x7f0 for TARGET_MICROMIPS.
+
    MIPS16e SAVE and RESTORE instructions can adjust the stack pointer by
    up to 0x7f8 bytes and can usually save or restore all the registers
    that we need to save or restore.  (Note that we can only use these
@@ -87,8 +90,8 @@ along with GCC; see the file COPYING3.  If not see
    to save and restore registers, and to allocate and deallocate the top
    part of the frame.  */
 #define MIPS_MAX_FIRST_STACK_STEP                                      \
-  (!TARGET_MIPS16 ? 0x7ff0                                             \
-   : GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8                             \
+  (!TARGET_COMPRESSION ? 0x7ff0                                                \
+   : TARGET_MICROMIPS || GENERATE_MIPS16E_SAVE_RESTORE ? 0x7f8         \
    : TARGET_64BIT ? 0x100 : 0x400)
 
 /* True if INSN is a mips.md pattern or asm statement.  */
@@ -560,8 +563,8 @@ static const struct mips_rtx_cost_data *mips_cost;
 /* The ambient target flags, excluding MASK_MIPS16.  */
 static int mips_base_target_flags;
 
-/* True if MIPS16 is the default mode.  */
-bool mips_base_mips16;
+/* The default compression mode.  */
+unsigned int mips_base_compression_flags;
 
 /* The ambient values of other global variables.  */
 static int mips_base_schedule_insns; /* flag_schedule_insns */
@@ -674,6 +677,9 @@ static const struct attribute_spec mips_attribute_table[] = {
      code generation but don't carry other semantics.  */
   { "mips16",     0, 0, true,  false, false, NULL, false },
   { "nomips16",    0, 0, true,  false, false, NULL, false },
+  { "micromips",   0, 0, true,  false, false, NULL, false },
+  { "nomicromips", 0, 0, true,  false, false, NULL, false },
+  { "nocompression", 0, 0, true,  false, false, NULL, false },
   /* Allow functions to be specified as interrupt handlers */
   { "interrupt",   0, 0, false, true,  true, NULL, false },
   { "use_shadow_register_set", 0, 0, false, true,  true, NULL, false },
@@ -1167,10 +1173,11 @@ mflip_mips16_use_mips16_p (tree decl)
   const char *name;
   hashval_t hash;
   void **slot;
+  bool base_is_mips16 = (mips_base_compression_flags & MASK_MIPS16) != 0;
 
   /* Use the opposite of the command-line setting for anonymous decls.  */
   if (!DECL_NAME (decl))
-    return !mips_base_mips16;
+    return !base_is_mips16;
 
   if (!mflip_mips16_htab)
     mflip_mips16_htab = htab_create_ggc (37, mflip_mips16_htab_hash,
@@ -1185,7 +1192,7 @@ mflip_mips16_use_mips16_p (tree decl)
       mips16_flipper = !mips16_flipper;
       entry = ggc_alloc_mflip_mips16_entry ();
       entry->name = name;
-      entry->mips16_p = mips16_flipper ? !mips_base_mips16 : mips_base_mips16;
+      entry->mips16_p = mips16_flipper ? !base_is_mips16 : base_is_mips16;
       *slot = entry;
     }
   return entry->mips16_p;
@@ -1207,19 +1214,6 @@ mips_far_type_p (const_tree type)
          || lookup_attribute ("far", TYPE_ATTRIBUTES (type)) != NULL);
 }
 
-/* Similar predicates for "mips16"/"nomips16" function attributes.  */
-
-static bool
-mips_mips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("mips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
-
-static bool
-mips_nomips16_decl_p (const_tree decl)
-{
-  return lookup_attribute ("nomips16", DECL_ATTRIBUTES (decl)) != NULL;
-}
 
 /* Check if the interrupt attribute is set for a function.  */
 
@@ -1257,12 +1251,52 @@ 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 the attributes in ATTRIBUTES.  */
 
-static bool
-mips_use_mips16_mode_p (tree decl)
+static unsigned int
+mips_get_compress_on_flags (tree attributes)
+{
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("mips16", attributes) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("micromips", attributes) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the set of compression modes that are explicitly forbidden
+   by the attributes in ATTRIBUTES.  */
+
+static unsigned int
+mips_get_compress_off_flags (tree attributes)
 {
+  unsigned int flags = 0;
+
+  if (lookup_attribute ("nocompression", attributes) != NULL)
+    flags |= MASK_MIPS16 | MASK_MICROMIPS;
+
+  if (lookup_attribute ("nomips16", attributes) != NULL)
+    flags |= MASK_MIPS16;
+
+  if (lookup_attribute ("nomicromips", attributes) != NULL)
+    flags |= MASK_MICROMIPS;
+
+  return flags;
+}
+
+/* Return the compression mode that should be used for function DECL.
+   Return the ambient setting if DECL is null.  */
+
+static unsigned int
+mips_get_compress_mode (tree decl)
+{
+  unsigned int flags, force_on;
+
+  flags = mips_base_compression_flags;
   if (decl)
     {
       /* Nested functions must use the same frame pointer as their
@@ -1270,12 +1304,36 @@ mips_use_mips16_mode_p (tree decl)
       tree parent = decl_function_context (decl);
       if (parent)
        decl = parent;
-      if (mips_mips16_decl_p (decl))
-       return true;
-      if (mips_nomips16_decl_p (decl))
-       return false;
+      force_on = mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+      if (force_on)
+       return force_on;
+      flags &= ~mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
     }
-  return mips_base_mips16;
+  return flags;
+}
+
+/* Return the attribute name associated with MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_on_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "mips16";
+  return "micromips";
+}
+
+/* Return the attribute name that forbids MASK_MIPS16 and MASK_MICROMIPS
+   flags FLAGS.  */
+
+static const char *
+mips_get_compress_off_name (unsigned int flags)
+{
+  if (flags == MASK_MIPS16)
+    return "nomips16";
+  if (flags == MASK_MICROMIPS)
+    return "nomicromips";
+  return "nocompression";
 }
 
 /* Implement TARGET_COMP_TYPE_ATTRIBUTES.  */
@@ -1297,37 +1355,50 @@ static void
 mips_insert_attributes (tree decl, tree *attributes)
 {
   const char *name;
-  bool mips16_p, nomips16_p;
+  unsigned int compression_flags, nocompression_flags;
 
   /* Check for "mips16" and "nomips16" attributes.  */
-  mips16_p = lookup_attribute ("mips16", *attributes) != NULL;
-  nomips16_p = lookup_attribute ("nomips16", *attributes) != NULL;
+  compression_flags = mips_get_compress_on_flags (*attributes);
+  nocompression_flags = mips_get_compress_off_flags (*attributes);
+
   if (TREE_CODE (decl) != FUNCTION_DECL)
     {
-      if (mips16_p)
-       error ("%qs attribute only applies to functions", "mips16");
-      if (nomips16_p)
-       error ("%qs attribute only applies to functions", "nomips16");
+      if (nocompression_flags)
+       error ("%qs attribute only applies to functions",
+              mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags)
+       error ("%qs attribute only applies to functions",
+              mips_get_compress_on_name (nocompression_flags));
     }
   else
     {
-      mips16_p |= mips_mips16_decl_p (decl);
-      nomips16_p |= mips_nomips16_decl_p (decl);
-      if (mips16_p || nomips16_p)
-       {
-         /* DECL cannot be simultaneously "mips16" and "nomips16".  */
-         if (mips16_p && nomips16_p)
-           error ("%qE cannot have both %<mips16%> and "
-                  "%<nomips16%> attributes",
-                  DECL_NAME (decl));
-       }
-      else if (TARGET_FLIP_MIPS16 && !DECL_ARTIFICIAL (decl))
+      compression_flags |= mips_get_compress_on_flags (DECL_ATTRIBUTES (decl));
+      nocompression_flags |=
+       mips_get_compress_off_flags (DECL_ATTRIBUTES (decl));
+
+      if (compression_flags && nocompression_flags)
+       error ("%qE cannot have both %qs and %qs attributes",
+              DECL_NAME (decl), mips_get_compress_on_name (compression_flags),
+              mips_get_compress_off_name (nocompression_flags));
+
+      if (compression_flags & MASK_MIPS16
+          && compression_flags & MASK_MICROMIPS)
+       error ("%qE cannot have both %qs and %qs attributes",
+              DECL_NAME (decl), "mips16", "micromips");
+
+      if (TARGET_FLIP_MIPS16
+         && !DECL_ARTIFICIAL (decl)
+         && compression_flags == 0
+         && nocompression_flags == 0)
        {
          /* Implement -mflip-mips16.  If DECL has neither a "nomips16" nor a
             "mips16" attribute, arbitrarily pick one.  We must pick the same
             setting for duplicate declarations of a function.  */
          name = mflip_mips16_use_mips16_p (decl) ? "mips16" : "nomips16";
          *attributes = tree_cons (get_identifier (name), NULL, *attributes);
+         name = "nomicromips";
+         *attributes = tree_cons (get_identifier (name), NULL, *attributes);
        }
     }
 }
@@ -1337,13 +1408,19 @@ mips_insert_attributes (tree decl, tree *attributes)
 static tree
 mips_merge_decl_attributes (tree olddecl, tree newdecl)
 {
-  /* The decls' "mips16" and "nomips16" attributes must match exactly.  */
-  if (mips_mips16_decl_p (olddecl) != mips_mips16_decl_p (newdecl))
+  unsigned int diff;
+
+  diff = (mips_get_compress_on_flags (DECL_ATTRIBUTES (olddecl))
+         ^ mips_get_compress_on_flags (DECL_ATTRIBUTES (newdecl)));
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-          DECL_NAME (newdecl), "mips16");
-  if (mips_nomips16_decl_p (olddecl) != mips_nomips16_decl_p (newdecl))
+          DECL_NAME (newdecl), mips_get_compress_on_name (diff));
+
+  diff = (mips_get_compress_off_flags (DECL_ATTRIBUTES (olddecl))
+         ^ mips_get_compress_off_flags (DECL_ATTRIBUTES (newdecl)));
+  if (diff)
     error ("%qE redeclared with conflicting %qs attributes",
-          DECL_NAME (newdecl), "nomips16");
+          DECL_NAME (newdecl), mips_get_compress_off_name (diff));
 
   return merge_attributes (DECL_ATTRIBUTES (olddecl),
                           DECL_ATTRIBUTES (newdecl));
@@ -1550,7 +1627,7 @@ mips16_local_function_p (const_rtx x)
   return (GET_CODE (x) == SYMBOL_REF
          && SYMBOL_REF_LOCAL_P (x)
          && !SYMBOL_REF_EXTERNAL_P (x)
-         && mips_use_mips16_mode_p (SYMBOL_REF_DECL (x)));
+         && (mips_get_compress_mode (SYMBOL_REF_DECL (x)) & MASK_MIPS16));
 }
 
 /* Return true if SYMBOL_REF X binds locally.  */
@@ -2300,6 +2377,20 @@ mips_address_insns (rtx x, enum machine_mode mode, bool might_split_p)
   return 0;
 }
 
+/* Return true if X is a legitimate address with a 12-bit offset.
+   MODE is the mode of the value being accessed.  */
+
+bool
+umips_12bit_offset_address_p (rtx x, enum machine_mode mode)
+{
+  struct mips_address_info addr;
+
+  return (mips_classify_address (&addr, x, mode, false)
+         && addr.type == ADDRESS_REG
+         && CONST_INT_P (addr.offset)
+         && UMIPS_12BIT_OFFSET_P (INTVAL (addr.offset)));
+}
+
 /* Return the number of instructions needed to load constant X.
    Return 0 if X isn't a valid constant.  */
 
@@ -6097,6 +6188,13 @@ mips_start_function_definition (const char *name, bool mips16_p)
   else
     fprintf (asm_out_file, "\t.set\tnomips16\n");
 
+  if (TARGET_MICROMIPS)
+    fprintf (asm_out_file, "\t.set\tmicromips\n");
+#ifdef HAVE_GAS_MICROMIPS
+  else
+    fprintf (asm_out_file, "\t.set\tnomicromips\n");
+#endif
+
   if (!flag_inhibit_size_directive)
     {
       fputs ("\t.ent\t", asm_out_file);
@@ -6903,6 +7001,37 @@ mips_split_call (rtx insn, rtx call_pattern)
     mips_restore_gp_from_cprestore_slot (gen_rtx_REG (Pmode, GP_ARG_FIRST + 2));
 }
 
+/* Return true if a call to DECL may need to use JALX.  */
+
+static bool
+mips_call_may_need_jalx_p (tree decl)
+{
+  /* If the current translation unit would use a different mode for DECL,
+     assume that the call needs JALX.  */
+  if (mips_get_compress_mode (decl) != TARGET_COMPRESSION)
+    return true;
+
+  /* mips_get_compress_mode is always accurate for locally-binding
+     functions in the current translation unit.  */
+  if (!DECL_EXTERNAL (decl) && targetm.binds_local_p (decl))
+    return false;
+
+  /* When -minterlink-compressed is in effect, assume that functions
+     could use a different encoding mode unless an attribute explicitly
+     tells us otherwise.  */
+  if (TARGET_INTERLINK_COMPRESSED)
+    {
+      if (!TARGET_COMPRESSION
+         && mips_get_compress_off_flags (DECL_ATTRIBUTES (decl)) ==0)
+       return true;
+      if (TARGET_COMPRESSION
+         && mips_get_compress_on_flags (DECL_ATTRIBUTES (decl)) == 0)
+       return true;
+    }
+
+  return false;
+}
+
 /* Implement TARGET_FUNCTION_OK_FOR_SIBCALL.  */
 
 static bool
@@ -6916,23 +7045,11 @@ mips_function_ok_for_sibcall (tree decl, tree exp ATTRIBUTE_UNUSED)
   if (mips_interrupt_type_p (TREE_TYPE (current_function_decl)))
     return false;
 
-  /* We can't do a sibcall if the called function is a MIPS16 function
-     because there is no direct "jx" instruction equivalent to "jalx" to
-     switch the ISA mode.  We only care about cases where the sibling
-     and normal calls would both be direct.  */
+  /* Direct Js are only possible to functions that use the same ISA encoding.
+     There is no JX counterpoart of JALX.  */
   if (decl
-      && mips_use_mips16_mode_p (decl)
-      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
-    return false;
-
-  /* When -minterlink-mips16 is in effect, assume that non-locally-binding
-     functions could be MIPS16 ones unless an attribute explicitly tells
-     us otherwise.  */
-  if (TARGET_INTERLINK_MIPS16
-      && decl
-      && (DECL_EXTERNAL (decl) || !targetm.binds_local_p (decl))
-      && !mips_nomips16_decl_p (decl)
-      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode))
+      && const_call_insn_operand (XEXP (DECL_RTL (decl), 0), VOIDmode)
+      && mips_call_may_need_jalx_p (decl))
     return false;
 
   /* Otherwise OK.  */
@@ -7798,6 +7915,9 @@ mips_pop_asm_switch (struct mips_asm_switch *asm_switch)
    '^' Print the name of the pic call-through register (t9 or $25).
    '+' Print the name of the gp register (usually gp or $28).
    '$' Print the name of the stack pointer register (sp or $29).
+   ':'  Print "c" to use the compact version if the delay slot is a nop.
+   '!'  Print "s" to use the short version if the delay slot contains a
+       16-bit instruction.
 
    See also mips_init_print_operand_pucnt.  */
 
@@ -7881,6 +8001,20 @@ mips_print_operand_punctuation (FILE *file, int ch)
       fputs (reg_names[STACK_POINTER_REGNUM], file);
       break;
 
+    case ':':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+        use the compact version for microMIPS.  */
+      if (final_sequence == 0)
+       putc ('c', file);
+      break;
+
+    case '!':
+      /* When final_sequence is 0, the delay slot will be a nop.  We can
+        a 16-bit delay slot for microMIPS.  */
+      if (final_sequence == 0)
+       putc ('s', file);
+      break;
+
     default:
       gcc_unreachable ();
       break;
@@ -7894,7 +8028,7 @@ mips_init_print_operand_punct (void)
 {
   const char *p;
 
-  for (p = "()[]<>*#/?~.@^+$"; *p; p++)
+  for (p = "()[]<>*#/?~.@^+$:!"; *p; p++)
     mips_print_operand_punct[(unsigned char) *p] = true;
 }
 
@@ -10236,6 +10370,126 @@ mips_for_each_saved_acc (HOST_WIDE_INT sp_offset, mips_save_restore_fn fn)
       }
 }
 
+/* Save register REG to MEM.  Make the instruction frame-related.  */
+
+static void
+mips_save_reg (rtx reg, rtx mem)
+{
+  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
+    {
+      rtx x1, x2;
+
+      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
+
+      x1 = mips_frame_set (mips_subword (mem, false),
+                          mips_subword (reg, false));
+      x2 = mips_frame_set (mips_subword (mem, true),
+                          mips_subword (reg, true));
+      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
+    }
+  else
+    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
+}
+
+/* Capture the register combinations that are allowed in a SWM or LWM
+   instruction.  The entries are ordered by number of registers set in
+   the mask.  We also ignore the single register encodings because a
+   normal SW/LW is preferred.  */
+
+static const unsigned int umips_swm_mask[17] = {
+  0xc0ff0000, 0x80ff0000, 0x40ff0000, 0x807f0000,
+  0x00ff0000, 0x803f0000, 0x007f0000, 0x801f0000,
+  0x003f0000, 0x800f0000, 0x001f0000, 0x80070000,
+  0x000f0000, 0x80030000, 0x00070000, 0x80010000,
+  0x00030000
+};
+
+static const unsigned int umips_swm_encoding[17] = {
+  25, 24, 9, 23, 8, 22, 7, 21, 6, 20, 5, 19, 4, 18, 3, 17, 2
+};
+
+/* Try to use a microMIPS LWM or SWM instruction to save or restore
+   as many GPRs in *MASK as possible.  *OFFSET is the offset from the
+   stack pointer of the topmost save slot.
+
+   Remove from *MASK all registers that were handled using LWM and SWM.
+   Update *OFFSET so that it points to the first unused save slot.  */
+
+static bool
+umips_build_save_restore (mips_save_restore_fn fn,
+                         unsigned *mask, HOST_WIDE_INT *offset)
+{
+  int nregs;
+  unsigned int i, j;
+  rtx pattern, set, reg, mem;
+  HOST_WIDE_INT this_offset;
+  rtx this_base;
+
+  /* Try matching $16 to $31 (s0 to ra).  */
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if ((*mask & 0xffff0000) == umips_swm_mask[i])
+      break;
+
+  if (i == ARRAY_SIZE (umips_swm_mask))
+    return false;
+
+  /* Get the offset of the lowest save slot.  */
+  nregs = (umips_swm_encoding[i] & 0xf) + (umips_swm_encoding[i] >> 4);
+  this_offset = *offset - UNITS_PER_WORD * (nregs - 1);
+
+  /* LWM/SWM can only support offsets from -2048 to 2047.  */
+  if (!UMIPS_12BIT_OFFSET_P (this_offset))
+    return false;
+
+  /* Create the final PARALLEL.  */
+  pattern = gen_rtx_PARALLEL (VOIDmode, rtvec_alloc (nregs));
+  this_base = stack_pointer_rtx;
+
+  /* For registers $16-$23 and $30.  */
+  for (j = 0; j < (umips_swm_encoding[i] & 0xf); j++)
+    {
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      unsigned int regno = (j != 8) ? 16 + j : 30;
+      *mask &= ~(1 << regno);
+      reg = gen_rtx_REG (SImode, regno);
+      if (fn == mips_save_reg)
+       set = mips_frame_set (mem, reg);
+      else
+       {
+         set = gen_rtx_SET (VOIDmode, reg, mem);
+         mips_add_cfa_restore (reg);
+       }
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  /* For register $31.  */
+  if (umips_swm_encoding[i] >> 4)
+    {
+      HOST_WIDE_INT offset = this_offset + j * UNITS_PER_WORD;
+      *mask &= ~(1 << 31);
+      mem = gen_frame_mem (SImode, plus_constant (Pmode, this_base, offset));
+      reg = gen_rtx_REG (SImode, 31);
+      if (fn == mips_save_reg)
+       set = mips_frame_set (mem, reg);
+      else
+       {
+         set = gen_rtx_SET (VOIDmode, reg, mem);
+         mips_add_cfa_restore (reg);
+       }
+      XVECEXP (pattern, 0, j) = set;
+    }
+
+  pattern = emit_insn (pattern);
+  if (fn == mips_save_reg)
+    RTX_FRAME_RELATED_P (pattern) = 1;
+
+  /* Adjust the last offset.  */
+  *offset -= UNITS_PER_WORD * nregs;
+
+  return true;
+}
+
 /* Call FN for each register that is saved by the current function.
    SP_OFFSET is the offset of the current stack pointer from the start
    of the frame.  */
@@ -10245,16 +10499,23 @@ mips_for_each_saved_gpr_and_fpr (HOST_WIDE_INT sp_offset,
                                 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;
+  unsigned int mask;
 
   /* Save registers starting from high to low.  The debuggers prefer at least
      the return register be stored at func+4, and also it allows us not to
      need a nop in the epilogue if at least one register is reloaded in
      addition to return address.  */
-  offset = cfun->machine->frame.gp_sp_offset - sp_offset;
+  offset = frame->gp_sp_offset - sp_offset;
+  mask = frame->mask;
+
+  if (TARGET_MICROMIPS)
+    umips_build_save_restore (fn, &mask, &offset);
+
   for (regno = GP_REG_LAST; regno >= GP_REG_FIRST; regno--)
-    if (BITSET_P (cfun->machine->frame.mask, regno - GP_REG_FIRST))
+    if (BITSET_P (mask, regno - GP_REG_FIRST))
       {
        /* Record the ra offset for use by mips_function_profiler.  */
        if (regno == RETURN_ADDR_REGNUM)
@@ -10501,26 +10762,6 @@ mips_frame_barrier (void)
   emit_clobber (gen_frame_mem (BLKmode, stack_pointer_rtx));
 }
 
-/* Save register REG to MEM.  Make the instruction frame-related.  */
-
-static void
-mips_save_reg (rtx reg, rtx mem)
-{
-  if (GET_MODE (reg) == DFmode && !TARGET_FLOAT64)
-    {
-      rtx x1, x2;
-
-      mips_emit_move_or_split (mem, reg, SPLIT_IF_NECESSARY);
-
-      x1 = mips_frame_set (mips_subword (mem, false),
-                          mips_subword (reg, false));
-      x2 = mips_frame_set (mips_subword (mem, true),
-                          mips_subword (reg, true));
-      mips_set_frame_expr (gen_rtx_PARALLEL (VOIDmode, gen_rtvec (2, x1, x2)));
-    }
-  else
-    mips_emit_save_slot_move (mem, reg, MIPS_PROLOGUE_TEMP (GET_MODE (reg)));
-}
 
 /* The __gnu_local_gp symbol.  */
 
@@ -11239,7 +11480,7 @@ mips_expand_epilogue (bool sibcall_p)
          mips_emit_move (gen_rtx_REG (word_mode, K0_REG_NUM), mem);
          offset -= UNITS_PER_WORD;
 
-         /* If we don't use shoadow register set, we need to update SP.  */
+         /* If we don't use shadow register set, we need to update SP.  */
          if (!cfun->machine->use_shadow_register_set_p)
            mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
          else
@@ -11254,6 +11495,7 @@ mips_expand_epilogue (bool sibcall_p)
        /* Deallocate the final bit of the frame.  */
        mips_deallocate_stack (stack_pointer_rtx, GEN_INT (step2), 0);
     }
+
   gcc_assert (!mips_epilogue.cfa_restores);
 
   /* Add in the __builtin_eh_return stack adjustment.  We need to
@@ -16211,17 +16453,19 @@ mips_output_mi_thunk (FILE *file, tree thunk_fndecl ATTRIBUTE_UNUSED,
   reload_completed = 0;
 }
 \f
-/* The last argument passed to mips_set_mips16_mode, or negative if the
-   function hasn't been called yet.  */
-static int was_mips16_p = -1;
 
-/* Set up the target-dependent global state so that it matches the
-   current function's ISA mode.  */
+/* The last argument passed to mips_set_compression_mode,
+   or negative if the function hasn't been called yet.  */
+static unsigned int old_compression_mode = -1;
+
+/* Set up the target-dependent global state for ISA mode COMPRESSION_MODE,
+   which is either MASK_MIPS16 or MASK_MICROMIPS.  */
 
 static void
-mips_set_mips16_mode (int mips16_p)
+mips_set_compression_mode (unsigned int compression_mode)
 {
-  if (mips16_p == was_mips16_p)
+
+  if (compression_mode == old_compression_mode)
     return;
 
   /* Restore base settings of various flags.  */
@@ -16232,8 +16476,10 @@ mips_set_mips16_mode (int mips16_p)
   align_loops = mips_base_align_loops;
   align_jumps = mips_base_align_jumps;
   align_functions = mips_base_align_functions;
+  target_flags &= ~(MASK_MIPS16 | MASK_MICROMIPS);
+  target_flags |= compression_mode;
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       /* Switch to MIPS16 mode.  */
       target_flags |= MASK_MIPS16;
@@ -16287,8 +16533,11 @@ mips_set_mips16_mode (int mips16_p)
     }
   else
     {
-      /* Switch to normal (non-MIPS16) mode.  */
-      target_flags &= ~MASK_MIPS16;
+      /* Switch to microMIPS or the standard encoding.  */
+
+      if (TARGET_MICROMIPS)
+       /* Avoid branch likely.  */
+       target_flags &= ~MASK_BRANCHLIKELY;
 
       /* Provide default values for align_* for 64-bit targets.  */
       if (TARGET_64BIT)
@@ -16310,7 +16559,7 @@ mips_set_mips16_mode (int mips16_p)
   /* (Re)initialize MIPS target internals for new ISA.  */
   mips_init_relocs ();
 
-  if (mips16_p)
+  if (compression_mode & MASK_MIPS16)
     {
       if (!mips16_globals)
        mips16_globals = save_target_globals_default_opts ();
@@ -16320,16 +16569,17 @@ mips_set_mips16_mode (int mips16_p)
   else
     restore_target_globals (&default_target_globals);
 
-  was_mips16_p = mips16_p;
+  old_compression_mode = compression_mode;
 }
 
 /* Implement TARGET_SET_CURRENT_FUNCTION.  Decide whether the current
-   function should use the MIPS16 ISA and switch modes accordingly.  */
+   function should use the MIPS16 or microMIPS ISA and switch modes
+   accordingly.  */
 
 static void
 mips_set_current_function (tree fndecl)
 {
-  mips_set_mips16_mode (mips_use_mips16_mode_p (fndecl));
+  mips_set_compression_mode (mips_get_compress_mode (fndecl));
 }
 \f
 /* Allocate a chunk of memory for per-function machine-dependent data.  */
@@ -16437,14 +16687,19 @@ mips_option_override (void)
   if (global_options_set.x_mips_isa_option)
     mips_isa_option_info = &mips_cpu_info_table[mips_isa_option];
 
-  /* Process flags as though we were generating non-MIPS16 code.  */
-  mips_base_mips16 = TARGET_MIPS16;
-  target_flags &= ~MASK_MIPS16;
-
 #ifdef SUBTARGET_OVERRIDE_OPTIONS
   SUBTARGET_OVERRIDE_OPTIONS;
 #endif
 
+  /* MIPS16 and microMIPS cannot coexist.  */
+  if (TARGET_MICROMIPS && TARGET_MIPS16)
+    error ("unsupported combination: %s", "-mips16 -mmicromips");
+
+  /* Save the base compression state and process flags as though we
+     were generating uncompressed code.  */
+  mips_base_compression_flags = TARGET_COMPRESSION;
+  target_flags &= ~TARGET_COMPRESSION;
+
   /* -mno-float overrides -mhard-float and -msoft-float.  */
   if (TARGET_NO_FLOAT)
     {
@@ -16453,7 +16708,7 @@ mips_option_override (void)
     }
 
   if (TARGET_FLIP_MIPS16)
-    TARGET_INTERLINK_MIPS16 = 1;
+    TARGET_INTERLINK_COMPRESSED = 1;
 
   /* Set the small data limit.  */
   mips_small_data_threshold = (global_options_set.x_g_switch_value
@@ -16826,9 +17081,9 @@ mips_option_override (void)
 
   /* Now select the ISA mode.
 
-     Do all CPP-sensitive stuff in non-MIPS16 mode; we'll switch to
-     MIPS16 mode afterwards if need be.  */
-  mips_set_mips16_mode (false);
+     Do all CPP-sensitive stuff in uncompressed mode; we'll switch modes
+     later if required.  */
+  mips_set_compression_mode (0);
 }
 
 /* Swap the register information for registers I and I + 1, which
@@ -17088,6 +17343,277 @@ mips_mulsidi3_gen_fn (enum rtx_code ext_code)
       return signed_p ? gen_mulsidi3_32bit : gen_umulsidi3_32bit;
     }
 }
+
+/* Return true if PATTERN matches the kind of instruction generated by
+   umips_build_save_restore.  SAVE_P is true for store.  */
+
+bool
+umips_save_restore_pattern_p (bool save_p, rtx pattern)
+{
+  int n;
+  unsigned int i;
+  HOST_WIDE_INT first_offset = 0;
+  rtx first_base = 0;
+  unsigned int regmask = 0;
+
+  for (n = 0; n < XVECLEN (pattern, 0); n++)
+    {
+      rtx set, reg, mem, this_base;
+      HOST_WIDE_INT this_offset;
+
+      /* Check that we have a SET.  */
+      set = XVECEXP (pattern, 0, n);
+      if (GET_CODE (set) != SET)
+       return false;
+
+      /* Check that the SET is a load (if restoring) or a store
+        (if saving).  */
+      mem = save_p ? SET_DEST (set) : SET_SRC (set);
+      if (!MEM_P (mem) || MEM_VOLATILE_P (mem))
+       return false;
+
+      /* Check that the address is the sum of base and a possibly-zero
+        constant offset.  Determine if the offset is in range.  */
+      mips_split_plus (XEXP (mem, 0), &this_base, &this_offset);
+      if (!REG_P (this_base))
+       return false;
+
+      if (n == 0)
+       {
+         if (!UMIPS_12BIT_OFFSET_P (this_offset))
+           return false;
+         first_base = this_base;
+         first_offset = this_offset;
+       }
+      else
+       {
+         /* Check that the save slots are consecutive.  */
+         if (REGNO (this_base) != REGNO (first_base)
+             || this_offset != first_offset + UNITS_PER_WORD * n)
+           return false;
+       }
+
+      /* Check that SET's other operand is a register.  */
+      reg = save_p ? SET_SRC (set) : SET_DEST (set);
+      if (!REG_P (reg))
+       return false;
+
+      regmask |= 1 << REGNO (reg);
+    }
+
+  for (i = 0; i < ARRAY_SIZE (umips_swm_mask); i++)
+    if (regmask == umips_swm_mask[i])
+      return true;
+
+  return false;
+}
+
+/* Return the assembly instruction for microMIPS LWM or SWM.
+   SAVE_P and PATTERN are as for umips_save_restore_pattern_p.  */
+
+const char *
+umips_output_save_restore (bool save_p, rtx pattern)
+{
+  static char buffer[300];
+  char *s;
+  int n;
+  HOST_WIDE_INT offset;
+  rtx base, mem, set, last_set, last_reg;
+
+  /* Parse the pattern.  */
+  gcc_assert (umips_save_restore_pattern_p (save_p, pattern));
+
+  s = strcpy (buffer, save_p ? "swm\t" : "lwm\t");
+  s += strlen (s);
+  n = XVECLEN (pattern, 0);
+
+  set = XVECEXP (pattern, 0, 0);
+  mem = save_p ? SET_DEST (set) : SET_SRC (set);
+  mips_split_plus (XEXP (mem, 0), &base, &offset);
+
+  last_set = XVECEXP (pattern, 0, n - 1);
+  last_reg = save_p ? SET_SRC (last_set) : SET_DEST (last_set);
+
+  if (REGNO (last_reg) == 31)
+    n--;
+
+  gcc_assert (n <= 9);
+  if (n == 0)
+    ;
+  else if (n == 1)
+    s += sprintf (s, "%s,", reg_names[16]);
+  else if (n < 9)
+    s += sprintf (s, "%s-%s,", reg_names[16], reg_names[15 + n]);
+  else if (n == 9)
+    s += sprintf (s, "%s-%s,%s,", reg_names[16], reg_names[23],
+                 reg_names[30]);
+
+  if (REGNO (last_reg) == 31)
+    s += sprintf (s, "%s,", reg_names[31]);
+
+  s += sprintf (s, "%d(%s)", (int)offset, reg_names[REGNO (base)]);
+  return buffer;
+}
+
+/* Return true if MEM1 and MEM2 use the same base register, and the
+   offset of MEM2 equals the offset of MEM1 plus 4.  FIRST_REG is the
+   register into (from) which the contents of MEM1 will be loaded
+   (stored), depending on the value of LOAD_P.
+   SWAP_P is true when the 1st and 2nd instructions are swapped.  */
+
+static bool
+umips_load_store_pair_p_1 (bool load_p, bool swap_p,
+                          rtx first_reg, rtx mem1, rtx mem2)
+{
+  rtx base1, base2;
+  HOST_WIDE_INT offset1, offset2;
+
+  if (!MEM_P (mem1) || !MEM_P (mem2))
+    return false;
+
+  mips_split_plus (XEXP (mem1, 0), &base1, &offset1);
+  mips_split_plus (XEXP (mem2, 0), &base2, &offset2);
+
+  if (!REG_P (base1) || !rtx_equal_p (base1, base2))
+    return false;
+
+  /* Avoid invalid load pair instructions.  */
+  if (load_p && REGNO (first_reg) == REGNO (base1))
+    return false;
+
+  /* We must avoid this case for anti-dependence.
+     Ex:  lw $3, 4($3)
+          lw $2, 0($3)
+     first_reg is $2, but the base is $3.  */
+  if (load_p
+      && swap_p
+      && REGNO (first_reg) + 1 == REGNO (base1))
+    return false;
+
+  if (offset2 != offset1 + 4)
+    return false;
+
+  if (!UMIPS_12BIT_OFFSET_P (offset1))
+    return false;
+
+  return true;
+}
+
+/* OPERANDS describes the operands to a pair of SETs, in the order
+   dest1, src1, dest2, src2.  Return true if the operands can be used
+   in an LWP or SWP instruction; LOAD_P says which.  */
+
+bool
+umips_load_store_pair_p (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    return umips_load_store_pair_p_1 (load_p, false, reg1, mem1, mem2);
+
+  if (REGNO (reg1) == REGNO (reg2) + 1)
+    return umips_load_store_pair_p_1 (load_p, true, reg2, mem2, mem1);
+
+  return false;
+}
+
+/* Return the assembly instruction for a microMIPS LWP or SWP in which
+   the first register is REG and the first memory slot is MEM.
+   LOAD_P is true for LWP.  */
+
+static void
+umips_output_load_store_pair_1 (bool load_p, rtx reg, rtx mem)
+{
+  rtx ops[] = {reg, mem};
+
+  if (load_p)
+    output_asm_insn ("lwp\t%0,%1", ops);
+  else
+    output_asm_insn ("swp\t%0,%1", ops);
+}
+
+/* Output the assembly instruction for a microMIPS LWP or SWP instruction.
+   LOAD_P and OPERANDS are as for umips_load_store_pair_p.  */
+
+void
+umips_output_load_store_pair (bool load_p, rtx *operands)
+{
+  rtx reg1, reg2, mem1, mem2;
+  if (load_p)
+    {
+      reg1 = operands[0];
+      reg2 = operands[2];
+      mem1 = operands[1];
+      mem2 = operands[3];
+    }
+  else
+    {
+      reg1 = operands[1];
+      reg2 = operands[3];
+      mem1 = operands[0];
+      mem2 = operands[2];
+    }
+
+  if (REGNO (reg2) == REGNO (reg1) + 1)
+    {
+      umips_output_load_store_pair_1 (load_p, reg1, mem1);
+      return;
+    }
+
+  gcc_assert (REGNO (reg1) == REGNO (reg2) + 1);
+  umips_output_load_store_pair_1 (load_p, reg2, mem2);
+}
+
+/* Return true if REG1 and REG2 match the criteria for a movep insn.  */
+
+bool
+umips_movep_target_p (rtx reg1, rtx reg2)
+{
+  int regno1, regno2, pair;
+  unsigned int i;
+  static const int match[8] = {
+    0x00000060, /* 5, 6 */
+    0x000000a0, /* 5, 7 */
+    0x000000c0, /* 6, 7 */
+    0x00200010, /* 4, 21 */
+    0x00400010, /* 4, 22 */
+    0x00000030, /* 4, 5 */
+    0x00000050, /* 4, 6 */
+    0x00000090  /* 4, 7 */
+  };
+
+  if (!REG_P (reg1) || !REG_P (reg2))
+    return false;
+
+  regno1 = REGNO (reg1);
+  regno2 = REGNO (reg2);
+
+  if (!GP_REG_P (regno1) || !GP_REG_P (regno2))
+    return false;
+
+  pair = (1 << regno1) | (1 << regno2);
+
+  for (i = 0; i < ARRAY_SIZE (match); i++)
+    if (pair == match[i])
+      return true;
+
+  return false;
+}
 \f
 /* Return the size in bytes of the trampoline code, padded to
    TRAMPOLINE_ALIGNMENT bits.  The static chain pointer and target
@@ -17342,7 +17868,7 @@ mips_prepare_pch_save (void)
      It therefore seems best to switch back to non-MIPS16 mode at
      save time, and to ensure that mips16_globals remains null after
      a PCH load.  */
-  mips_set_mips16_mode (false);
+  mips_set_compression_mode (0);
   mips16_globals = 0;
 }
 \f
index 0acce14bd8c92c0f04f835f6e163650b7f109360..0db36988dcccf55c7a50416a35ab72ed80094aba 100644 (file)
@@ -174,6 +174,9 @@ struct mips_cpu_info {
 #define ISA_HAS_DSP_MULT ISA_HAS_DSPR2
 #endif
 
+/* The ISA compression flags that are currently in effect.  */
+#define TARGET_COMPRESSION (target_flags & (MASK_MIPS16 | MASK_MICROMIPS))
+
 /* Generate mips16 code */
 #define TARGET_MIPS16          ((target_flags & MASK_MIPS16) != 0)
 /* Generate mips16e code. Default 16bit ASE for mips32* and mips64* */
@@ -374,7 +377,7 @@ struct mips_cpu_info {
       else                                                             \
        builtin_define ("__mips_fpr=32");                               \
                                                                        \
-      if (mips_base_mips16)                                            \
+      if (mips_base_compression_flags & MASK_MIPS16)                   \
        builtin_define ("__mips16");                                    \
                                                                        \
       if (TARGET_MIPS3D)                                               \
@@ -383,6 +386,9 @@ struct mips_cpu_info {
       if (TARGET_SMARTMIPS)                                            \
        builtin_define ("__mips_smartmips");                            \
                                                                        \
+      if (mips_base_compression_flags & MASK_MICROMIPS)                        \
+       builtin_define ("__mips_micromips");                            \
+                                                                       \
       if (TARGET_MCU)                                                  \
        builtin_define ("__mips_mcu");                                  \
                                                                        \
@@ -702,7 +708,7 @@ struct mips_cpu_info {
        |march=r10000|march=r12000|march=r14000|march=r16000:-mips4} \
      %{march=mips32|march=4kc|march=4km|march=4kp|march=4ksc:-mips32} \
      %{march=mips32r2|march=m4k|march=4ke*|march=4ksd|march=24k* \
-       |march=34k*|march=74k*|march=1004k*: -mips32r2} \
+       |march=34k*|march=74k*|march=m14k*|march=1004k*: -mips32r2} \
      %{march=mips64|march=5k*|march=20k*|march=sb1*|march=sr71000 \
        |march=xlr|march=loongson3a: -mips64} \
      %{march=mips64r2|march=octeon|march=xlp: -mips64r2} \
@@ -716,7 +722,7 @@ struct mips_cpu_info {
   "%{mhard-float|msoft-float|mno-float|march=mips*:; \
      march=vr41*|march=m4k|march=4k*|march=24kc|march=24kec \
      |march=34kc|march=34kn|march=74kc|march=1004kc|march=5kc \
-     |march=octeon|march=xlr: -msoft-float;              \
+     |march=m14k*|march=octeon|march=xlr: -msoft-float;                  \
      march=*: -mhard-float}"
 
 /* A spec condition that matches 32-bit options.  It only works if
@@ -989,7 +995,8 @@ struct mips_cpu_info {
                                     || ISA_MIPS64R2))
 
 /* ISA has lwxs instruction (load w/scaled index address.  */
-#define ISA_HAS_LWXS           (TARGET_SMARTMIPS && !TARGET_MIPS16)
+#define ISA_HAS_LWXS           ((TARGET_SMARTMIPS || TARGET_MICROMIPS) \
+                                && !TARGET_MIPS16)
 
 /* ISA has lbx, lbux, lhx, lhx, lhux, lwx, lwux, or ldx instruction. */
 #define ISA_HAS_LBX            (TARGET_OCTEON2)
@@ -1012,7 +1019,8 @@ struct mips_cpu_info {
    and "addiu $4,$4,1".  */
 #define ISA_HAS_LOAD_DELAY     (ISA_MIPS1                              \
                                 && !TARGET_MIPS3900                    \
-                                && !TARGET_MIPS16)
+                                && !TARGET_MIPS16                      \
+                                && !TARGET_MICROMIPS)
 
 /* Likewise mtc1 and mfc1.  */
 #define ISA_HAS_XFER_DELAY     (mips_isa <= 3                  \
@@ -1123,6 +1131,7 @@ struct mips_cpu_info {
 %{G*} %(endian_spec) %{mips1} %{mips2} %{mips3} %{mips4} \
 %{mips32*} %{mips64*} \
 %{mips16} %{mno-mips16:-no-mips16} \
+%{mmicromips} %{mno-micromips} \
 %{mips3d} %{mno-mips3d:-no-mips3d} \
 %{mdmx} %{mno-mdmx:-no-mdmx} \
 %{mdsp} %{mno-dsp} \
@@ -1672,6 +1681,8 @@ struct mips_cpu_info {
   ((unsigned int) ((int) (REGNO) - GP_REG_FIRST) < GP_REG_NUM)
 #define M16_REG_P(REGNO) \
   (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 16 || (REGNO) == 17)
+#define M16STORE_REG_P(REGNO) \
+  (((REGNO) >= 2 && (REGNO) <= 7) || (REGNO) == 0 || (REGNO) == 17)
 #define FP_REG_P(REGNO)  \
   ((unsigned int) ((int) (REGNO) - FP_REG_FIRST) < FP_REG_NUM)
 #define MD_REG_P(REGNO) \
@@ -2034,6 +2045,7 @@ enum reg_class
 #define SMALL_INT(X) SMALL_OPERAND (INTVAL (X))
 #define SMALL_INT_UNSIGNED(X) SMALL_OPERAND_UNSIGNED (INTVAL (X))
 #define LUI_INT(X) LUI_OPERAND (INTVAL (X))
+#define UMIPS_12BIT_OFFSET_P(OFFSET) (IN_RANGE (OFFSET, -2048, 2047))
 
 /* The HI and LO registers can only be reloaded via the general
    registers.  Condition code registers can only be loaded to the
@@ -2452,17 +2464,32 @@ typedef struct mips_args {
    all calls should use assembly macros.  Otherwise, all indirect
    calls should use "jr" or "jalr"; we will arrange to restore $gp
    afterwards if necessary.  Finally, we can only generate direct
-   calls for -mabicalls by temporarily switching to non-PIC mode.  */
+   calls for -mabicalls by temporarily switching to non-PIC mode.
+
+   For microMIPS jal(r), we try to generate jal(r)s when a 16-bit
+   instruction is in the delay slot of jal(r).  */
 #define MIPS_CALL(INSN, OPERANDS, TARGET_OPNO, SIZE_OPNO)      \
   (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS                   \
    ? "%*" INSN "\t%" #TARGET_OPNO "%/"                         \
-   : (REG_P (OPERANDS[TARGET_OPNO])                            \
-      && mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO))       \
-   ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"             \
-      "1:\t" INSN "r\t%" #TARGET_OPNO "%/")                    \
    : REG_P (OPERANDS[TARGET_OPNO])                             \
-   ? "%*" INSN "r\t%" #TARGET_OPNO "%/"                                \
+   ? (mips_get_pic_call_symbol (OPERANDS, SIZE_OPNO)           \
+      ? ("%*.reloc\t1f,R_MIPS_JALR,%" #SIZE_OPNO "\n"          \
+        "1:\t" INSN "r\t%" #TARGET_OPNO "%/")                  \
+      : TARGET_MICROMIPS && !TARGET_INTERLINK_COMPRESSED       \
+      ? "%*" INSN "r%!\t%" #TARGET_OPNO "%/"                   \
+      : "%*" INSN "r\t%" #TARGET_OPNO "%/")                    \
    : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #TARGET_OPNO "%/"))
+
+/* Similar to MIPS_CALL, but this is for MICROMIPS "j" to generate
+   "jrc" when nop is in the delay slot of "jr".  */
+
+#define MICROMIPS_J(INSN, OPERANDS, OPNO)                      \
+  (TARGET_USE_GOT && !TARGET_EXPLICIT_RELOCS                   \
+   ? "%*j\t%" #OPNO "%/"                                       \
+   : REG_P (OPERANDS[OPNO])                                    \
+   ? "%*jr%:\t%" #OPNO                                         \
+   : MIPS_ABSOLUTE_JUMP ("%*" INSN "\t%" #OPNO "%/"))
+
 \f
 /* Control the assembler format that we output.  */
 
@@ -2877,7 +2904,7 @@ extern enum processor mips_tune;        /* which cpu to schedule for */
 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 7aa461dbd695467e45c17a9566ae764c2a02eddb..bbcc5c9b797d93828ad6844662cdd308c87bbdae 100644 (file)
 ;; 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")
 
 
 ;; 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
          ;; from the shorten_branches reference address.
          (and (eq_attr "type" "branch")
               (not (match_test "TARGET_MIPS16")))
-         (cond [(and (le (minus (match_dup 0) (pc)) (const_int 131064))
-                     (le (minus (pc) (match_dup 0)) (const_int 131068)))
+         (cond [;; Any variant can handle the 17-bit range.
+                (and (le (minus (match_dup 0) (pc)) (const_int 65532))
+                     (le (minus (pc) (match_dup 0)) (const_int 65534)))
+                  (const_int 4)
+
+                ;; The 18-bit range is OK other than for microMIPS.
+                (and (not (match_test "TARGET_MICROMIPS"))
+                     (and (le (minus (match_dup 0) (pc)) (const_int 131064))
+                          (le (minus (pc) (match_dup 0)) (const_int 131068))))
                   (const_int 4)
 
                 ;; The non-PIC case: branch, first delay slot, and J.
 ;; 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")])
 (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"
 (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])"
 (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"
 (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])"
         (pc)))]
   "!TARGET_MIPS16"
 {
+  /* For a simple BNEZ or BEQZ microMIPS branch.  */
+  if (TARGET_MICROMIPS
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+                                          "%*b%C1z%:\t%2,%0",
+                                          "%*b%N1z%:\t%2,%0");
+
   return mips_output_conditional_branch (insn, operands,
                                         MIPS_BRANCH ("b%C1", "%2,%z3,%0"),
                                         MIPS_BRANCH ("b%N1", "%2,%z3,%0"));
         (label_ref (match_operand 0 "" ""))))]
   "!TARGET_MIPS16"
 {
+  /* For a simple BNEZ or BEQZ microMIPS branch.  */
+  if (TARGET_MICROMIPS
+      && operands[3] == const0_rtx
+      && get_attr_length (insn) <= 8)
+    return mips_output_conditional_branch (insn, operands,
+                                          "%*b%N0z%:\t%2,%1",
+                                          "%*b%C0z%:\t%2,%1");
+
   return mips_output_conditional_branch (insn, operands,
                                         MIPS_BRANCH ("b%N1", "%2,%z3,%0"),
                                         MIPS_BRANCH ("b%C1", "%2,%z3,%0"));
   [(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"
 (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")])
 
        (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")])
 
   [(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")])
 
   [(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")])
 
         (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")])
 
        (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")])
 
 
 
 (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"
 ; MIPS fixed-point instructions.
 (include "mips-fixed.md")
 
+; microMIPS patterns.
+(include "micromips.md")
+
 ; ST-Microelectronics Loongson-2E/2F-specific patterns.
 (include "loongson.md")
 
index d8ef2e7712e9fa6bd8775284fe498525b2c2fc65..f9e88b3cd72451647382e508e3c06daf3b421c5c 100644 (file)
@@ -217,9 +217,13 @@ mhard-float
 Target Report RejectNegative InverseMask(SOFT_FLOAT_ABI, HARD_FLOAT_ABI)
 Allow the use of hardware floating-point ABI and instructions
 
+minterlink-compressed
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+Generate code that is link-compatible with MIPS16 and microMIPS code.
+
 minterlink-mips16
-Target Report Var(TARGET_INTERLINK_MIPS16) Init(0)
-Generate code that can be safely linked with MIPS16 code.
+Target Report Var(TARGET_INTERLINK_COMPRESSED) Init(0)
+An alias for minterlink-compressed provided for backward-compatibility.
 
 mips
 Target RejectNegative Joined ToLower Enum(mips_mips_opt_value) Var(mips_isa_option)
@@ -261,6 +265,10 @@ mmemcpy
 Target Report Mask(MEMCPY)
 Don't optimize block moves
 
+mmicromips
+Target Report Mask(MICROMIPS)
+Use microMIPS instructions
+
 mmt
 Target Report Var(TARGET_MT)
 Allow the use of MT instructions
index 397d541f9be1ca8b0228762e7508b3896655fe59..c6d7707093ee3e70cb4763cd6d1179113f35ba6a 100644 (file)
                    ? M16_REG_P (REGNO (op))
                    : GP_REG_P (REGNO (op))")))
 
+(define_predicate "movep_src_register"
+  (and (match_code "reg")
+       (ior (match_test ("IN_RANGE (REGNO (op), 2, 3)"))
+           (match_test ("IN_RANGE (REGNO (op), 16, 20)")))))
+
+(define_predicate "movep_src_operand"
+  (ior (match_operand 0 "const_0_operand")
+       (match_operand 0 "movep_src_register")))
+
 (define_predicate "lo_operand"
   (and (match_code "reg")
        (match_test "REGNO (op) == LO_REGNUM")))
 (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 3cd8343ef45e5cd4f9c9f00aa52118cca5d4ca52..d40c2246bb1191babcbb62e82e870e4279177d8b 100644 (file)
@@ -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")
    (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"))]
 
 ;; 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")
 ;; 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")
 (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)
 
 ;; 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")
 ;; 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")
 (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")]
    (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"))]
 ;; 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)
 
 (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)
 
 (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
 
 (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
    (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))]
 
 (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")
 
 (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")
    (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"
 
 (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))]
 
 (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))]
 
 (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))]
 
 (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")
        ;; 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")
 
 (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")]
 
 (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 075f8f3da67a20b39c6db4ff177a803afb490fee..15f506f8afe970753baa0c8aa3f919c545a137bd 100644 (file)
@@ -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.
index d4f49bbeceb8d2bed6c0f7f01494364f276ac135..81bc2c6ddc5138b14a605494860c2bb3ec7503eb 100755 (executable)
@@ -25706,6 +25706,37 @@ if test $gcc_cv_as_mips_gnu_attribute = yes; then
 
 $as_echo "#define HAVE_AS_GNU_ATTRIBUTE 1" >>confdefs.h
 
+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
index 811c296cb81c30d7224b76061858432f54cb60c6..b5b79acf823868d24431ab05d799ce95c8613bfa 100644 (file)
@@ -4036,6 +4036,12 @@ LCF0:
       [AC_DEFINE(HAVE_AS_GNU_ATTRIBUTE, 1,
          [Define if your assembler supports .gnu_attribute.])])
 
+    gcc_GAS_CHECK_FEATURE([.micromips support],
+      gcc_cv_as_micromips_support,,,
+      [.set micromips],,
+      [AC_DEFINE(HAVE_GAS_MICROMIPS, 1,
+          [Define if your assembler supports the .set micromips directive])])
+
     gcc_GAS_CHECK_FEATURE([.dtprelword support],
       gcc_cv_as_mips_dtprelword, [2,18,0],,
       [.section .tdata,"awT",@progbits
index eb84408ce7ca253d2018bdb4d17945fbc0b705a8..a644b603b266141727ddb0d5ffedcb8b85e11326 100644 (file)
@@ -3053,6 +3053,25 @@ not that within individual functions.  Mixed MIPS16 and non-MIPS16 code
 may interact badly with some GCC extensions such as @code{__builtin_apply}
 (@pxref{Constructing Calls}).
 
+@item micromips/nomicromips
+@cindex @code{micromips} attribute
+@cindex @code{nomicromips} attribute
+
+On MIPS targets, you can use the @code{micromips} and @code{nomicromips}
+function attributes to locally select or turn off microMIPS code generation.
+A function with the @code{micromips} attribute is emitted as microMIPS code,
+while microMIPS code generation is disabled for functions with the
+@code{nomicromips} attribute.  These attributes override the
+@option{-mmicromips} and @option{-mno-micromips} options on the command line
+(@pxref{MIPS Options}).
+
+When compiling files containing mixed microMIPS and non-microMIPS code, the
+preprocessor symbol @code{__mips_micromips} reflects the setting on the
+command line,
+not that within individual functions.  Mixed microMIPS and non-microMIPS code
+may interact badly with some GCC extensions such as @code{__builtin_apply}
+(@pxref{Constructing Calls}).
+
 @item model (@var{model-name})
 @cindex function addressability on the M32R/D
 @cindex variable addressability on the IA-64
@@ -3155,6 +3174,13 @@ is an NMI handler.  The compiler generates function entry and
 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 cadee0401cee82fe5d008c79d42025d5c8f5ef17..f18d07e248bee38858706f213e26ba02e706ad9d 100644 (file)
@@ -740,6 +740,7 @@ Objective-C and Objective-C++ Dialects}.
 -mips1  -mips2  -mips3  -mips4  -mips32  -mips32r2 @gol
 -mips64  -mips64r2 @gol
 -mips16  -mno-mips16  -mflip-mips16 @gol
+-minterlink-compressed -mno-interlink-compressed @gol
 -minterlink-mips16  -mno-interlink-mips16 @gol
 -mabi=@var{abi}  -mabicalls  -mno-abicalls @gol
 -mshared  -mno-shared  -mplt  -mno-plt  -mxgot  -mno-xgot @gol
@@ -747,6 +748,7 @@ Objective-C and Objective-C++ Dialects}.
 -mno-float -msingle-float  -mdouble-float  @gol
 -mdsp  -mno-dsp  -mdspr2  -mno-dspr2 @gol
 -mmcu -mmno-mcu @gol
+-mmicromips -mno-micromips @gol
 -mfpu=@var{fpu-type} @gol
 -msmartmips  -mno-smartmips @gol
 -mpaired-single  -mno-paired-single  -mdmx  -mno-mdmx @gol
@@ -15880,6 +15882,7 @@ The processor names are:
 @samp{1004kc}, @samp{1004kf2_1}, @samp{1004kf1_1},
 @samp{loongson2e}, @samp{loongson2f}, @samp{loongson3a},
 @samp{m4k},
+@samp{m14k}, @samp{m14ke}, @samp{m14kec},
 @samp{octeon}, @samp{octeon+}, @samp{octeon2},
 @samp{orion},
 @samp{r2000}, @samp{r3000}, @samp{r3900}, @samp{r4000}, @samp{r4400},
@@ -15993,17 +15996,25 @@ Generate MIPS16 code on alternating functions.  This option is provided
 for regression testing of mixed MIPS16/non-MIPS16 code generation, and is
 not intended for ordinary use in compiling user code.
 
+@item -minterlink-compressed
+@item -mno-interlink-compressed
+@opindex minterlink-compressed
+@opindex mno-interlink-compressed
+Require (do not require) that code using the standard (uncompressed) MIPS ISA
+be link-compatible with MIPS16 and microMIPS code, and vice versa.
+
+For example, code using the standard ISA encoding cannot jump directly
+to MIPS16 or microMIPS code; it must either use a call or an indirect jump.
+@option{-minterlink-compressed} therefore disables direct jumps unless GCC
+knows that the target of the jump is not compressed.
+
 @item -minterlink-mips16
 @itemx -mno-interlink-mips16
 @opindex minterlink-mips16
 @opindex mno-interlink-mips16
-Require (do not require) that non-MIPS16 code be link-compatible with
-MIPS16 code.
-
-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.
+Aliases of @option{-minterlink-compressed} and
+@option{-mno-interlink-compressed}.  These options predate the microMIPS ASE
+and are retained for backwards compatiblity.
 
 @item -mabi=32
 @itemx -mabi=o64
@@ -16218,6 +16229,16 @@ hardware floating-point support to be enabled.
 Use (do not use) the MIPS-3D ASE@.  @xref{MIPS-3D Built-in Functions}.
 The option @option{-mips3d} implies @option{-mpaired-single}.
 
+@item -mmicromips
+@itemx -mno-micromips
+@opindex mmicromips
+@opindex mno-mmicromips
+Generate (do not generate) microMIPS code.
+
+MicroMIPS code generation can also be controlled on a per-function basis
+by means of @code{micromips} and @code{nomicromips} attributes.
+@xref{Function Attributes}, for more information.
+
 @item -mmt
 @itemx -mno-mt
 @opindex mmt
index 9739e4f8f79a5eb85ad3bd8153771d128b5c6860..2ece55cec61b190deeba924d8b19734b99ccad2f 100644 (file)
@@ -2916,6 +2916,19 @@ Floating-point zero.
 
 @item R
 An address that can be used in a non-macro load or store.
+
+@item ZC
+When compiling microMIPS code, this constraint matches a memory operand
+whose address is formed from a base register and a 12-bit offset.  These
+operands can be used for microMIPS instructions such as @code{ll} and
+@code{sc}.  When not compiling for microMIPS code, @code{ZC} is
+equivalent to @code{R}.
+
+@item ZD
+When compiling microMIPS code, this constraint matches an address operand
+that is formed from a base register and a 12-bit offset.  These operands
+can be used for microMIPS instructions such as @code{prefetch}.  When
+not compiling for microMIPS code, @code{ZD} is equivalent to @code{p}.
 @end table
 
 @item Motorola 680x0---@file{config/m68k/constraints.md}
index 351cb17d8ee20893a49e1807edc023f795872fa8..9097083229d7d2f8e6ba62f0148cdf5a4e0e26ef 100644 (file)
@@ -1,3 +1,31 @@
+2013-02-24  Catherine Moore  <clm@codesourcery.com>
+           Richard Sandiford <rdsandiford@googlemail.com>
+
+       * gcc.target/mips/mips.exp: Add microMIPS support.
+       * gcc.target/mips/umips-movep-2.c: New test.
+       * gcc.target/mips/umips-lwp-2.c: New test.
+       * gcc.target/mips/umips-swp-5.c: New test.
+       * gcc.target/mips/umips-constraints-1.c: New test.
+       * gcc.target/mips/umips-lwp-3.c: New test.
+       * gcc.target/mips/umips-swp-6.c: New test.
+       * gcc.target/mips/umips-constraints-2.c: New test.
+       * gcc.target/mips/umips-save-restore-1.c: New test.
+       * gcc.target/mips/umips-lwp-4.c: New test.
+       * gcc.target/mips/umips-swp-7.c: New test.
+       * gcc.target/mips/umips-save-restore-2.c: New test.
+       * gcc.target/mips/umips-lwp-swp-volatile.c: New test.
+       * gcc.target/mips/umips-lwp-5.c: New test.
+       * gcc.target/mips/umips-save-restore-3.c: New test.
+       * gcc.target/mips/umips-lwp-6.c: New test.
+       * gcc.target/mips/umips-swp-1.c: New test.
+       * gcc.target/mips/umips-lwp-7.c: New test.
+       * gcc.target/mips/umips-swp-2.c: New test.
+       * gcc.target/mips/umips-lwp-8.c: New test.
+       * gcc.target/mips/umips-swp-3.c: New test.
+       * gcc.target/mips/umips-movep-1.c: New test.
+       * gcc.target/mips/umips-lwp-1.c: New test.
+       * gcc.target/mips/umips-swp-4.c: New test.
+
 2013-02-22  Jakub Jelinek  <jakub@redhat.com>
 
        PR sanitizer/56393
index ad32fb67713b7a0f6e64001a8289eac16ca925d6..15b1386bd9e19a06bb2814a3d8f73c6e9a003862 100644 (file)
@@ -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)"
@@ -816,6 +817,8 @@ proc mips-dg-finish {} {
 #            |                           |
 #         -mips16/-mflip-mips16       -mno-mips16
 #            |                           |
+#         -micromips                  -mno-micromips
+#            |                           |
 #         -mips3d                     -mno-mips3d
 #            |                           |
 #         -mpaired-single             -mno-paired-single
@@ -904,6 +907,8 @@ proc mips-dg-options { args } {
 
     # Handle dependencies between options on the left of the
     # dependency diagram.
+    mips_option_dependency options "-mips16" "-mno-micromips"
+    mips_option_dependency options "-mmicromips" "-mno-mips16"
     mips_option_dependency options "-mips3d" "-mpaired-single"
     mips_option_dependency options "-mpaired-single" "-mfp64"
     mips_option_dependency options "-mfp64" "-mhard-float"
@@ -1246,6 +1251,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 +1284,6 @@ proc mips-gcc-dg-test { prog do_what extra_tool_flags } {
 dg-init
 mips-dg-init
 gcc-dg-runtest [lsort [glob -nocomplain $srcdir/$subdir/*.c]] \
-    "-DNOMIPS16=__attribute__((nomips16))"
+    "-DNOMIPS16=__attribute__((nomips16)) -DNOMICROMIPS=__attribute__((nomicromips)) -DNOCOMPRESSION=__attribute__((nocompression))"
 mips-dg-finish
 dg-finish
diff --git a/gcc/testsuite/gcc.target/mips/umips-constraints-1.c b/gcc/testsuite/gcc.target/mips/umips-constraints-1.c
new file mode 100644 (file)
index 0000000..ddec815
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *x)
+{
+  asm volatile ("insn1\t%a0" :: "ZD" (&x[0]));
+  asm volatile ("insn2\t%a0" :: "ZD" (&x[511]));
+  asm volatile ("insn3\t%a0" :: "ZD" (&x[512]));
+}
+
+/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
+/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
+/* { dg-final { scan-assembler-not "\tinsn3\t2048\\(" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-constraints-2.c b/gcc/testsuite/gcc.target/mips/umips-constraints-2.c
new file mode 100644 (file)
index 0000000..0240d46
--- /dev/null
@@ -0,0 +1,14 @@
+/* { dg-options "(-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *x)
+{
+  asm volatile ("insn1\t%0" :: "ZC" (x[0]));
+  asm volatile ("insn2\t%0" :: "ZC" (x[511]));
+  asm volatile ("insn3\t%0" :: "ZC" (x[512]));
+}
+
+/* { dg-final { scan-assembler "\tinsn1\t0\\(" } } */
+/* { dg-final { scan-assembler "\tinsn2\t2044\\(" } } */
+/* { dg-final { scan-assembler-not "\tinsn3\t2048\\(" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-1.c b/gcc/testsuite/gcc.target/mips/umips-lwp-1.c
new file mode 100644 (file)
index 0000000..0cdb1b7
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[0];
+  int r6 = r4[1];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,0\\(\\\$4\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-2.c b/gcc/testsuite/gcc.target/mips/umips-lwp-2.c
new file mode 100644 (file)
index 0000000..ea3f396
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[0];
+  int r6 = r4[1];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,0\\(\\\$4\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-3.c b/gcc/testsuite/gcc.target/mips/umips-lwp-3.c
new file mode 100644 (file)
index 0000000..2cb3751
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[511];
+  int r6 = r4[512];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,2044\\(\\\$4\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-4.c b/gcc/testsuite/gcc.target/mips/umips-lwp-4.c
new file mode 100644 (file)
index 0000000..b8a86b4
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[511];
+  int r6 = r4[512];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$5,2044\\(\\\$4\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-5.c b/gcc/testsuite/gcc.target/mips/umips-lwp-5.c
new file mode 100644 (file)
index 0000000..2315f21
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[512];
+  int r6 = r4[513];
+  r4[2] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-6.c b/gcc/testsuite/gcc.target/mips/umips-lwp-6.c
new file mode 100644 (file)
index 0000000..9534974
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4)
+{
+  int r5 = r4[512];
+  int r6 = r4[513];
+  r4[2] = r6 * r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[3]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-7.c b/gcc/testsuite/gcc.target/mips/umips-lwp-7.c
new file mode 100644 (file)
index 0000000..87ff6dc
--- /dev/null
@@ -0,0 +1,41 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+f1 (int *r4, int dummy, int *other)
+{
+  int r5 = r4[1];
+  int newr4 = r4[0];
+  other[0] = r5 * r5;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r4asm asm ("$4") = newr4;
+    asm ("#foo" : "=m" (other[1]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+void MICROMIPS
+f2 (int *r4, int dummy, int *other)
+{
+  int newr4 = r4[0];
+  int r5 = *(int *)(newr4 + 4);
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r4asm asm ("$4") = newr4;
+    asm ("#foo" : "=m" (other[0]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+void MICROMIPS
+f3 (int dummy, int *r5, int *other)
+{
+  int newr5 = r5[1];
+  int r4 = *(int *)newr5;
+  {
+    register int r5asm asm ("$4") = r4;
+    register int r4asm asm ("$5") = newr5;
+    asm ("#foo" : "=m" (other[0]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tlwp" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-8.c b/gcc/testsuite/gcc.target/mips/umips-lwp-8.c
new file mode 100644 (file)
index 0000000..43b9842
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-mgp32 -fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+f1 (int dummy, int *r5, int *other)
+{
+  int r4 = r5[0];
+  int newr5 = r5[1];
+  other[0] = r4 * r4;
+  {
+    register int r5asm asm ("$4") = r4;
+    register int r4asm asm ("$5") = newr5;
+    asm ("#foo" : "=m" (other[1]) : "d" (r4asm), "d" (r5asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tlwp\t\\\$4,0\\(\\\$5\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c b/gcc/testsuite/gcc.target/mips/umips-lwp-swp-volatile.c
new file mode 100644 (file)
index 0000000..da2cbaf
--- /dev/null
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "-mmicromips" } */
+
+/* This test ensures that we do not generate microMIPS SWP or LWP
+   instructions when any component of the accessed memory is volatile;
+   they are unsafe for such since they might cause replay of partial
+   accesses if interrupted by an exception.  */
+
+static void set_csr (volatile void *p, int v)
+{
+  *(volatile int *) (p) = v;
+}
+
+static int get_csr (volatile void *p)
+{
+  return *(volatile int *) (p);
+}
+
+int main ()
+{
+  int i, q = 0, p = 0, r = 0;
+
+  for (i = 0; i < 20; i++)
+    {
+      set_csr ((volatile void *) 0xbf0100a8, 0xffff0002);
+      set_csr ((volatile void *) 0xbf0100a4, 0x80000008);
+    }
+
+  for (i = 0; i < 20; i++)
+    {
+      register int k, j;
+      k = get_csr ((volatile void *) 0xbf0100b8);
+      p += k;
+      j = get_csr ((volatile void *) 0xbf0100b4);
+      r += j;
+      q = j + k;
+    }
+  return q + r + p;
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } } */
+/* { dg-final { scan-assembler-not "\tlwp" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-movep-1.c b/gcc/testsuite/gcc.target/mips/umips-movep-1.c
new file mode 100644 (file)
index 0000000..0865b78
--- /dev/null
@@ -0,0 +1,16 @@
+/* Check that we can generate the MOVEP instruction.  */
+/* { dg-options "-mgp32 -fpeephole2 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+long long bar (long long, long long);
+
+MICROMIPS long long
+foo (long long n, long long a)
+{
+  long long i, j;
+
+  i = bar (n, a);
+  j = bar (n, a);
+  return i + j;
+}
+/* { dg-final { scan-assembler "\tmovep\t" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-movep-2.c b/gcc/testsuite/gcc.target/mips/umips-movep-2.c
new file mode 100644 (file)
index 0000000..5a3a841
--- /dev/null
@@ -0,0 +1,13 @@
+/* Check that we can generate the MOVEP instruction.  */
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+int bar (int, int);
+
+int MICROMIPS
+foo (int n, int a)
+{
+  return bar (0, 0);
+}
+
+/* { dg-final { scan-assembler "\tmovep\t\\\$4,\\\$5,\\\$0,\\\$0" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-save-restore-1.c b/gcc/testsuite/gcc.target/mips/umips-save-restore-1.c
new file mode 100644 (file)
index 0000000..ff1ea4b
--- /dev/null
@@ -0,0 +1,18 @@
+/* Check that we can use the swm/lwm instructions.  */
+/* { dg-options "-mabi=32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+int bar (int, int, int, int, int);
+
+MICROMIPS int
+foo (int n, int a, int b, int c, int d)
+{
+  int i, j;
+
+  i = bar (n, a, b, c, d);
+  j = bar (n, a, b, c, d);
+  return i + j;
+}
+
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$2(0|1),\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$2(0|1),\\\$31" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-save-restore-2.c b/gcc/testsuite/gcc.target/mips/umips-save-restore-2.c
new file mode 100644 (file)
index 0000000..cb421d5
--- /dev/null
@@ -0,0 +1,16 @@
+/* Check that we can use the save instruction to save spilled arguments.  */
+/* { dg-options "-mabi=32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+MICROMIPS void
+foo (int *a, int b, int c)
+{
+  asm volatile ("" ::: "$2", "$3", "$4", "$5", "$6", "$7", "$8",
+               "$9", "$10", "$11", "$12", "$13", "$14", "$15", "$16",
+               "$17", "$18", "$19", "$20", "$21", "$22", "$23", "$24",
+               "$25", "$30", "memory");
+  a[b] = 1;
+  a[c] = 1;
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$23,\\\$fp" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$23,\\\$fp" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-save-restore-3.c b/gcc/testsuite/gcc.target/mips/umips-save-restore-3.c
new file mode 100644 (file)
index 0000000..22c6f45
--- /dev/null
@@ -0,0 +1,14 @@
+/* Check that we can use the swm instruction to save $16, $17 and $31.  */
+/* { dg-options "-mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void bar (void);
+
+MICROMIPS void
+foo (void)
+{
+  bar ();
+  asm volatile ("" ::: "$16", "$17");
+}
+/* { dg-final { scan-assembler "\tswm\t\\\$16-\\\$17,\\\$31" } } */
+/* { dg-final { scan-assembler "\tlwm\t\\\$16-\\\$17,\\\$31" } } */
diff --git a/gcc/testsuite/gcc.target/mips/umips-swp-1.c b/gcc/testsuite/gcc.target/mips/umips-swp-1.c
new file mode 100644 (file)
index 0000000..5e337b2
--- /dev/null
@@ -0,0 +1,10 @@
+/* { dg-options "-fpeephole2 -mgp32 (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (long long l1, long long *l2)
+{
+  *l2 = l1;
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$4,0\\(\\\$6\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-swp-2.c b/gcc/testsuite/gcc.target/mips/umips-swp-2.c
new file mode 100644 (file)
index 0000000..042322c
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[0] = r5;
+  r4[1] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,0\\(\\\$4\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-swp-3.c b/gcc/testsuite/gcc.target/mips/umips-swp-3.c
new file mode 100644 (file)
index 0000000..f0e5464
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[0] = r5;
+  r4[1] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,0\\(\\\$4\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-swp-4.c b/gcc/testsuite/gcc.target/mips/umips-swp-4.c
new file mode 100644 (file)
index 0000000..5e8f5ea
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[511] = r5;
+  r4[512] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,2044\\(\\\$4\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-swp-5.c b/gcc/testsuite/gcc.target/mips/umips-swp-5.c
new file mode 100644 (file)
index 0000000..dc1938e
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[511] = r5;
+  r4[512] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler "\tswp\t\\\$5,2044\\(\\\$4\\)" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-swp-6.c b/gcc/testsuite/gcc.target/mips/umips-swp-6.c
new file mode 100644 (file)
index 0000000..b489006
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r6 *= r6;
+  r4[512] = r5;
+  r4[513] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } }*/
diff --git a/gcc/testsuite/gcc.target/mips/umips-swp-7.c b/gcc/testsuite/gcc.target/mips/umips-swp-7.c
new file mode 100644 (file)
index 0000000..6dde49b
--- /dev/null
@@ -0,0 +1,17 @@
+/* { dg-options "-fpeephole2 -mtune=m14k (-mmicromips)" } */
+/* { dg-skip-if "code quality test" { *-*-* } { "-O0" } { "" } } */
+
+void MICROMIPS
+foo (int *r4, int r5, int r6)
+{
+  r5 *= r5;
+  r4[512] = r5;
+  r4[513] = r6;
+  {
+    register int r5asm asm ("$5") = r5;
+    register int r6asm asm ("$6") = r6;
+    asm ("#foo" : "=m" (r4[2]) : "d" (r5asm), "d" (r6asm));
+  }
+}
+
+/* { dg-final { scan-assembler-not "\tswp" } }*/
index 6032f6f1a6a628a1b59bdf4d174e18dfc9e49945..20667f0ddc84423d34c8affe0c5654afd9a2c2f5 100644 (file)
@@ -1,3 +1,11 @@
+2013-02-24  Catherine Moore  <clm@codesourcery.com>
+           Joseph Myers  <joseph@codesourcery.com>
+           Chao-ying Fu  <fu@mips.com>
+
+       * config/mips/mips16.S:  Don't build for microMIPS.
+       * config/mips/linux-unwind.h: Handle microMIPS frame.
+       * config/mips/crtn.S (fini, init): New labels.
+
 2012-02-19  Edgar E. Iglesias  <edgar.iglesias@gmail.com>
        * config/microblaze/modsi3.S (modsi3): Fix case with 0x80000000 
        as dividend.
index 59d1a905c11da17a9ee8729c868afe3836b2df07..99007176db2c8eb15978cacb7472f1234856a42b 100644 (file)
@@ -31,6 +31,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
 #endif
 
        .section .init,"ax",@progbits
+init:  
 #ifdef __mips64
        ld      RA,40($sp)
        daddu   $sp,$sp,48
@@ -41,6 +42,7 @@ see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
        j       RA
 
        .section .fini,"ax",@progbits
+fini:  
 #ifdef __mips64
        ld      RA,40($sp)
        daddu   $sp,$sp,48
index a009797195c2178e564aa47f1c1e9ca9293246d8..92c2941ef425eb3dd38caaaadee1f1d5250d9734 100644 (file)
@@ -51,6 +51,11 @@ mips_fallback_frame_state (struct _Unwind_Context *context,
   _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 ab3a7942d6c48fdf1a5f4a8124fa32236d0df894..826750180025a308a9968ea2651e0c1f16dada32 100644 (file)
@@ -21,6 +21,10 @@ a copy of the GCC Runtime Library Exception along with this program;
 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 @@ CALL_STUB_RET (__mips16_call_stub_dc_10, 10, DC)
 #endif /* !__mips_single_float */
 
 #endif
+#endif /* __mips_micromips */