summaryrefslogtreecommitdiff
path: root/gcc/config/fr30
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/config/fr30')
-rw-r--r--gcc/config/fr30/constraints.md72
-rw-r--r--gcc/config/fr30/crti.asm61
-rw-r--r--gcc/config/fr30/crtn.asm44
-rw-r--r--gcc/config/fr30/fr30-protos.h35
-rw-r--r--gcc/config/fr30/fr30.c1066
-rw-r--r--gcc/config/fr30/fr30.h871
-rw-r--r--gcc/config/fr30/fr30.md1268
-rw-r--r--gcc/config/fr30/fr30.opt27
-rw-r--r--gcc/config/fr30/lib1funcs.asm115
-rw-r--r--gcc/config/fr30/predicates.md123
-rw-r--r--gcc/config/fr30/t-fr3056
11 files changed, 3738 insertions, 0 deletions
diff --git a/gcc/config/fr30/constraints.md b/gcc/config/fr30/constraints.md
new file mode 100644
index 000000000..2fb049159
--- /dev/null
+++ b/gcc/config/fr30/constraints.md
@@ -0,0 +1,72 @@
+;; Constraint definitions for the FR30.
+;; Copyright (C) 2011
+;; Free Software Foundation, Inc.
+
+;; 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/>.
+
+;; Register constraints.
+(define_register_constraint "d" "MULTIPLY_64_REG"
+ "The MDH,MDL register pair as used by MUL and MULU.")
+
+(define_register_constraint "e" "MULTIPLY_32_REG"
+ "The MDL register as used by MULH and MULUH.")
+
+(define_register_constraint "h" "HIGH_REGS"
+ "Registers 8 through 15.")
+
+(define_register_constraint "l" "LOW_REGS"
+ "Registers 0 through 7.")
+
+(define_register_constraint "a" "ALL_REGS"
+ "@internal")
+
+;; Integer constraints.
+(define_constraint "I"
+ "An integer in the range 0 to 15."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 0, 15)")))
+
+(define_constraint "J"
+ "An integer in the range -16 to -1."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, -16, -1)")))
+
+(define_constraint "K"
+ "An integer in the range 16 to 31."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 16, 31)")))
+
+(define_constraint "L"
+ "An integer in the range 0 to 255."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 0, 255)")))
+
+(define_constraint "M"
+ "An integer in the range 0 to 1048575."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, 0, 1048575)")))
+
+(define_constraint "P"
+ "An integer in the range -256 to 255."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE (ival, -256, 255)")))
+
+;; Extra constraints.
+(define_constraint "Q"
+ "@internal"
+ (and (match_code "mem")
+ (match_code "symbol_ref" "0")))
diff --git a/gcc/config/fr30/crti.asm b/gcc/config/fr30/crti.asm
new file mode 100644
index 000000000..4ce61231b
--- /dev/null
+++ b/gcc/config/fr30/crti.asm
@@ -0,0 +1,61 @@
+# crti.s for ELF
+
+# Copyright (C) 1992, 1998, 1999, 2008, 2009 Free Software Foundation, Inc.
+# Written By David Vinayak Henkel-Wallace, June 1992
+#
+# This file 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.
+#
+# This file 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# 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/>.
+
+# This file just make a stack frame for the contents of the .fini and
+# .init sections. Users may put any desired instructions in those
+# sections.
+
+ .section ".init"
+ .global _init
+ .type _init,#function
+ .align 4
+_init:
+ st rp, @-r15
+ enter #4
+
+ # These nops are here to align the end of this code with a 16 byte
+ # boundary. The linker will start inserting code into the .init
+ # section at such a boundary.
+
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
+
+
+ .section ".fini"
+ .global _fini
+ .type _fini,#function
+ .align 4
+_fini:
+ st rp, @-r15
+ enter #4
+ nop
+ nop
+ nop
+ nop
+ nop
+ nop
diff --git a/gcc/config/fr30/crtn.asm b/gcc/config/fr30/crtn.asm
new file mode 100644
index 000000000..ac2712186
--- /dev/null
+++ b/gcc/config/fr30/crtn.asm
@@ -0,0 +1,44 @@
+# crtn.asm for ELF
+
+# Copyright (C) 1992, 1999, 2008, 2009 Free Software Foundation, Inc.
+# Written By David Vinayak Henkel-Wallace, June 1992
+#
+# This file 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.
+#
+# This file 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.
+#
+# Under Section 7 of GPL version 3, you are granted additional
+# permissions described in the GCC Runtime Library Exception, version
+# 3.1, as published by the Free Software Foundation.
+#
+# You should have received a copy of the GNU General Public License and
+# 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/>.
+
+# This file just makes sure that the .fini and .init sections do in
+# fact return. Users may put any desired instructions in those sections.
+# This file is the last thing linked into any executable.
+
+ .section ".init"
+ .align 4
+
+ leave
+ ld @r15+,rp
+ ret
+
+
+ .section ".fini"
+ .align 4
+
+ leave
+ ld @r15+,rp
+ ret
+
+# Th-th-th-that is all folks!
diff --git a/gcc/config/fr30/fr30-protos.h b/gcc/config/fr30/fr30-protos.h
new file mode 100644
index 000000000..45bb3444e
--- /dev/null
+++ b/gcc/config/fr30/fr30-protos.h
@@ -0,0 +1,35 @@
+/* Prototypes for fr30.c functions used in the md file & elsewhere.
+ Copyright (C) 1999, 2000, 2002, 2004, 2007, 2010
+ Free Software Foundation, Inc.
+
+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/>. */
+
+extern void fr30_expand_prologue (void);
+extern void fr30_expand_epilogue (void);
+extern unsigned int fr30_compute_frame_size (int, int);
+
+#ifdef RTX_CODE
+extern int fr30_check_multiple_regs (rtx *, int, int);
+extern void fr30_print_operand (FILE *, rtx, int);
+extern void fr30_print_operand_address (FILE *, rtx);
+extern rtx fr30_move_double (rtx *);
+#ifdef HAVE_MACHINE_MODES
+#define Mmode enum machine_mode
+extern int fr30_const_double_is_zero (rtx);
+#undef Mmode
+#endif /* HAVE_MACHINE_MODES */
+#endif /* RTX_CODE */
diff --git a/gcc/config/fr30/fr30.c b/gcc/config/fr30/fr30.c
new file mode 100644
index 000000000..74585b5dc
--- /dev/null
+++ b/gcc/config/fr30/fr30.c
@@ -0,0 +1,1066 @@
+/* FR30 specific functions.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2005, 2007, 2008, 2009,
+ 2010 Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+ 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/>. */
+
+/*{{{ Includes */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "recog.h"
+#include "tree.h"
+#include "output.h"
+#include "expr.h"
+#include "obstack.h"
+#include "except.h"
+#include "function.h"
+#include "df.h"
+#include "diagnostic-core.h"
+#include "tm_p.h"
+#include "target.h"
+#include "target-def.h"
+
+/*}}}*/
+/*{{{ Function Prologues & Epilogues */
+
+/* The FR30 stack looks like this:
+
+ Before call After call
+ FP ->| | | |
+ +-----------------------+ +-----------------------+ high
+ | | | | memory
+ | local variables, | | local variables, |
+ | reg save area, etc. | | reg save area, etc. |
+ | | | |
+ +-----------------------+ +-----------------------+
+ | | | |
+ | args to the func that | | args to this func. |
+ | is being called that | | |
+ SP ->| do not fit in regs | | |
+ +-----------------------+ +-----------------------+
+ | args that used to be | \
+ | in regs; only created | | pretend_size
+ AP-> | for vararg funcs | /
+ +-----------------------+
+ | | \
+ | register save area | |
+ | | |
+ +-----------------------+ | reg_size
+ | return address | |
+ +-----------------------+ |
+ FP ->| previous frame ptr | /
+ +-----------------------+
+ | | \
+ | local variables | | var_size
+ | | /
+ +-----------------------+
+ | | \
+ low | room for args to | |
+ memory | other funcs called | | args_size
+ | from this one | |
+ SP ->| | /
+ +-----------------------+
+
+ Note, AP is a fake hard register. It will be eliminated in favor of
+ SP or FP as appropriate.
+
+ Note, Some or all of the stack sections above may be omitted if they
+ are not needed. */
+
+/* Structure to be filled in by fr30_compute_frame_size() with register
+ save masks, and offsets for the current function. */
+struct fr30_frame_info
+{
+ unsigned int total_size; /* # Bytes that the entire frame takes up. */
+ unsigned int pretend_size; /* # Bytes we push and pretend caller did. */
+ unsigned int args_size; /* # Bytes that outgoing arguments take up. */
+ unsigned int reg_size; /* # Bytes needed to store regs. */
+ unsigned int var_size; /* # Bytes that variables take up. */
+ unsigned int frame_size; /* # Bytes in current frame. */
+ unsigned int gmask; /* Mask of saved registers. */
+ unsigned int save_fp; /* Nonzero if frame pointer must be saved. */
+ unsigned int save_rp; /* Nonzero if return pointer must be saved. */
+ int initialised; /* Nonzero if frame size already calculated. */
+};
+
+/* Current frame information calculated by fr30_compute_frame_size(). */
+static struct fr30_frame_info current_frame_info;
+
+/* Zero structure to initialize current_frame_info. */
+static struct fr30_frame_info zero_frame_info;
+
+static void fr30_setup_incoming_varargs (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, int *, int);
+static bool fr30_must_pass_in_stack (enum machine_mode, const_tree);
+static int fr30_arg_partial_bytes (CUMULATIVE_ARGS *, enum machine_mode,
+ tree, bool);
+static rtx fr30_function_arg (CUMULATIVE_ARGS *, enum machine_mode,
+ const_tree, bool);
+static void fr30_function_arg_advance (CUMULATIVE_ARGS *, enum machine_mode,
+ const_tree, bool);
+static bool fr30_frame_pointer_required (void);
+static rtx fr30_function_value (const_tree, const_tree, bool);
+static rtx fr30_libcall_value (enum machine_mode, const_rtx);
+static bool fr30_function_value_regno_p (const unsigned int);
+static bool fr30_can_eliminate (const int, const int);
+static void fr30_asm_trampoline_template (FILE *);
+static void fr30_trampoline_init (rtx, tree, rtx);
+static int fr30_num_arg_regs (enum machine_mode, const_tree);
+
+#define FRAME_POINTER_MASK (1 << (FRAME_POINTER_REGNUM))
+#define RETURN_POINTER_MASK (1 << (RETURN_POINTER_REGNUM))
+
+/* Tell prologue and epilogue if register REGNO should be saved / restored.
+ The return address and frame pointer are treated separately.
+ Don't consider them here. */
+#define MUST_SAVE_REGISTER(regno) \
+ ( (regno) != RETURN_POINTER_REGNUM \
+ && (regno) != FRAME_POINTER_REGNUM \
+ && df_regs_ever_live_p (regno) \
+ && ! call_used_regs [regno] )
+
+#define MUST_SAVE_FRAME_POINTER (df_regs_ever_live_p (FRAME_POINTER_REGNUM) || frame_pointer_needed)
+#define MUST_SAVE_RETURN_POINTER (df_regs_ever_live_p (RETURN_POINTER_REGNUM) || crtl->profile)
+
+#if UNITS_PER_WORD == 4
+#define WORD_ALIGN(SIZE) (((SIZE) + 3) & ~3)
+#endif
+
+/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
+static const struct default_options fr30_option_optimization_table[] =
+ {
+ { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+ { OPT_LEVELS_NONE, 0, NULL, 0 }
+ };
+
+/* Initialize the GCC target structure. */
+#undef TARGET_ASM_ALIGNED_HI_OP
+#define TARGET_ASM_ALIGNED_HI_OP "\t.hword\t"
+#undef TARGET_ASM_ALIGNED_SI_OP
+#define TARGET_ASM_ALIGNED_SI_OP "\t.word\t"
+
+#undef TARGET_PROMOTE_PROTOTYPES
+#define TARGET_PROMOTE_PROTOTYPES hook_bool_const_tree_true
+#undef TARGET_PASS_BY_REFERENCE
+#define TARGET_PASS_BY_REFERENCE hook_pass_by_reference_must_pass_in_stack
+#undef TARGET_ARG_PARTIAL_BYTES
+#define TARGET_ARG_PARTIAL_BYTES fr30_arg_partial_bytes
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG fr30_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE fr30_function_arg_advance
+
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE fr30_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE fr30_libcall_value
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P fr30_function_value_regno_p
+
+#undef TARGET_SETUP_INCOMING_VARARGS
+#define TARGET_SETUP_INCOMING_VARARGS fr30_setup_incoming_varargs
+#undef TARGET_MUST_PASS_IN_STACK
+#define TARGET_MUST_PASS_IN_STACK fr30_must_pass_in_stack
+
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED fr30_frame_pointer_required
+
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE fr30_can_eliminate
+
+#undef TARGET_ASM_TRAMPOLINE_TEMPLATE
+#define TARGET_ASM_TRAMPOLINE_TEMPLATE fr30_asm_trampoline_template
+#undef TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT fr30_trampoline_init
+
+#undef TARGET_EXCEPT_UNWIND_INFO
+#define TARGET_EXCEPT_UNWIND_INFO sjlj_except_unwind_info
+
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE fr30_option_optimization_table
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+
+/* Worker function for TARGET_CAN_ELIMINATE. */
+
+bool
+fr30_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+ return (to == FRAME_POINTER_REGNUM || ! frame_pointer_needed);
+}
+
+/* Returns the number of bytes offset between FROM_REG and TO_REG
+ for the current function. As a side effect it fills in the
+ current_frame_info structure, if the data is available. */
+unsigned int
+fr30_compute_frame_size (int from_reg, int to_reg)
+{
+ int regno;
+ unsigned int return_value;
+ unsigned int var_size;
+ unsigned int args_size;
+ unsigned int pretend_size;
+ unsigned int reg_size;
+ unsigned int gmask;
+
+ var_size = WORD_ALIGN (get_frame_size ());
+ args_size = WORD_ALIGN (crtl->outgoing_args_size);
+ pretend_size = crtl->args.pretend_args_size;
+
+ reg_size = 0;
+ gmask = 0;
+
+ /* Calculate space needed for registers. */
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno ++)
+ {
+ if (MUST_SAVE_REGISTER (regno))
+ {
+ reg_size += UNITS_PER_WORD;
+ gmask |= 1 << regno;
+ }
+ }
+
+ current_frame_info.save_fp = MUST_SAVE_FRAME_POINTER;
+ current_frame_info.save_rp = MUST_SAVE_RETURN_POINTER;
+
+ reg_size += (current_frame_info.save_fp + current_frame_info.save_rp)
+ * UNITS_PER_WORD;
+
+ /* Save computed information. */
+ current_frame_info.pretend_size = pretend_size;
+ current_frame_info.var_size = var_size;
+ current_frame_info.args_size = args_size;
+ current_frame_info.reg_size = reg_size;
+ current_frame_info.frame_size = args_size + var_size;
+ current_frame_info.total_size = args_size + var_size + reg_size + pretend_size;
+ current_frame_info.gmask = gmask;
+ current_frame_info.initialised = reload_completed;
+
+ /* Calculate the required distance. */
+ return_value = 0;
+
+ if (to_reg == STACK_POINTER_REGNUM)
+ return_value += args_size + var_size;
+
+ if (from_reg == ARG_POINTER_REGNUM)
+ return_value += reg_size;
+
+ return return_value;
+}
+
+/* Called after register allocation to add any instructions needed for the
+ prologue. Using a prologue insn is favored compared to putting all of the
+ instructions in output_function_prologue(), since it allows the scheduler
+ to intermix instructions with the saves of the caller saved registers. In
+ some cases, it might be necessary to emit a barrier instruction as the last
+ insn to prevent such scheduling. */
+
+void
+fr30_expand_prologue (void)
+{
+ int regno;
+ rtx insn;
+
+ if (! current_frame_info.initialised)
+ fr30_compute_frame_size (0, 0);
+
+ /* This cases shouldn't happen. Catch it now. */
+ gcc_assert (current_frame_info.total_size || !current_frame_info.gmask);
+
+ /* Allocate space for register arguments if this is a variadic function. */
+ if (current_frame_info.pretend_size)
+ {
+ int regs_to_save = current_frame_info.pretend_size / UNITS_PER_WORD;
+
+ /* Push argument registers into the pretend arg area. */
+ for (regno = FIRST_ARG_REGNUM + FR30_NUM_ARG_REGS; regno --, regs_to_save --;)
+ {
+ insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+
+ if (current_frame_info.gmask)
+ {
+ /* Save any needed call-saved regs. */
+ for (regno = STACK_POINTER_REGNUM; regno--;)
+ {
+ if ((current_frame_info.gmask & (1 << regno)) != 0)
+ {
+ insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode, regno)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+
+ /* Save return address if necessary. */
+ if (current_frame_info.save_rp)
+ {
+ insn = emit_insn (gen_movsi_push (gen_rtx_REG (Pmode,
+ RETURN_POINTER_REGNUM)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ /* Save old frame pointer and create new one, if necessary. */
+ if (current_frame_info.save_fp)
+ {
+ if (current_frame_info.frame_size < ((1 << 10) - UNITS_PER_WORD))
+ {
+ int enter_size = current_frame_info.frame_size + UNITS_PER_WORD;
+ rtx pattern;
+
+ insn = emit_insn (gen_enter_func (GEN_INT (enter_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ pattern = PATTERN (insn);
+
+ /* Also mark all 3 subexpressions as RTX_FRAME_RELATED_P. */
+ if (GET_CODE (pattern) == PARALLEL)
+ {
+ int x;
+ for (x = XVECLEN (pattern, 0); x--;)
+ {
+ rtx part = XVECEXP (pattern, 0, x);
+
+ /* One of the insns in the ENTER pattern updates the
+ frame pointer. If we do not actually need the frame
+ pointer in this function then this is a side effect
+ rather than a desired effect, so we do not mark that
+ insn as being related to the frame set up. Doing this
+ allows us to compile the crash66.C test file in the
+ G++ testsuite. */
+ if (! frame_pointer_needed
+ && GET_CODE (part) == SET
+ && SET_DEST (part) == hard_frame_pointer_rtx)
+ RTX_FRAME_RELATED_P (part) = 0;
+ else
+ RTX_FRAME_RELATED_P (part) = 1;
+ }
+ }
+ }
+ else
+ {
+ insn = emit_insn (gen_movsi_push (frame_pointer_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+
+ if (frame_pointer_needed)
+ {
+ insn = emit_insn (gen_movsi (frame_pointer_rtx, stack_pointer_rtx));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ }
+ }
+
+ /* Allocate the stack frame. */
+ if (current_frame_info.frame_size == 0)
+ ; /* Nothing to do. */
+ else if (current_frame_info.save_fp
+ && current_frame_info.frame_size < ((1 << 10) - UNITS_PER_WORD))
+ ; /* Nothing to do. */
+ else if (current_frame_info.frame_size <= 512)
+ {
+ insn = emit_insn (gen_add_to_stack
+ (GEN_INT (- (signed) current_frame_info.frame_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else
+ {
+ rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
+ insn = emit_insn (gen_movsi (tmp, GEN_INT (current_frame_info.frame_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ insn = emit_insn (gen_subsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ if (crtl->profile)
+ emit_insn (gen_blockage ());
+}
+
+/* Called after register allocation to add any instructions needed for the
+ epilogue. Using an epilogue insn is favored compared to putting all of the
+ instructions in output_function_epilogue(), since it allows the scheduler
+ to intermix instructions with the restores of the caller saved registers.
+ In some cases, it might be necessary to emit a barrier instruction as the
+ first insn to prevent such scheduling. */
+void
+fr30_expand_epilogue (void)
+{
+ int regno;
+
+ /* Perform the inversion operations of the prologue. */
+ gcc_assert (current_frame_info.initialised);
+
+ /* Pop local variables and arguments off the stack.
+ If frame_pointer_needed is TRUE then the frame pointer register
+ has actually been used as a frame pointer, and we can recover
+ the stack pointer from it, otherwise we must unwind the stack
+ manually. */
+ if (current_frame_info.frame_size > 0)
+ {
+ if (current_frame_info.save_fp && frame_pointer_needed)
+ {
+ emit_insn (gen_leave_func ());
+ current_frame_info.save_fp = 0;
+ }
+ else if (current_frame_info.frame_size <= 508)
+ emit_insn (gen_add_to_stack
+ (GEN_INT (current_frame_info.frame_size)));
+ else
+ {
+ rtx tmp = gen_rtx_REG (Pmode, PROLOGUE_TMP_REGNUM);
+ emit_insn (gen_movsi (tmp, GEN_INT (current_frame_info.frame_size)));
+ emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx, tmp));
+ }
+ }
+
+ if (current_frame_info.save_fp)
+ emit_insn (gen_movsi_pop (frame_pointer_rtx));
+
+ /* Pop all the registers that were pushed. */
+ if (current_frame_info.save_rp)
+ emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, RETURN_POINTER_REGNUM)));
+
+ for (regno = 0; regno < STACK_POINTER_REGNUM; regno ++)
+ if (current_frame_info.gmask & (1 << regno))
+ emit_insn (gen_movsi_pop (gen_rtx_REG (Pmode, regno)));
+
+ if (current_frame_info.pretend_size)
+ emit_insn (gen_add_to_stack (GEN_INT (current_frame_info.pretend_size)));
+
+ /* Reset state info for each function. */
+ current_frame_info = zero_frame_info;
+
+ emit_jump_insn (gen_return_from_func ());
+}
+
+/* Do any needed setup for a variadic function. We must create a register
+ parameter block, and then copy any anonymous arguments, plus the last
+ named argument, from registers into memory. * copying actually done in
+ fr30_expand_prologue().
+
+ ARG_REGS_USED_SO_FAR has *not* been updated for the last named argument
+ which has type TYPE and mode MODE, and we rely on this fact. */
+void
+fr30_setup_incoming_varargs (CUMULATIVE_ARGS *arg_regs_used_so_far,
+ enum machine_mode mode,
+ tree type ATTRIBUTE_UNUSED,
+ int *pretend_size,
+ int second_time ATTRIBUTE_UNUSED)
+{
+ int size;
+
+ /* All BLKmode values are passed by reference. */
+ gcc_assert (mode != BLKmode);
+
+ /* ??? This run-time test as well as the code inside the if
+ statement is probably unnecessary. */
+ if (targetm.calls.strict_argument_naming (arg_regs_used_so_far))
+ /* If TARGET_STRICT_ARGUMENT_NAMING returns true, then the last named
+ arg must not be treated as an anonymous arg. */
+ arg_regs_used_so_far += fr30_num_arg_regs (mode, type);
+
+ size = FR30_NUM_ARG_REGS - (* arg_regs_used_so_far);
+
+ if (size <= 0)
+ return;
+
+ * pretend_size = (size * UNITS_PER_WORD);
+}
+
+/*}}}*/
+/*{{{ Printing operands */
+
+/* Print a memory address as an operand to reference that memory location. */
+
+void
+fr30_print_operand_address (FILE *stream, rtx address)
+{
+ switch (GET_CODE (address))
+ {
+ case SYMBOL_REF:
+ output_addr_const (stream, address);
+ break;
+
+ default:
+ fprintf (stderr, "code = %x\n", GET_CODE (address));
+ debug_rtx (address);
+ output_operand_lossage ("fr30_print_operand_address: unhandled address");
+ break;
+ }
+}
+
+/* Print an operand. */
+
+void
+fr30_print_operand (FILE *file, rtx x, int code)
+{
+ rtx x0;
+
+ switch (code)
+ {
+ case '#':
+ /* Output a :D if this instruction is delayed. */
+ if (dbr_sequence_length () != 0)
+ fputs (":D", file);
+ return;
+
+ case 'p':
+ /* Compute the register name of the second register in a hi/lo
+ register pair. */
+ if (GET_CODE (x) != REG)
+ output_operand_lossage ("fr30_print_operand: unrecognized %%p code");
+ else
+ fprintf (file, "r%d", REGNO (x) + 1);
+ return;
+
+ case 'b':
+ /* Convert GCC's comparison operators into FR30 comparison codes. */
+ switch (GET_CODE (x))
+ {
+ case EQ: fprintf (file, "eq"); break;
+ case NE: fprintf (file, "ne"); break;
+ case LT: fprintf (file, "lt"); break;
+ case LE: fprintf (file, "le"); break;
+ case GT: fprintf (file, "gt"); break;
+ case GE: fprintf (file, "ge"); break;
+ case LTU: fprintf (file, "c"); break;
+ case LEU: fprintf (file, "ls"); break;
+ case GTU: fprintf (file, "hi"); break;
+ case GEU: fprintf (file, "nc"); break;
+ default:
+ output_operand_lossage ("fr30_print_operand: unrecognized %%b code");
+ break;
+ }
+ return;
+
+ case 'B':
+ /* Convert GCC's comparison operators into the complimentary FR30
+ comparison codes. */
+ switch (GET_CODE (x))
+ {
+ case EQ: fprintf (file, "ne"); break;
+ case NE: fprintf (file, "eq"); break;
+ case LT: fprintf (file, "ge"); break;
+ case LE: fprintf (file, "gt"); break;
+ case GT: fprintf (file, "le"); break;
+ case GE: fprintf (file, "lt"); break;
+ case LTU: fprintf (file, "nc"); break;
+ case LEU: fprintf (file, "hi"); break;
+ case GTU: fprintf (file, "ls"); break;
+ case GEU: fprintf (file, "c"); break;
+ default:
+ output_operand_lossage ("fr30_print_operand: unrecognized %%B code");
+ break;
+ }
+ return;
+
+ case 'A':
+ /* Print a signed byte value as an unsigned value. */
+ if (GET_CODE (x) != CONST_INT)
+ output_operand_lossage ("fr30_print_operand: invalid operand to %%A code");
+ else
+ {
+ HOST_WIDE_INT val;
+
+ val = INTVAL (x);
+
+ val &= 0xff;
+
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, val);
+ }
+ return;
+
+ case 'x':
+ if (GET_CODE (x) != CONST_INT
+ || INTVAL (x) < 16
+ || INTVAL (x) > 32)
+ output_operand_lossage ("fr30_print_operand: invalid %%x code");
+ else
+ fprintf (file, HOST_WIDE_INT_PRINT_DEC, INTVAL (x) - 16);
+ return;
+
+ case 'F':
+ if (GET_CODE (x) != CONST_DOUBLE)
+ output_operand_lossage ("fr30_print_operand: invalid %%F code");
+ else
+ {
+ char str[30];
+
+ real_to_decimal (str, CONST_DOUBLE_REAL_VALUE (x),
+ sizeof (str), 0, 1);
+ fputs (str, file);
+ }
+ return;
+
+ case 0:
+ /* Handled below. */
+ break;
+
+ default:
+ fprintf (stderr, "unknown code = %x\n", code);
+ output_operand_lossage ("fr30_print_operand: unknown code");
+ return;
+ }
+
+ switch (GET_CODE (x))
+ {
+ case REG:
+ fputs (reg_names [REGNO (x)], file);
+ break;
+
+ case MEM:
+ x0 = XEXP (x,0);
+
+ switch (GET_CODE (x0))
+ {
+ case REG:
+ gcc_assert ((unsigned) REGNO (x0) < ARRAY_SIZE (reg_names));
+ fprintf (file, "@%s", reg_names [REGNO (x0)]);
+ break;
+
+ case PLUS:
+ if (GET_CODE (XEXP (x0, 0)) != REG
+ || REGNO (XEXP (x0, 0)) < FRAME_POINTER_REGNUM
+ || REGNO (XEXP (x0, 0)) > STACK_POINTER_REGNUM
+ || GET_CODE (XEXP (x0, 1)) != CONST_INT)
+ {
+ fprintf (stderr, "bad INDEXed address:");
+ debug_rtx (x);
+ output_operand_lossage ("fr30_print_operand: unhandled MEM");
+ }
+ else if (REGNO (XEXP (x0, 0)) == FRAME_POINTER_REGNUM)
+ {
+ HOST_WIDE_INT val = INTVAL (XEXP (x0, 1));
+ if (val < -(1 << 9) || val > ((1 << 9) - 4))
+ {
+ fprintf (stderr, "frame INDEX out of range:");
+ debug_rtx (x);
+ output_operand_lossage ("fr30_print_operand: unhandled MEM");
+ }
+ fprintf (file, "@(r14, #" HOST_WIDE_INT_PRINT_DEC ")", val);
+ }
+ else
+ {
+ HOST_WIDE_INT val = INTVAL (XEXP (x0, 1));
+ if (val < 0 || val > ((1 << 6) - 4))
+ {
+ fprintf (stderr, "stack INDEX out of range:");
+ debug_rtx (x);
+ output_operand_lossage ("fr30_print_operand: unhandled MEM");
+ }
+ fprintf (file, "@(r15, #" HOST_WIDE_INT_PRINT_DEC ")", val);
+ }
+ break;
+
+ case SYMBOL_REF:
+ output_address (x0);
+ break;
+
+ default:
+ fprintf (stderr, "bad MEM code = %x\n", GET_CODE (x0));
+ debug_rtx (x);
+ output_operand_lossage ("fr30_print_operand: unhandled MEM");
+ break;
+ }
+ break;
+
+ case CONST_DOUBLE :
+ /* We handle SFmode constants here as output_addr_const doesn't. */
+ if (GET_MODE (x) == SFmode)
+ {
+ REAL_VALUE_TYPE d;
+ long l;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (d, x);
+ REAL_VALUE_TO_TARGET_SINGLE (d, l);
+ fprintf (file, "0x%08lx", l);
+ break;
+ }
+
+ /* Fall through. Let output_addr_const deal with it. */
+ default:
+ output_addr_const (file, x);
+ break;
+ }
+
+ return;
+}
+
+/*}}}*/
+
+/* Implements TARGET_FUNCTION_VALUE. */
+
+static rtx
+fr30_function_value (const_tree valtype,
+ const_tree fntype_or_decli ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (TYPE_MODE (valtype), RETURN_VALUE_REGNUM);
+}
+
+/* Implements TARGET_LIBCALL_VALUE. */
+
+static rtx
+fr30_libcall_value (enum machine_mode mode,
+ const_rtx fun ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (mode, RETURN_VALUE_REGNUM);
+}
+
+/* Implements TARGET_FUNCTION_VALUE_REGNO_P. */
+
+static bool
+fr30_function_value_regno_p (const unsigned int regno)
+{
+ return (regno == RETURN_VALUE_REGNUM);
+}
+
+/*{{{ Function arguments */
+
+/* Return true if we should pass an argument on the stack rather than
+ in registers. */
+
+static bool
+fr30_must_pass_in_stack (enum machine_mode mode, const_tree type)
+{
+ if (mode == BLKmode)
+ return true;
+ if (type == NULL)
+ return false;
+ return AGGREGATE_TYPE_P (type);
+}
+
+/* Compute the number of word sized registers needed to hold a
+ function argument of mode INT_MODE and tree type TYPE. */
+static int
+fr30_num_arg_regs (enum machine_mode mode, const_tree type)
+{
+ int size;
+
+ if (targetm.calls.must_pass_in_stack (mode, type))
+ return 0;
+
+ if (type && mode == BLKmode)
+ size = int_size_in_bytes (type);
+ else
+ size = GET_MODE_SIZE (mode);
+
+ return (size + UNITS_PER_WORD - 1) / UNITS_PER_WORD;
+}
+
+/* Returns the number of bytes in which *part* of a parameter of machine
+ mode MODE and tree type TYPE (which may be NULL if the type is not known).
+ If the argument fits entirely in the argument registers, or entirely on
+ the stack, then 0 is returned.
+ CUM is the number of argument registers already used by earlier
+ parameters to the function. */
+
+static int
+fr30_arg_partial_bytes (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ tree type, bool named)
+{
+ /* Unnamed arguments, i.e. those that are prototyped as ...
+ are always passed on the stack.
+ Also check here to see if all the argument registers are full. */
+ if (named == 0 || *cum >= FR30_NUM_ARG_REGS)
+ return 0;
+
+ /* Work out how many argument registers would be needed if this
+ parameter were to be passed entirely in registers. If there
+ are sufficient argument registers available (or if no registers
+ are needed because the parameter must be passed on the stack)
+ then return zero, as this parameter does not require partial
+ register, partial stack stack space. */
+ if (*cum + fr30_num_arg_regs (mode, type) <= FR30_NUM_ARG_REGS)
+ return 0;
+
+ return (FR30_NUM_ARG_REGS - *cum) * UNITS_PER_WORD;
+}
+
+static rtx
+fr30_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ const_tree type, bool named)
+{
+ if (!named
+ || fr30_must_pass_in_stack (mode, type)
+ || *cum >= FR30_NUM_ARG_REGS)
+ return NULL_RTX;
+ else
+ return gen_rtx_REG (mode, *cum + FIRST_ARG_REGNUM);
+}
+
+/* A C statement (sans semicolon) to update the summarizer variable CUM to
+ advance past an argument in the argument list. The values MODE, TYPE and
+ NAMED describe that argument. Once this is done, the variable CUM is
+ suitable for analyzing the *following* argument with `FUNCTION_ARG', etc.
+
+ This macro need not do anything if the argument in question was passed on
+ the stack. The compiler knows how to track the amount of stack space used
+ for arguments without any special help. */
+static void
+fr30_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+ const_tree type, bool named)
+{
+ *cum += named * fr30_num_arg_regs (mode, type);
+}
+
+/*}}}*/
+/*{{{ Operand predicates */
+
+#ifndef Mmode
+#define Mmode enum machine_mode
+#endif
+
+/* Returns true iff all the registers in the operands array
+ are in descending or ascending order. */
+int
+fr30_check_multiple_regs (rtx *operands, int num_operands, int descending)
+{
+ if (descending)
+ {
+ unsigned int prev_regno = 0;
+
+ while (num_operands --)
+ {
+ if (GET_CODE (operands [num_operands]) != REG)
+ return 0;
+
+ if (REGNO (operands [num_operands]) < prev_regno)
+ return 0;
+
+ prev_regno = REGNO (operands [num_operands]);
+ }
+ }
+ else
+ {
+ unsigned int prev_regno = CONDITION_CODE_REGNUM;
+
+ while (num_operands --)
+ {
+ if (GET_CODE (operands [num_operands]) != REG)
+ return 0;
+
+ if (REGNO (operands [num_operands]) > prev_regno)
+ return 0;
+
+ prev_regno = REGNO (operands [num_operands]);
+ }
+ }
+
+ return 1;
+}
+
+int
+fr30_const_double_is_zero (rtx operand)
+{
+ REAL_VALUE_TYPE d;
+
+ if (operand == NULL || GET_CODE (operand) != CONST_DOUBLE)
+ return 0;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (d, operand);
+
+ return REAL_VALUES_EQUAL (d, dconst0);
+}
+
+/*}}}*/
+/*{{{ Instruction Output Routines */
+
+/* Output a double word move.
+ It must be REG<-REG, REG<-MEM, MEM<-REG or REG<-CONST.
+ On the FR30 we are constrained by the fact that it does not
+ support offsetable addresses, and so we have to load the
+ address of the secnd word into the second destination register
+ before we can use it. */
+
+rtx
+fr30_move_double (rtx * operands)
+{
+ rtx src = operands[1];
+ rtx dest = operands[0];
+ enum rtx_code src_code = GET_CODE (src);
+ enum rtx_code dest_code = GET_CODE (dest);
+ enum machine_mode mode = GET_MODE (dest);
+ rtx val;
+
+ start_sequence ();
+
+ if (dest_code == REG)
+ {
+ if (src_code == REG)
+ {
+ int reverse = (REGNO (dest) == REGNO (src) + 1);
+
+ /* We normally copy the low-numbered register first. However, if
+ the first register of operand 0 is the same as the second register
+ of operand 1, we must copy in the opposite order. */
+ emit_insn (gen_rtx_SET (VOIDmode,
+ operand_subword (dest, reverse, TRUE, mode),
+ operand_subword (src, reverse, TRUE, mode)));
+
+ emit_insn (gen_rtx_SET (VOIDmode,
+ operand_subword (dest, !reverse, TRUE, mode),
+ operand_subword (src, !reverse, TRUE, mode)));
+ }
+ else if (src_code == MEM)
+ {
+ rtx addr = XEXP (src, 0);
+ rtx dest0 = operand_subword (dest, 0, TRUE, mode);
+ rtx dest1 = operand_subword (dest, 1, TRUE, mode);
+ rtx new_mem;
+
+ gcc_assert (GET_CODE (addr) == REG);
+
+ /* Copy the address before clobbering it. See PR 34174. */
+ emit_insn (gen_rtx_SET (SImode, dest1, addr));
+ emit_insn (gen_rtx_SET (VOIDmode, dest0,
+ adjust_address (src, SImode, 0)));
+ emit_insn (gen_rtx_SET (SImode, dest1,
+ plus_constant (dest1, UNITS_PER_WORD)));
+
+ new_mem = gen_rtx_MEM (SImode, dest1);
+ MEM_COPY_ATTRIBUTES (new_mem, src);
+
+ emit_insn (gen_rtx_SET (VOIDmode, dest1, new_mem));
+ }
+ else if (src_code == CONST_INT || src_code == CONST_DOUBLE)
+ {
+ rtx words[2];
+ split_double (src, &words[0], &words[1]);
+ emit_insn (gen_rtx_SET (VOIDmode,
+ operand_subword (dest, 0, TRUE, mode),
+ words[0]));
+
+ emit_insn (gen_rtx_SET (VOIDmode,
+ operand_subword (dest, 1, TRUE, mode),
+ words[1]));
+ }
+ }
+ else if (src_code == REG && dest_code == MEM)
+ {
+ rtx addr = XEXP (dest, 0);
+ rtx src0;
+ rtx src1;
+
+ gcc_assert (GET_CODE (addr) == REG);
+
+ src0 = operand_subword (src, 0, TRUE, mode);
+ src1 = operand_subword (src, 1, TRUE, mode);
+
+ emit_move_insn (adjust_address (dest, SImode, 0), src0);
+
+ if (REGNO (addr) == STACK_POINTER_REGNUM
+ || REGNO (addr) == FRAME_POINTER_REGNUM)
+ emit_insn (gen_rtx_SET (VOIDmode,
+ adjust_address (dest, SImode, UNITS_PER_WORD),
+ src1));
+ else
+ {
+ rtx new_mem;
+ rtx scratch_reg_r0 = gen_rtx_REG (SImode, 0);
+
+ /* We need a scratch register to hold the value of 'address + 4'.
+ We use r0 for this purpose. It is used for example for long
+ jumps and is already marked to not be used by normal register
+ allocation. */
+ emit_insn (gen_movsi_internal (scratch_reg_r0, addr));
+ emit_insn (gen_addsi_small_int (scratch_reg_r0, scratch_reg_r0,
+ GEN_INT (UNITS_PER_WORD)));
+ new_mem = gen_rtx_MEM (SImode, scratch_reg_r0);
+ MEM_COPY_ATTRIBUTES (new_mem, dest);
+ emit_move_insn (new_mem, src1);
+ emit_insn (gen_blockage ());
+ }
+ }
+ else
+ /* This should have been prevented by the constraints on movdi_insn. */
+ gcc_unreachable ();
+
+ val = get_insns ();
+ end_sequence ();
+
+ return val;
+}
+
+/* Implement TARGET_FRAME_POINTER_REQUIRED. */
+
+bool
+fr30_frame_pointer_required (void)
+{
+ return (flag_omit_frame_pointer == 0 || crtl->args.pretend_args_size > 0);
+}
+
+/*}}}*/
+/*{{{ Trampoline Output Routines */
+
+/* Implement TARGET_ASM_TRAMPOLINE_TEMPLATE.
+ On the FR30, the trampoline is:
+
+ nop
+ ldi:32 STATIC, r12
+ nop
+ ldi:32 FUNCTION, r0
+ jmp @r0
+
+ The no-ops are to guarantee that the static chain and final
+ target are 32 bit aligned within the trampoline. That allows us to
+ initialize those locations with simple SImode stores. The alternative
+ would be to use HImode stores. */
+
+static void
+fr30_asm_trampoline_template (FILE *f)
+{
+ fprintf (f, "\tnop\n");
+ fprintf (f, "\tldi:32\t#0, %s\n", reg_names [STATIC_CHAIN_REGNUM]);
+ fprintf (f, "\tnop\n");
+ fprintf (f, "\tldi:32\t#0, %s\n", reg_names [COMPILER_SCRATCH_REGISTER]);
+ fprintf (f, "\tjmp\t@%s\n", reg_names [COMPILER_SCRATCH_REGISTER]);
+}
+
+/* Implement TARGET_TRAMPOLINE_INIT. */
+
+static void
+fr30_trampoline_init (rtx m_tramp, tree fndecl, rtx chain_value)
+{
+ rtx fnaddr = XEXP (DECL_RTL (fndecl), 0);
+ rtx mem;
+
+ emit_block_move (m_tramp, assemble_trampoline_template (),
+ GEN_INT (TRAMPOLINE_SIZE), BLOCK_OP_NORMAL);
+
+ mem = adjust_address (m_tramp, SImode, 4);
+ emit_move_insn (mem, chain_value);
+ mem = adjust_address (m_tramp, SImode, 12);
+ emit_move_insn (mem, fnaddr);
+}
+
+/*}}}*/
+/* Local Variables: */
+/* folded-file: t */
+/* End: */
diff --git a/gcc/config/fr30/fr30.h b/gcc/config/fr30/fr30.h
new file mode 100644
index 000000000..d20d7fb79
--- /dev/null
+++ b/gcc/config/fr30/fr30.h
@@ -0,0 +1,871 @@
+/*{{{ Comment. */
+
+/* Definitions of FR30 target.
+ Copyright (C) 1998, 1999, 2000, 2001, 2002, 2004, 2007, 2008, 2009, 2010
+ Free Software Foundation, Inc.
+ Contributed by Cygnus Solutions.
+
+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/>. */
+
+/*}}}*/
+/*{{{ Run-time target specifications. */
+
+#undef ASM_SPEC
+#define ASM_SPEC ""
+
+/* Define this to be a string constant containing `-D' options to define the
+ predefined macros that identify this machine and system. These macros will
+ be predefined unless the `-ansi' option is specified. */
+
+#define TARGET_CPU_CPP_BUILTINS() \
+ do \
+ { \
+ builtin_define_std ("fr30"); \
+ builtin_assert ("machine=fr30"); \
+ } \
+ while (0)
+
+#define TARGET_VERSION fprintf (stderr, " (fr30)");
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "crt0.o%s crti.o%s crtbegin.o%s"
+
+/* Include the OS stub library, so that the code can be simulated.
+ This is not the right way to do this. Ideally this kind of thing
+ should be done in the linker script - but I have not worked out how
+ to specify the location of a linker script in a gcc command line yet... */
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "%{!mno-lsim:-lsim} crtend.o%s crtn.o%s"
+
+#undef LIB_SPEC
+#define LIB_SPEC "-lc"
+
+#undef LINK_SPEC
+#define LINK_SPEC "%{h*} %{v:-V} \
+ %{static:-Bstatic} %{shared:-shared} %{symbolic:-Bsymbolic}"
+
+/*}}}*/
+/*{{{ Storage Layout. */
+
+#define BITS_BIG_ENDIAN 1
+
+#define BYTES_BIG_ENDIAN 1
+
+#define WORDS_BIG_ENDIAN 1
+
+#define UNITS_PER_WORD 4
+
+#define PROMOTE_MODE(MODE,UNSIGNEDP,TYPE) \
+ do \
+ { \
+ if (GET_MODE_CLASS (MODE) == MODE_INT \
+ && GET_MODE_SIZE (MODE) < 4) \
+ (MODE) = SImode; \
+ } \
+ while (0)
+
+#define PARM_BOUNDARY 32
+
+#define STACK_BOUNDARY 32
+
+#define FUNCTION_BOUNDARY 32
+
+#define BIGGEST_ALIGNMENT 32
+
+#define DATA_ALIGNMENT(TYPE, ALIGN) \
+ (TREE_CODE (TYPE) == ARRAY_TYPE \
+ && TYPE_MODE (TREE_TYPE (TYPE)) == QImode \
+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+#define CONSTANT_ALIGNMENT(EXP, ALIGN) \
+ (TREE_CODE (EXP) == STRING_CST \
+ && (ALIGN) < BITS_PER_WORD ? BITS_PER_WORD : (ALIGN))
+
+#define STRICT_ALIGNMENT 1
+
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/*}}}*/
+/*{{{ Layout of Source Language Data Types. */
+
+#define SHORT_TYPE_SIZE 16
+#define INT_TYPE_SIZE 32
+#define LONG_TYPE_SIZE 32
+#define LONG_LONG_TYPE_SIZE 64
+#define FLOAT_TYPE_SIZE 32
+#define DOUBLE_TYPE_SIZE 64
+#define LONG_DOUBLE_TYPE_SIZE 64
+
+#define DEFAULT_SIGNED_CHAR 1
+
+#undef SIZE_TYPE
+#define SIZE_TYPE "unsigned int"
+
+#undef PTRDIFF_TYPE
+#define PTRDIFF_TYPE "int"
+
+#undef WCHAR_TYPE
+#define WCHAR_TYPE "long int"
+
+#undef WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE BITS_PER_WORD
+
+/*}}}*/
+/*{{{ REGISTER BASICS. */
+
+/* Number of hardware registers known to the compiler. They receive numbers 0
+ through `FIRST_PSEUDO_REGISTER-1'; thus, the first pseudo register's number
+ really is assigned the number `FIRST_PSEUDO_REGISTER'. */
+#define FIRST_PSEUDO_REGISTER 21
+
+/* Fixed register assignments: */
+
+/* Here we do a BAD THING - reserve a register for use by the machine
+ description file. There are too many places in compiler where it
+ assumes that it can issue a branch or jump instruction without
+ providing a scratch register for it, and reload just cannot cope, so
+ we keep a register back for these situations. */
+#define COMPILER_SCRATCH_REGISTER 0
+
+/* The register that contains the result of a function call. */
+#define RETURN_VALUE_REGNUM 4
+
+/* The first register that can contain the arguments to a function. */
+#define FIRST_ARG_REGNUM 4
+
+/* A call-used register that can be used during the function prologue. */
+#define PROLOGUE_TMP_REGNUM COMPILER_SCRATCH_REGISTER
+
+/* Register numbers used for passing a function's static chain pointer. If
+ register windows are used, the register number as seen by the called
+ function is `STATIC_CHAIN_INCOMING_REGNUM', while the register number as
+ seen by the calling function is `STATIC_CHAIN_REGNUM'. If these registers
+ are the same, `STATIC_CHAIN_INCOMING_REGNUM' need not be defined.
+
+ The static chain register need not be a fixed register.
+
+ If the static chain is passed in memory, these macros should not be defined;
+ instead, the next two macros should be defined. */
+#define STATIC_CHAIN_REGNUM 12
+/* #define STATIC_CHAIN_INCOMING_REGNUM */
+
+/* An FR30 specific hardware register. */
+#define ACCUMULATOR_REGNUM 13
+
+/* The register number of the frame pointer register, which is used to access
+ automatic variables in the stack frame. On some machines, the hardware
+ determines which register this is. On other machines, you can choose any
+ register you wish for this purpose. */
+#define FRAME_POINTER_REGNUM 14
+
+/* The register number of the stack pointer register, which must also be a
+ fixed register according to `FIXED_REGISTERS'. On most machines, the
+ hardware determines which register this is. */
+#define STACK_POINTER_REGNUM 15
+
+/* The following a fake hard registers that describe some of the dedicated
+ registers on the FR30. */
+#define CONDITION_CODE_REGNUM 16
+#define RETURN_POINTER_REGNUM 17
+#define MD_HIGH_REGNUM 18
+#define MD_LOW_REGNUM 19
+
+/* An initializer that says which registers are used for fixed purposes all
+ throughout the compiled code and are therefore not available for general
+ allocation. These would include the stack pointer, the frame pointer
+ (except on machines where that can be used as a general register when no
+ frame pointer is needed), the program counter on machines where that is
+ considered one of the addressable registers, and any other numbered register
+ with a standard use.
+
+ This information is expressed as a sequence of numbers, separated by commas
+ and surrounded by braces. The Nth number is 1 if register N is fixed, 0
+ otherwise.
+
+ The table initialized from this macro, and the table initialized by the
+ following one, may be overridden at run time either automatically, by the
+ actions of the macro `TARGET_CONDITIONAL_REGISTER_USAGE', or by the user
+ with the command options `-ffixed-REG', `-fcall-used-REG' and
+ `-fcall-saved-REG'. */
+#define FIXED_REGISTERS \
+ { 1, 0, 0, 0, 0, 0, 0, 0, /* 0 - 7 */ \
+ 0, 0, 0, 0, 0, 0, 0, 1, /* 8 - 15 */ \
+ 1, 1, 1, 1, 1 } /* 16 - 20 */
+
+/* XXX - MDL and MDH set as fixed for now - this is until I can get the
+ mul patterns working. */
+
+/* Like `FIXED_REGISTERS' but has 1 for each register that is clobbered (in
+ general) by function calls as well as for fixed registers. This macro
+ therefore identifies the registers that are not available for general
+ allocation of values that must live across function calls.
+
+ If a register has 0 in `CALL_USED_REGISTERS', the compiler automatically
+ saves it on function entry and restores it on function exit, if the register
+ is used within the function. */
+#define CALL_USED_REGISTERS \
+ { 1, 1, 1, 1, 1, 1, 1, 1, /* 0 - 7 */ \
+ 0, 0, 0, 0, 1, 1, 0, 1, /* 8 - 15 */ \
+ 1, 1, 1, 1, 1 } /* 16 - 20 */
+
+/* A C initializer containing the assembler's names for the machine registers,
+ each one as a C string constant. This is what translates register numbers
+ in the compiler into assembler language. */
+#define REGISTER_NAMES \
+{ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+ "r8", "r9", "r10", "r11", "r12", "ac", "fp", "sp", \
+ "cc", "rp", "mdh", "mdl", "ap" \
+}
+
+/* If defined, a C initializer for an array of structures containing a name and
+ a register number. This macro defines additional names for hard registers,
+ thus allowing the `asm' option in declarations to refer to registers using
+ alternate names. */
+#define ADDITIONAL_REGISTER_NAMES \
+{ \
+ {"r13", 13}, {"r14", 14}, {"r15", 15}, {"usp", 15}, {"ps", 16}\
+}
+
+/*}}}*/
+/*{{{ How Values Fit in Registers. */
+
+/* A C expression for the number of consecutive hard registers, starting at
+ register number REGNO, required to hold a value of mode MODE. */
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* A C expression that is nonzero if it is permissible to store a value of mode
+ MODE in hard register number REGNO (or in several registers starting with
+ that one). */
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) 1
+
+/* A C expression that is nonzero if it is desirable to choose register
+ allocation so as to avoid move instructions between a value of mode MODE1
+ and a value of mode MODE2.
+
+ If `HARD_REGNO_MODE_OK (R, MODE1)' and `HARD_REGNO_MODE_OK (R, MODE2)' are
+ ever different for any R, then `MODES_TIEABLE_P (MODE1, MODE2)' must be
+ zero. */
+#define MODES_TIEABLE_P(MODE1, MODE2) 1
+
+/*}}}*/
+/*{{{ Register Classes. */
+
+/* An enumeral type that must be defined with all the register class names as
+ enumeral values. `NO_REGS' must be first. `ALL_REGS' must be the last
+ register class, followed by one more enumeral value, `LIM_REG_CLASSES',
+ which is not a register class but rather tells how many classes there are.
+
+ Each register class has a number, which is the value of casting the class
+ name to type `int'. The number serves as an index in many of the tables
+ described below. */
+enum reg_class
+{
+ NO_REGS,
+ MULTIPLY_32_REG, /* the MDL register as used by the MULH, MULUH insns */
+ MULTIPLY_64_REG, /* the MDH,MDL register pair as used by MUL and MULU */
+ LOW_REGS, /* registers 0 through 7 */
+ HIGH_REGS, /* registers 8 through 15 */
+ REAL_REGS, /* i.e. all the general hardware registers on the FR30 */
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+#define GENERAL_REGS REAL_REGS
+#define N_REG_CLASSES ((int) LIM_REG_CLASSES)
+
+#define IRA_COVER_CLASSES \
+{ \
+ REAL_REGS, MULTIPLY_64_REG, LIM_REG_CLASSES \
+}
+
+/* An initializer containing the names of the register classes as C string
+ constants. These names are used in writing some of the debugging dumps. */
+#define REG_CLASS_NAMES \
+{ \
+ "NO_REGS", \
+ "MULTIPLY_32_REG", \
+ "MULTIPLY_64_REG", \
+ "LOW_REGS", \
+ "HIGH_REGS", \
+ "REAL_REGS", \
+ "ALL_REGS" \
+ }
+
+/* An initializer containing the contents of the register classes, as integers
+ which are bit masks. The Nth integer specifies the contents of class N.
+ The way the integer MASK is interpreted is that register R is in the class
+ if `MASK & (1 << R)' is 1.
+
+ When the machine has more than 32 registers, an integer does not suffice.
+ Then the integers are replaced by sub-initializers, braced groupings
+ containing several integers. Each sub-initializer must be suitable as an
+ initializer for the type `HARD_REG_SET' which is defined in
+ `hard-reg-set.h'. */
+#define REG_CLASS_CONTENTS \
+{ \
+ { 0 }, \
+ { 1 << MD_LOW_REGNUM }, \
+ { (1 << MD_LOW_REGNUM) | (1 << MD_HIGH_REGNUM) }, \
+ { (1 << 8) - 1 }, \
+ { ((1 << 8) - 1) << 8 }, \
+ { (1 << CONDITION_CODE_REGNUM) - 1 }, \
+ { (1 << FIRST_PSEUDO_REGISTER) - 1 } \
+}
+
+/* A C expression whose value is a register class containing hard register
+ REGNO. In general there is more than one such class; choose a class which
+ is "minimal", meaning that no smaller class also contains the register. */
+#define REGNO_REG_CLASS(REGNO) \
+ ( (REGNO) < 8 ? LOW_REGS \
+ : (REGNO) < CONDITION_CODE_REGNUM ? HIGH_REGS \
+ : (REGNO) == MD_LOW_REGNUM ? MULTIPLY_32_REG \
+ : (REGNO) == MD_HIGH_REGNUM ? MULTIPLY_64_REG \
+ : ALL_REGS)
+
+/* A macro whose definition is the name of the class to which a valid base
+ register must belong. A base register is one used in an address which is
+ the register value plus a displacement. */
+#define BASE_REG_CLASS REAL_REGS
+
+/* A macro whose definition is the name of the class to which a valid index
+ register must belong. An index register is one used in an address where its
+ value is either multiplied by a scale factor or added to another register
+ (as well as added to a displacement). */
+#define INDEX_REG_CLASS REAL_REGS
+
+/* A C expression which is nonzero if register number NUM is suitable for use
+ as a base register in operand addresses. It may be either a suitable hard
+ register or a pseudo register that has been allocated such a hard register. */
+#define REGNO_OK_FOR_BASE_P(NUM) 1
+
+/* A C expression which is nonzero if register number NUM is suitable for use
+ as an index register in operand addresses. It may be either a suitable hard
+ register or a pseudo register that has been allocated such a hard register.
+
+ The difference between an index register and a base register is that the
+ index register may be scaled. If an address involves the sum of two
+ registers, neither one of them scaled, then either one may be labeled the
+ "base" and the other the "index"; but whichever labeling is used must fit
+ the machine's constraints of which registers may serve in each capacity.
+ The compiler will try both labelings, looking for one that is valid, and
+ will reload one or both registers only if neither labeling works. */
+#define REGNO_OK_FOR_INDEX_P(NUM) 1
+
+/* A C expression for the maximum number of consecutive registers of
+ class CLASS needed to hold a value of mode MODE.
+
+ This is closely related to the macro `HARD_REGNO_NREGS'. In fact, the value
+ of the macro `CLASS_MAX_NREGS (CLASS, MODE)' should be the maximum value of
+ `HARD_REGNO_NREGS (REGNO, MODE)' for all REGNO values in the class CLASS.
+
+ This macro helps control the handling of multiple-word values in
+ the reload pass. */
+#define CLASS_MAX_NREGS(CLASS, MODE) HARD_REGNO_NREGS (0, MODE)
+
+/*}}}*/
+/*{{{ Basic Stack Layout. */
+
+/* Define this macro if pushing a word onto the stack moves the stack pointer
+ to a smaller address. */
+#define STACK_GROWS_DOWNWARD 1
+
+/* Define this to macro nonzero if the addresses of local variable slots
+ are at negative offsets from the frame pointer. */
+#define FRAME_GROWS_DOWNWARD 1
+
+/* Offset from the frame pointer to the first local variable slot to be
+ allocated.
+
+ If `FRAME_GROWS_DOWNWARD', find the next slot's offset by subtracting the
+ first slot's length from `STARTING_FRAME_OFFSET'. Otherwise, it is found by
+ adding the length of the first slot to the value `STARTING_FRAME_OFFSET'. */
+/* #define STARTING_FRAME_OFFSET -4 */
+#define STARTING_FRAME_OFFSET 0
+
+/* Offset from the stack pointer register to the first location at which
+ outgoing arguments are placed. If not specified, the default value of zero
+ is used. This is the proper value for most machines.
+
+ If `ARGS_GROW_DOWNWARD', this is the offset to the location above the first
+ location at which outgoing arguments are placed. */
+#define STACK_POINTER_OFFSET 0
+
+/* Offset from the argument pointer register to the first argument's address.
+ On some machines it may depend on the data type of the function.
+
+ If `ARGS_GROW_DOWNWARD', this is the offset to the location above the first
+ argument's address. */
+#define FIRST_PARM_OFFSET(FUNDECL) 0
+
+/* A C expression whose value is RTL representing the location of the incoming
+ return address at the beginning of any function, before the prologue. This
+ RTL is either a `REG', indicating that the return value is saved in `REG',
+ or a `MEM' representing a location in the stack.
+
+ You only need to define this macro if you want to support call frame
+ debugging information like that provided by DWARF 2. */
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_REG (SImode, RETURN_POINTER_REGNUM)
+
+/*}}}*/
+/*{{{ Register That Address the Stack Frame. */
+
+/* The register number of the arg pointer register, which is used to access the
+ function's argument list. On some machines, this is the same as the frame
+ pointer register. On some machines, the hardware determines which register
+ this is. On other machines, you can choose any register you wish for this
+ purpose. If this is not the same register as the frame pointer register,
+ then you must mark it as a fixed register according to `FIXED_REGISTERS', or
+ arrange to be able to eliminate it. */
+#define ARG_POINTER_REGNUM 20
+
+/*}}}*/
+/*{{{ Eliminating the Frame Pointer and the Arg Pointer. */
+
+/* If defined, this macro specifies a table of register pairs used to eliminate
+ unneeded registers that point into the stack frame. If it is not defined,
+ the only elimination attempted by the compiler is to replace references to
+ the frame pointer with references to the stack pointer.
+
+ The definition of this macro is a list of structure initializations, each of
+ which specifies an original and replacement register.
+
+ On some machines, the position of the argument pointer is not known until
+ the compilation is completed. In such a case, a separate hard register must
+ be used for the argument pointer. This register can be eliminated by
+ replacing it with either the frame pointer or the argument pointer,
+ depending on whether or not the frame pointer has been eliminated.
+
+ In this case, you might specify:
+ #define ELIMINABLE_REGS \
+ {{ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}}
+
+ Note that the elimination of the argument pointer with the stack pointer is
+ specified first since that is the preferred elimination. */
+
+#define ELIMINABLE_REGS \
+{ \
+ {ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ {ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ {FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \
+}
+
+/* This macro is similar to `INITIAL_FRAME_POINTER_OFFSET'. It specifies the
+ initial difference between the specified pair of registers. This macro must
+ be defined if `ELIMINABLE_REGS' is defined. */
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ (OFFSET) = fr30_compute_frame_size (FROM, TO)
+
+/*}}}*/
+/*{{{ Passing Function Arguments on the Stack. */
+
+/* If defined, the maximum amount of space required for outgoing arguments will
+ be computed and placed into the variable
+ `crtl->outgoing_args_size'. No space will be pushed onto the
+ stack for each call; instead, the function prologue should increase the
+ stack frame size by this amount.
+
+ Defining both `PUSH_ROUNDING' and `ACCUMULATE_OUTGOING_ARGS' is not
+ proper. */
+#define ACCUMULATE_OUTGOING_ARGS 1
+
+/*}}}*/
+/*{{{ Function Arguments in Registers. */
+
+/* The number of register assigned to holding function arguments. */
+
+#define FR30_NUM_ARG_REGS 4
+
+/* A C type for declaring a variable that is used as the first argument of
+ `FUNCTION_ARG' and other related values. For some target machines, the type
+ `int' suffices and can hold the number of bytes of argument so far.
+
+ There is no need to record in `CUMULATIVE_ARGS' anything about the arguments
+ that have been passed on the stack. The compiler has other variables to
+ keep track of that. For target machines on which all arguments are passed
+ on the stack, there is no need to store anything in `CUMULATIVE_ARGS';
+ however, the data structure must exist and should not be empty, so use
+ `int'. */
+/* On the FR30 this value is an accumulating count of the number of argument
+ registers that have been filled with argument values, as opposed to say,
+ the number of bytes of argument accumulated so far. */
+#define CUMULATIVE_ARGS int
+
+/* A C statement (sans semicolon) for initializing the variable CUM for the
+ state at the beginning of the argument list. The variable has type
+ `CUMULATIVE_ARGS'. The value of FNTYPE is the tree node for the data type
+ of the function which will receive the args, or 0 if the args are to a
+ compiler support library function. The value of INDIRECT is nonzero when
+ processing an indirect call, for example a call through a function pointer.
+ The value of INDIRECT is zero for a call to an explicitly named function, a
+ library function call, or when `INIT_CUMULATIVE_ARGS' is used to find
+ arguments for the function being compiled.
+
+ When processing a call to a compiler support library function, LIBNAME
+ identifies which one. It is a `symbol_ref' rtx which contains the name of
+ the function, as a string. LIBNAME is 0 when an ordinary C function call is
+ being processed. Thus, each time this macro is called, either LIBNAME or
+ FNTYPE is nonzero, but never both of them at once. */
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
+ (CUM) = 0
+
+/* A C expression that is nonzero if REGNO is the number of a hard register in
+ which function arguments are sometimes passed. This does *not* include
+ implicit arguments such as the static chain and the structure-value address.
+ On many machines, no registers can be used for this purpose since all
+ function arguments are pushed on the stack. */
+#define FUNCTION_ARG_REGNO_P(REGNO) \
+ ((REGNO) >= FIRST_ARG_REGNUM && ((REGNO) < FIRST_ARG_REGNUM + FR30_NUM_ARG_REGS))
+
+/*}}}*/
+/*{{{ How Large Values are Returned. */
+
+/* Define this macro to be 1 if all structure and union return values must be
+ in memory. Since this results in slower code, this should be defined only
+ if needed for compatibility with other compilers or with an ABI. If you
+ define this macro to be 0, then the conventions used for structure and union
+ return values are decided by the `TARGET_RETURN_IN_MEMORY' macro.
+
+ If not defined, this defaults to the value 1. */
+#define DEFAULT_PCC_STRUCT_RETURN 1
+
+/*}}}*/
+/*{{{ Generating Code for Profiling. */
+
+/* A C statement or compound statement to output to FILE some assembler code to
+ call the profiling subroutine `mcount'. Before calling, the assembler code
+ must load the address of a counter variable into a register where `mcount'
+ expects to find the address. The name of this variable is `LP' followed by
+ the number LABELNO, so you would generate the name using `LP%d' in a
+ `fprintf'.
+
+ The details of how the address should be passed to `mcount' are determined
+ by your operating system environment, not by GCC. To figure them out,
+ compile a small program for profiling using the system's installed C
+ compiler and look at the assembler code that results. */
+#define FUNCTION_PROFILER(FILE, LABELNO) \
+{ \
+ fprintf (FILE, "\t mov rp, r1\n" ); \
+ fprintf (FILE, "\t ldi:32 mcount, r0\n" ); \
+ fprintf (FILE, "\t call @r0\n" ); \
+ fprintf (FILE, ".word\tLP%d\n", LABELNO); \
+}
+
+/*}}}*/
+/*{{{ Trampolines for Nested Functions. */
+
+/* A C expression for the size in bytes of the trampoline, as an integer. */
+#define TRAMPOLINE_SIZE 18
+
+/* We want the trampoline to be aligned on a 32bit boundary so that we can
+ make sure the location of the static chain & target function within
+ the trampoline is also aligned on a 32bit boundary. */
+#define TRAMPOLINE_ALIGNMENT 32
+
+/*}}}*/
+/*{{{ Addressing Modes. */
+
+/* A number, the maximum number of registers that can appear in a valid memory
+ address. Note that it is up to you to specify a value equal to the maximum
+ number that `GO_IF_LEGITIMATE_ADDRESS' would ever accept. */
+#define MAX_REGS_PER_ADDRESS 1
+
+/* A C compound statement with a conditional `goto LABEL;' executed if X (an
+ RTX) is a legitimate memory address on the target machine for a memory
+ operand of mode MODE. */
+
+/* On the FR30 we only have one real addressing mode - an address in a
+ register. There are three special cases however:
+
+ * indexed addressing using small positive offsets from the stack pointer
+
+ * indexed addressing using small signed offsets from the frame pointer
+
+ * register plus register addressing using R13 as the base register.
+
+ At the moment we only support the first two of these special cases. */
+
+#ifdef REG_OK_STRICT
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \
+ do \
+ { \
+ if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \
+ goto LABEL; \
+ if (GET_CODE (X) == PLUS \
+ && ((MODE) == SImode || (MODE) == SFmode) \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && IN_RANGE (INTVAL (XEXP (X, 1)), 0, (1 << 6) - 4)) \
+ goto LABEL; \
+ if (GET_CODE (X) == PLUS \
+ && ((MODE) == SImode || (MODE) == SFmode) \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && REGNO (XEXP (X, 0)) == FRAME_POINTER_REGNUM \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && IN_RANGE (INTVAL (XEXP (X, 1)), -(1 << 9), (1 << 9) - 4)) \
+ goto LABEL; \
+ } \
+ while (0)
+#else
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL) \
+ do \
+ { \
+ if (GET_CODE (X) == REG && REG_OK_FOR_BASE_P (X)) \
+ goto LABEL; \
+ if (GET_CODE (X) == PLUS \
+ && ((MODE) == SImode || (MODE) == SFmode) \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && REGNO (XEXP (X, 0)) == STACK_POINTER_REGNUM \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && IN_RANGE (INTVAL (XEXP (X, 1)), 0, (1 << 6) - 4)) \
+ goto LABEL; \
+ if (GET_CODE (X) == PLUS \
+ && ((MODE) == SImode || (MODE) == SFmode) \
+ && GET_CODE (XEXP (X, 0)) == REG \
+ && (REGNO (XEXP (X, 0)) == FRAME_POINTER_REGNUM \
+ || REGNO (XEXP (X, 0)) == ARG_POINTER_REGNUM) \
+ && GET_CODE (XEXP (X, 1)) == CONST_INT \
+ && IN_RANGE (INTVAL (XEXP (X, 1)), -(1 << 9), (1 << 9) - 4)) \
+ goto LABEL; \
+ } \
+ while (0)
+#endif
+
+/* A C expression that is nonzero if X (assumed to be a `reg' RTX) is valid for
+ use as a base register. For hard registers, it should always accept those
+ which the hardware permits and reject the others. Whether the macro accepts
+ or rejects pseudo registers must be controlled by `REG_OK_STRICT' as
+ described above. This usually requires two variant definitions, of which
+ `REG_OK_STRICT' controls the one actually used. */
+#ifdef REG_OK_STRICT
+#define REG_OK_FOR_BASE_P(X) (((unsigned) REGNO (X)) <= STACK_POINTER_REGNUM)
+#else
+#define REG_OK_FOR_BASE_P(X) 1
+#endif
+
+/* A C expression that is nonzero if X (assumed to be a `reg' RTX) is valid for
+ use as an index register.
+
+ The difference between an index register and a base register is that the
+ index register may be scaled. If an address involves the sum of two
+ registers, neither one of them scaled, then either one may be labeled the
+ "base" and the other the "index"; but whichever labeling is used must fit
+ the machine's constraints of which registers may serve in each capacity.
+ The compiler will try both labelings, looking for one that is valid, and
+ will reload one or both registers only if neither labeling works. */
+#define REG_OK_FOR_INDEX_P(X) REG_OK_FOR_BASE_P (X)
+
+/* A C expression that is nonzero if X is a legitimate constant for an
+ immediate operand on the target machine. You can assume that X satisfies
+ `CONSTANT_P', so you need not check this. In fact, `1' is a suitable
+ definition for this macro on machines where anything `CONSTANT_P' is valid. */
+#define LEGITIMATE_CONSTANT_P(X) 1
+
+/*}}}*/
+/*{{{ Describing Relative Costs of Operations */
+
+/* Define this macro as a C expression which is nonzero if accessing less than
+ a word of memory (i.e. a `char' or a `short') is no faster than accessing a
+ word of memory, i.e., if such access require more than one instruction or if
+ there is no difference in cost between byte and (aligned) word loads.
+
+ When this macro is not defined, the compiler will access a field by finding
+ the smallest containing object; when it is defined, a fullword load will be
+ used if alignment permits. Unless bytes accesses are faster than word
+ accesses, using word accesses is preferable since it may eliminate
+ subsequent memory access if subsequent accesses occur to other fields in the
+ same word of the structure, but to different bytes. */
+#define SLOW_BYTE_ACCESS 1
+
+/*}}}*/
+/*{{{ Dividing the output into sections. */
+
+/* A C expression whose value is a string containing the assembler operation
+ that should precede instructions and read-only data. Normally `".text"' is
+ right. */
+#define TEXT_SECTION_ASM_OP "\t.text"
+
+/* A C expression whose value is a string containing the assembler operation to
+ identify the following data as writable initialized data. Normally
+ `".data"' is right. */
+#define DATA_SECTION_ASM_OP "\t.data"
+
+/* If defined, a C expression whose value is a string containing the
+ assembler operation to identify the following data as
+ uninitialized global data. If not defined, and neither
+ `ASM_OUTPUT_BSS' nor `ASM_OUTPUT_ALIGNED_BSS' are defined,
+ uninitialized global data will be output in the data section if
+ `-fno-common' is passed, otherwise `ASM_OUTPUT_COMMON' will be
+ used. */
+#define BSS_SECTION_ASM_OP "\t.section .bss"
+
+/*}}}*/
+/*{{{ The Overall Framework of an Assembler File. */
+
+/* A C string constant describing how to begin a comment in the target
+ assembler language. The compiler assumes that the comment will end at the
+ end of the line. */
+#define ASM_COMMENT_START ";"
+
+/* A C string constant for text to be output before each `asm' statement or
+ group of consecutive ones. Normally this is `"#APP"', which is a comment
+ that has no effect on most assemblers but tells the GNU assembler that it
+ must check the lines that follow for all valid assembler constructs. */
+#define ASM_APP_ON "#APP\n"
+
+/* A C string constant for text to be output after each `asm' statement or
+ group of consecutive ones. Normally this is `"#NO_APP"', which tells the
+ GNU assembler to resume making the time-saving assumptions that are valid
+ for ordinary compiler output. */
+#define ASM_APP_OFF "#NO_APP\n"
+
+/*}}}*/
+/*{{{ Output and Generation of Labels. */
+
+/* Globalizing directive for a label. */
+#define GLOBAL_ASM_OP "\t.globl "
+
+/*}}}*/
+/*{{{ Output of Assembler Instructions. */
+
+/* A C compound statement to output to stdio stream STREAM the assembler syntax
+ for an instruction operand X. X is an RTL expression.
+
+ CODE is a value that can be used to specify one of several ways of printing
+ the operand. It is used when identical operands must be printed differently
+ depending on the context. CODE comes from the `%' specification that was
+ used to request printing of the operand. If the specification was just
+ `%DIGIT' then CODE is 0; if the specification was `%LTR DIGIT' then CODE is
+ the ASCII code for LTR.
+
+ If X is a register, this macro should print the register's name. The names
+ can be found in an array `reg_names' whose type is `char *[]'. `reg_names'
+ is initialized from `REGISTER_NAMES'.
+
+ When the machine description has a specification `%PUNCT' (a `%' followed by
+ a punctuation character), this macro is called with a null pointer for X and
+ the punctuation character for CODE. */
+#define PRINT_OPERAND(STREAM, X, CODE) fr30_print_operand (STREAM, X, CODE)
+
+/* A C expression which evaluates to true if CODE is a valid punctuation
+ character for use in the `PRINT_OPERAND' macro. If
+ `PRINT_OPERAND_PUNCT_VALID_P' is not defined, it means that no punctuation
+ characters (except for the standard one, `%') are used in this way. */
+#define PRINT_OPERAND_PUNCT_VALID_P(CODE) (CODE == '#')
+
+/* A C compound statement to output to stdio stream STREAM the assembler syntax
+ for an instruction operand that is a memory reference whose address is X. X
+ is an RTL expression. */
+
+#define PRINT_OPERAND_ADDRESS(STREAM, X) fr30_print_operand_address (STREAM, X)
+
+#define REGISTER_PREFIX "%"
+#define LOCAL_LABEL_PREFIX "."
+#define USER_LABEL_PREFIX ""
+#define IMMEDIATE_PREFIX ""
+
+/*}}}*/
+/*{{{ Output of Dispatch Tables. */
+
+/* This macro should be provided on machines where the addresses in a dispatch
+ table are relative to the table's own address.
+
+ The definition should be a C statement to output to the stdio stream STREAM
+ an assembler pseudo-instruction to generate a difference between two labels.
+ VALUE and REL are the numbers of two internal labels. The definitions of
+ these labels are output using `(*targetm.asm_out.internal_label)', and they must be
+ printed in the same way here. For example,
+
+ fprintf (STREAM, "\t.word L%d-L%d\n", VALUE, REL) */
+#define ASM_OUTPUT_ADDR_DIFF_ELT(STREAM, BODY, VALUE, REL) \
+fprintf (STREAM, "\t.word .L%d-.L%d\n", VALUE, REL)
+
+/* This macro should be provided on machines where the addresses in a dispatch
+ table are absolute.
+
+ The definition should be a C statement to output to the stdio stream STREAM
+ an assembler pseudo-instruction to generate a reference to a label. VALUE
+ is the number of an internal label whose definition is output using
+ `(*targetm.asm_out.internal_label)'. For example,
+
+ fprintf (STREAM, "\t.word L%d\n", VALUE) */
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
+fprintf (STREAM, "\t.word .L%d\n", VALUE)
+
+/*}}}*/
+/*{{{ Assembler Commands for Alignment. */
+
+/* A C statement to output to the stdio stream STREAM an assembler command to
+ advance the location counter to a multiple of 2 to the POWER bytes. POWER
+ will be a C expression of type `int'. */
+#define ASM_OUTPUT_ALIGN(STREAM, POWER) \
+ fprintf ((STREAM), "\t.p2align %d\n", (POWER))
+
+/*}}}*/
+/*{{{ Miscellaneous Parameters. */
+
+/* An alias for a machine mode name. This is the machine mode that elements of
+ a jump-table should have. */
+#define CASE_VECTOR_MODE SImode
+
+/* The maximum number of bytes that a single instruction can move quickly from
+ memory to memory. */
+#define MOVE_MAX 8
+
+/* A C expression which is nonzero if on this machine it is safe to "convert"
+ an integer of INPREC bits to one of OUTPREC bits (where OUTPREC is smaller
+ than INPREC) by merely operating on it as if it had only OUTPREC bits.
+
+ On many machines, this expression can be 1.
+
+ When `TRULY_NOOP_TRUNCATION' returns 1 for a pair of sizes for modes for
+ which `MODES_TIEABLE_P' is 0, suboptimal code can result. If this is the
+ case, making `TRULY_NOOP_TRUNCATION' return 0 in such cases may improve
+ things. */
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+/* An alias for the machine mode for pointers. On most machines, define this
+ to be the integer mode corresponding to the width of a hardware pointer;
+ `SImode' on 32-bit machine or `DImode' on 64-bit machines. On some machines
+ you must define this to be one of the partial integer modes, such as
+ `PSImode'.
+
+ The width of `Pmode' must be at least as large as the value of
+ `POINTER_SIZE'. If it is not equal, you must define the macro
+ `POINTERS_EXTEND_UNSIGNED' to specify how pointers are extended to `Pmode'. */
+#define Pmode SImode
+
+/* An alias for the machine mode used for memory references to functions being
+ called, in `call' RTL expressions. On most machines this should be
+ `QImode'. */
+#define FUNCTION_MODE QImode
+
+/* If cross-compiling, don't require stdio.h etc to build libgcc.a. */
+#if defined CROSS_DIRECTORY_STRUCTURE && ! defined inhibit_libc
+#define inhibit_libc
+#endif
+
+/*}}}*/
+
+/* Local Variables: */
+/* folded-file: t */
+/* End: */
diff --git a/gcc/config/fr30/fr30.md b/gcc/config/fr30/fr30.md
new file mode 100644
index 000000000..6b3559983
--- /dev/null
+++ b/gcc/config/fr30/fr30.md
@@ -0,0 +1,1268 @@
+;; FR30 machine description.
+;; Copyright (C) 1998, 1999, 2000, 2002, 2004, 2005, 2007, 2010
+;; Free Software Foundation, Inc.
+;; Contributed by Cygnus Solutions.
+
+;; 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/>.
+
+;;- See file "rtl.def" for documentation on define_insn, match_*, et. al.
+
+;;{{{ Attributes
+
+(define_attr "length" "" (const_int 2))
+
+;; Used to distinguish between small memory model targets and big mode targets.
+
+(define_attr "size" "small,big"
+ (const (if_then_else (symbol_ref "TARGET_SMALL_MODEL")
+ (const_string "small")
+ (const_string "big"))))
+
+
+;; Define an attribute to be used by the delay slot code.
+;; An instruction by default is considered to be 'delayable'
+;; that is, it can be placed into a delay slot, but it is not
+;; itself a delayed branch type instruction. An instruction
+;; whose type is 'delayed' is one which has a delay slot, and
+;; an instruction whose delay_type is 'other' is one which does
+;; not have a delay slot, nor can it be placed into a delay slot.
+
+(define_attr "delay_type" "delayable,delayed,other" (const_string "delayable"))
+
+;;}}}
+;;{{{ Delay Slot Specifications
+
+(define_delay (eq_attr "delay_type" "delayed")
+ [(and (eq_attr "delay_type" "delayable")
+ (eq_attr "length" "2"))
+ (nil)
+ (nil)]
+)
+
+(include "predicates.md")
+(include "constraints.md")
+
+;;}}}
+;;{{{ Moves
+
+;;{{{ Comment
+
+;; Wrap moves in define_expand to prevent memory->memory moves from being
+;; generated at the RTL level, which generates better code for most machines
+;; which can't do mem->mem moves.
+
+;; If operand 0 is a `subreg' with mode M of a register whose own mode is wider
+;; than M, the effect of this instruction is to store the specified value in
+;; the part of the register that corresponds to mode M. The effect on the rest
+;; of the register is undefined.
+
+;; This class of patterns is special in several ways. First of all, each of
+;; these names *must* be defined, because there is no other way to copy a datum
+;; from one place to another.
+
+;; Second, these patterns are not used solely in the RTL generation pass. Even
+;; the reload pass can generate move insns to copy values from stack slots into
+;; temporary registers. When it does so, one of the operands is a hard
+;; register and the other is an operand that can need to be reloaded into a
+;; register.
+
+;; Therefore, when given such a pair of operands, the pattern must
+;; generate RTL which needs no reloading and needs no temporary
+;; registers--no registers other than the operands. For example, if
+;; you support the pattern with a `define_expand', then in such a
+;; case the `define_expand' mustn't call `force_reg' or any other such
+;; function which might generate new pseudo registers.
+
+;; This requirement exists even for subword modes on a RISC machine
+;; where fetching those modes from memory normally requires several
+;; insns and some temporary registers. Look in `spur.md' to see how
+;; the requirement can be satisfied.
+
+;; During reload a memory reference with an invalid address may be passed as an
+;; operand. Such an address will be replaced with a valid address later in the
+;; reload pass. In this case, nothing may be done with the address except to
+;; use it as it stands. If it is copied, it will not be replaced with a valid
+;; address. No attempt should be made to make such an address into a valid
+;; address and no routine (such as `change_address') that will do so may be
+;; called. Note that `general_operand' will fail when applied to such an
+;; address.
+;;
+;; The global variable `reload_in_progress' (which must be explicitly declared
+;; if required) can be used to determine whether such special handling is
+;; required.
+;;
+;; The variety of operands that have reloads depends on the rest of
+;; the machine description, but typically on a RISC machine these can
+;; only be pseudo registers that did not get hard registers, while on
+;; other machines explicit memory references will get optional
+;; reloads.
+;;
+;; If a scratch register is required to move an object to or from memory, it
+;; can be allocated using `gen_reg_rtx' prior to reload. But this is
+;; impossible during and after reload. If there are cases needing scratch
+;; registers after reload, you must define `SECONDARY_INPUT_RELOAD_CLASS' and
+;; perhaps also `SECONDARY_OUTPUT_RELOAD_CLASS' to detect them, and provide
+;; patterns `reload_inM' or `reload_outM' to handle them.
+
+;; The constraints on a `moveM' must permit moving any hard register to any
+;; other hard register provided that `HARD_REGNO_MODE_OK' permits mode M in
+;; both registers and `REGISTER_MOVE_COST' applied to their classes returns a
+;; value of 2.
+
+;; It is obligatory to support floating point `moveM' instructions
+;; into and out of any registers that can hold fixed point values,
+;; because unions and structures (which have modes `SImode' or
+;; `DImode') can be in those registers and they may have floating
+;; point members.
+
+;; There may also be a need to support fixed point `moveM' instructions in and
+;; out of floating point registers. Unfortunately, I have forgotten why this
+;; was so, and I don't know whether it is still true. If `HARD_REGNO_MODE_OK'
+;; rejects fixed point values in floating point registers, then the constraints
+;; of the fixed point `moveM' instructions must be designed to avoid ever
+;; trying to reload into a floating point register.
+
+;;}}}
+;;{{{ Push and Pop
+
+;; Push a register onto the stack
+(define_insn "movsi_push"
+ [(set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 0 "register_operand" "a"))]
+ ""
+ "st %0, @-r15"
+)
+
+;; Pop a register off the stack
+(define_insn "movsi_pop"
+ [(set (match_operand:SI 0 "register_operand" "=a")
+ (mem:SI (post_inc:SI (reg:SI 15))))]
+ ""
+ "ld @r15+, %0"
+)
+
+;;}}}
+;;{{{ 1 Byte Moves
+
+(define_expand "movqi"
+ [(set (match_operand:QI 0 "general_operand" "")
+ (match_operand:QI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (!reload_in_progress
+ && !reload_completed
+ && GET_CODE (operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM
+ || immediate_operand (operands[1], QImode)))
+ operands[1] = copy_to_mode_reg (QImode, operands[1]);
+}")
+
+(define_insn "movqi_unsigned_register_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:QI 1 "memory_operand" "m")))]
+ ""
+ "ldub %1, %0"
+)
+
+(define_expand "movqi_signed_register_load"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:QI 1 "memory_operand" "")))]
+ ""
+ "
+ emit_insn (gen_movqi_unsigned_register_load (operands[0], operands[1]));
+ emit_insn (gen_extendqisi2 (operands[0], operands[0]));
+ DONE;
+ "
+)
+
+(define_insn "*movqi_internal"
+ [(set (match_operand:QI 0 "nonimmediate_operand" "=r,red,m,r")
+ (match_operand:QI 1 "general_operand" "i,red,r,rm"))]
+ ""
+ "@
+ ldi:8\\t#%A1, %0
+ mov \\t%1, %0
+ stb \\t%1, %0
+ ldub \\t%1, %0"
+)
+
+;;}}}
+;;{{{ 2 Byte Moves
+
+(define_expand "movhi"
+ [(set (match_operand:HI 0 "general_operand" "")
+ (match_operand:HI 1 "general_operand" ""))]
+ ""
+ "
+{
+ if (!reload_in_progress
+ && !reload_completed
+ && GET_CODE (operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM
+ || immediate_operand (operands[1], HImode)))
+ operands[1] = copy_to_mode_reg (HImode, operands[1]);
+}")
+
+(define_insn "movhi_unsigned_register_load"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:HI 1 "memory_operand" "m")))]
+ ""
+ "lduh %1, %0"
+)
+
+(define_expand "movhi_signed_register_load"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (sign_extend:SI (match_operand:HI 1 "memory_operand" "")))]
+ ""
+ "
+ emit_insn (gen_movhi_unsigned_register_load (operands[0], operands[1]));
+ emit_insn (gen_extendhisi2 (operands[0], operands[0]));
+ DONE;
+ "
+)
+
+(define_insn "*movhi_internal"
+ [(set (match_operand:HI 0 "nonimmediate_operand" "=r,r,r,red,m,r")
+ (match_operand:HI 1 "general_operand" "L,M,n,red,r,rm"))]
+ ""
+ "@
+ ldi:8 \\t#%1, %0
+ ldi:20\\t#%1, %0
+ ldi:32\\t#%1, %0
+ mov \\t%1, %0
+ sth \\t%1, %0
+ lduh \\t%1, %0"
+ [(set_attr "length" "*,4,6,*,*,*")]
+)
+
+;;}}}
+;;{{{ 4 Byte Moves
+
+;; If the destination is a MEM and the source is a
+;; MEM or an CONST_INT move the source into a register.
+(define_expand "movsi"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "")
+ (match_operand:SI 1 "general_operand" ""))]
+ ""
+ "{
+ if (!reload_in_progress
+ && !reload_completed
+ && GET_CODE(operands[0]) == MEM
+ && (GET_CODE (operands[1]) == MEM
+ || immediate_operand (operands[1], SImode)))
+ operands[1] = copy_to_mode_reg (SImode, operands[1]);
+ }"
+)
+
+;; We can do some clever tricks when loading certain immediate
+;; values. We implement these tricks as define_splits, rather
+;; than putting the code into the define_expand "movsi" above,
+;; because if we put them there, they will be evaluated at RTL
+;; generation time and then the combiner pass will come along
+;; and replace the multiple insns that have been generated with
+;; the original, slower, load insns. (The combiner pass only
+;; cares about reducing the number of instructions, it does not
+;; care about instruction lengths or speeds). Splits are
+;; evaluated after the combine pass and before the scheduling
+;; passes, so that they are the perfect place to put this
+;; intelligence.
+;;
+;; XXX we probably ought to implement these for QI and HI mode
+;; loads as well.
+
+;; If we are loading a small negative constant we can save space
+;; and time by loading the positive value and then sign extending it.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))]
+ "INTVAL (operands[1]) <= -1 && INTVAL (operands[1]) >= -128
+ && (GET_CODE (operands[0]) != SUBREG
+ || SCALAR_INT_MODE_P (GET_MODE (XEXP (operands[0], 0))))"
+ [(set (match_dup 0) (match_dup 1))
+ (set (match_dup 0) (sign_extend:SI (match_dup 2)))]
+ "{
+ operands[1] = GEN_INT (INTVAL (operands[1]) & 0xff);
+ operands[2] = gen_lowpart (QImode, operands[0]);
+ }"
+)
+
+;; If we are loading a large negative constant, one which does
+;; not have any of its bottom 24 bit set, then we can save time
+;; and space by loading the byte value and shifting it into place.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))]
+ "(INTVAL (operands[1]) < 0) && ((INTVAL (operands[1]) & 0x00ffffff) == 0)"
+ [(set (match_dup 0) (match_dup 2))
+ (parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (const_int 24)))
+ (clobber (reg:CC 16))])]
+ "{
+ HOST_WIDE_INT val = INTVAL (operands[1]);
+ operands[2] = GEN_INT (val >> 24);
+ }"
+)
+
+;; If we are loading a large positive constant, one which has bits
+;; in the top byte set, but whose set bits all lie within an 8 bit
+;; range, then we can save time and space by loading the byte value
+;; and shifting it into place.
+(define_split
+ [(set (match_operand:SI 0 "register_operand" "")
+ (match_operand:SI 1 "const_int_operand" ""))]
+ "(INTVAL (operands[1]) > 0x00ffffff)
+ && ((INTVAL (operands[1]) >> exact_log2 (INTVAL (operands[1]) & (- INTVAL (operands[1])))) < 0x100)"
+ [(set (match_dup 0) (match_dup 2))
+ (parallel [(set (match_dup 0) (ashift:SI (match_dup 0) (match_dup 3)))
+ (clobber (reg:CC 16))])]
+ "{
+ HOST_WIDE_INT val = INTVAL (operands[1]);
+ int shift = exact_log2 (val & ( - val));
+ operands[2] = GEN_INT (val >> shift);
+ operands[3] = GEN_INT (shift);
+ }"
+)
+
+;; When TARGET_SMALL_MODEL is defined we assume that all symbolic
+;; values are addresses which will fit in 20 bits.
+
+(define_insn "movsi_internal"
+ [(set (match_operand:SI 0 "nonimmediate_operand" "=r,r,r,r,red,V,r,m")
+ (match_operand:SI 1 "general_operand" "L,M,n,i,rde,r,rm,r"))]
+ ""
+ "*
+ {
+ switch (which_alternative)
+ {
+ case 0: return \"ldi:8 \\t#%1, %0\";
+ case 1: return \"ldi:20\\t#%1, %0\";
+ case 2: return \"ldi:32\\t#%1, %0\";
+ case 3: if (TARGET_SMALL_MODEL)
+ return \"ldi:20\\t%1, %0\";
+ else
+ return \"ldi:32\\t%1, %0\";
+ case 4: return \"mov \\t%1, %0\";
+ case 5: return \"st \\t%1, %0\";
+ case 6: return \"ld \\t%1, %0\";
+ case 7: return \"st \\t%1, %0\";
+ default: gcc_unreachable ();
+ }
+ }"
+ [(set (attr "length") (cond [(eq_attr "alternative" "1") (const_int 4)
+ (eq_attr "alternative" "2") (const_int 6)
+ (eq_attr "alternative" "3")
+ (if_then_else (eq_attr "size" "small")
+ (const_int 4)
+ (const_int 6))]
+ (const_int 2)))]
+)
+
+;;}}}
+;;{{{ 8 Byte Moves
+
+;; Note - the FR30 does not have an 8 byte load/store instruction
+;; but we have to support this pattern because some other patterns
+;; (e.g. muldisi2) can produce a DImode result.
+;; (This code is stolen from the M32R port.)
+
+(define_expand "movdi"
+ [(set (match_operand:DI 0 "nonimmediate_operand" "")
+ (match_operand:DI 1 "general_operand" ""))]
+ ""
+ "
+ /* Everything except mem = const or mem = mem can be done easily. */
+
+ if (GET_CODE (operands[0]) == MEM)
+ operands[1] = force_reg (DImode, operands[1]);
+ "
+)
+
+;; We use an insn and a split so that we can generate
+;; RTL rather than text from fr30_move_double().
+
+(define_insn "*movdi_insn"
+ [(set (match_operand:DI 0 "nonimmediate_di_operand" "=r,r,m,r")
+ (match_operand:DI 1 "di_operand" "r,m,r,nF"))]
+ "register_operand (operands[0], DImode) || register_operand (operands[1], DImode)"
+ "#"
+ [(set_attr "length" "4,8,12,12")]
+)
+
+(define_split
+ [(set (match_operand:DI 0 "nonimmediate_di_operand" "")
+ (match_operand:DI 1 "di_operand" ""))]
+ "reload_completed"
+ [(match_dup 2)]
+ "operands[2] = fr30_move_double (operands);"
+)
+
+;;}}}
+;;{{{ Load & Store Multiple Registers
+
+;; The load multiple and store multiple patterns are implemented
+;; as peepholes because the only time they are expected to occur
+;; is during function prologues and epilogues.
+
+(define_peephole
+ [(set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 0 "high_register_operand" "h"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 1 "high_register_operand" "h"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 2 "high_register_operand" "h"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 3 "high_register_operand" "h"))]
+ "fr30_check_multiple_regs (operands, 4, 1)"
+ "stm1 (%0, %1, %2, %3)"
+ [(set_attr "delay_type" "other")]
+)
+
+(define_peephole
+ [(set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 0 "high_register_operand" "h"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 1 "high_register_operand" "h"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 2 "high_register_operand" "h"))]
+ "fr30_check_multiple_regs (operands, 3, 1)"
+ "stm1 (%0, %1, %2)"
+ [(set_attr "delay_type" "other")]
+)
+
+(define_peephole
+ [(set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 0 "high_register_operand" "h"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 1 "high_register_operand" "h"))]
+ "fr30_check_multiple_regs (operands, 2, 1)"
+ "stm1 (%0, %1)"
+ [(set_attr "delay_type" "other")]
+)
+
+(define_peephole
+ [(set (match_operand:SI 0 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))
+ (set (match_operand:SI 1 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))
+ (set (match_operand:SI 2 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))
+ (set (match_operand:SI 3 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))]
+ "fr30_check_multiple_regs (operands, 4, 0)"
+ "ldm1 (%0, %1, %2, %3)"
+ [(set_attr "delay_type" "other")]
+)
+
+(define_peephole
+ [(set (match_operand:SI 0 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))
+ (set (match_operand:SI 1 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))
+ (set (match_operand:SI 2 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))]
+ "fr30_check_multiple_regs (operands, 3, 0)"
+ "ldm1 (%0, %1, %2)"
+ [(set_attr "delay_type" "other")]
+)
+
+(define_peephole
+ [(set (match_operand:SI 0 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))
+ (set (match_operand:SI 1 "high_register_operand" "h")
+ (mem:SI (post_inc:SI (reg:SI 15))))]
+ "fr30_check_multiple_regs (operands, 2, 0)"
+ "ldm1 (%0, %1)"
+ [(set_attr "delay_type" "other")]
+)
+
+(define_peephole
+ [(set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 0 "low_register_operand" "l"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 1 "low_register_operand" "l"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 2 "low_register_operand" "l"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 3 "low_register_operand" "l"))]
+ "fr30_check_multiple_regs (operands, 4, 1)"
+ "stm0 (%0, %1, %2, %3)"
+ [(set_attr "delay_type" "other")]
+)
+
+(define_peephole
+ [(set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 0 "low_register_operand" "l"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 1 "low_register_operand" "l"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 2 "low_register_operand" "l"))]
+ "fr30_check_multiple_regs (operands, 3, 1)"
+ "stm0 (%0, %1, %2)"
+ [(set_attr "delay_type" "other")]
+)
+
+(define_peephole
+ [(set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 0 "low_register_operand" "l"))
+ (set (mem:SI (pre_dec:SI (reg:SI 15)))
+ (match_operand:SI 1 "low_register_operand" "l"))]
+ "fr30_check_multiple_regs (operands, 2, 1)"
+ "stm0 (%0, %1)"
+ [(set_attr "delay_type" "other")]
+)
+
+;;}}}
+;;{{{ Floating Point Moves
+
+;; Note - Patterns for SF mode moves are compulsory, but
+;; patterns for DF are optional, as GCC can synthesize them.
+
+(define_expand "movsf"
+ [(set (match_operand:SF 0 "general_operand" "")
+ (match_operand:SF 1 "general_operand" ""))]
+ ""
+ "{
+ if (!reload_in_progress && !reload_completed
+ && memory_operand (operands[0], SFmode)
+ && memory_operand (operands[1], SFmode))
+ operands[1] = copy_to_mode_reg (SFmode, operands[1]);
+ }"
+)
+
+(define_insn "*movsf_internal"
+ [(set (match_operand:SF 0 "nonimmediate_operand" "=r,r,red,m,r")
+ (match_operand:SF 1 "general_operand" "Fn,i,rde,r,rm"))]
+ ""
+ "*
+ {
+ switch (which_alternative)
+ {
+ case 0: return \"ldi:32\\t%1, %0\";
+ case 1: if (TARGET_SMALL_MODEL)
+ return \"ldi:20\\t%1, %0\";
+ else
+ return \"ldi:32\\t%1, %0\";
+ case 2: return \"mov \\t%1, %0\";
+ case 3: return \"st \\t%1, %0\";
+ case 4: return \"ld \\t%1, %0\";
+ default: gcc_unreachable ();
+ }
+ }"
+ [(set (attr "length") (cond [(eq_attr "alternative" "0") (const_int 6)
+ (eq_attr "alternative" "1")
+ (if_then_else (eq_attr "size" "small")
+ (const_int 4)
+ (const_int 6))]
+ (const_int 2)))]
+)
+
+(define_insn "*movsf_constant_store"
+ [(set (match_operand:SF 0 "memory_operand" "=m")
+ (match_operand:SF 1 "immediate_operand" "F"))]
+ ""
+ "*
+ {
+ const char * ldi_instr;
+ const char * tmp_reg;
+ static char buffer[100];
+
+ ldi_instr = fr30_const_double_is_zero (operands[1]) ? \"ldi:8\" : \"ldi:32\";
+
+ tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER];
+
+ sprintf (buffer, \"%s\\t#%%1, %s\\t;\\n\\tst\\t%s, %%0\\t; Created by movsf_constant_store\",
+ ldi_instr, tmp_reg, tmp_reg);
+
+ return buffer;
+ }"
+ [(set_attr "length" "8")]
+)
+
+;;}}}
+
+;;}}}
+;;{{{ Conversions
+
+;; Signed conversions from a smaller integer to a larger integer
+
+(define_insn "extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:QI 1 "register_operand" "0")))]
+ ""
+ "extsb %0"
+)
+
+(define_insn "extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sign_extend:SI (match_operand:HI 1 "register_operand" "0")))]
+ ""
+ "extsh %0"
+)
+
+;; Unsigned conversions from a smaller integer to a larger integer
+
+(define_insn "zero_extendqisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:QI 1 "register_operand" "0")))]
+ ""
+ "extub %0"
+)
+
+(define_insn "zero_extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (zero_extend:SI (match_operand:HI 1 "register_operand" "0")))]
+ ""
+ "extuh %0"
+)
+
+;;}}}
+;;{{{ Arithmetic
+
+;;{{{ Addition
+
+;; This is a special pattern just for adjusting the stack size.
+(define_insn "add_to_stack"
+ [(set (reg:SI 15)
+ (plus:SI (reg:SI 15)
+ (match_operand:SI 0 "stack_add_operand" "i")))]
+ ""
+ "addsp %0"
+)
+
+;; We need some trickery to be able to handle the addition of
+;; large (i.e. outside +/- 16) constants. We need to be able to
+;; handle this because reload assumes that it can generate add
+;; instructions with arbitrary sized constants.
+(define_expand "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))]
+ ""
+ "{
+ if ( GET_CODE (operands[2]) == REG
+ || GET_CODE (operands[2]) == SUBREG)
+ emit_insn (gen_addsi_regs (operands[0], operands[1], operands[2]));
+ else if (GET_CODE (operands[2]) != CONST_INT)
+ emit_insn (gen_addsi_big_int (operands[0], operands[1], operands[2]));
+ else if (INTVAL (operands[2]) >= -16
+ && INTVAL (operands[2]) <= 15
+ && (!REG_P (operands[1])
+ || !REGNO_PTR_FRAME_P (REGNO (operands[1]))
+ || REGNO (operands[1]) == STACK_POINTER_REGNUM))
+ emit_insn (gen_addsi_small_int (operands[0], operands[1], operands[2]));
+ else
+ emit_insn (gen_addsi_big_int (operands[0], operands[1], operands[2]));
+ DONE;
+ }"
+)
+
+(define_insn "addsi_regs"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "addn %2, %0"
+)
+
+;; Do not allow an eliminable register in the source register. It
+;; might be eliminated in favor of the stack pointer, probably
+;; increasing the offset, and so rendering the instruction illegal.
+(define_insn "addsi_small_int"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "add_immediate_operand" "I,J")))]
+ "!REG_P (operands[1])
+ || !REGNO_PTR_FRAME_P (REGNO (operands[1]))
+ || REGNO (operands[1]) == STACK_POINTER_REGNUM"
+ "@
+ addn %2, %0
+ addn2 %2, %0"
+)
+
+(define_expand "addsi_big_int"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (plus:SI (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "immediate_operand" "")))]
+ ""
+ "{
+ /* Cope with the possibility that ops 0 and 1 are the same register. */
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ if (reload_in_progress || reload_completed)
+ {
+ rtx reg = gen_rtx_REG (SImode, 0/*COMPILER_SCRATCH_REGISTER*/);
+
+ emit_insn (gen_movsi (reg, operands[2]));
+ emit_insn (gen_addsi_regs (operands[0], operands[0], reg));
+ }
+ else
+ {
+ operands[2] = force_reg (SImode, operands[2]);
+ emit_insn (gen_addsi_regs (operands[0], operands[0], operands[2]));
+ }
+ }
+ else
+ {
+ emit_insn (gen_movsi (operands[0], operands[2]));
+ emit_insn (gen_addsi_regs (operands[0], operands[0], operands[1]));
+ }
+ DONE;
+ }"
+)
+
+(define_insn "*addsi_for_reload"
+ [(set (match_operand:SI 0 "register_operand" "=&r,r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "r,r,r")
+ (match_operand:SI 2 "immediate_operand" "L,M,n")))]
+ "reload_in_progress || reload_completed"
+ "@
+ ldi:8\\t#%2, %0 \\n\\taddn\\t%1, %0
+ ldi:20\\t#%2, %0 \\n\\taddn\\t%1, %0
+ ldi:32\\t#%2, %0 \\n\\taddn\\t%1, %0"
+ [(set_attr "length" "4,6,8")]
+)
+
+;;}}}
+;;{{{ Subtraction
+
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:SI 2 "register_operand" "r")))]
+ ""
+ "subn %2, %0"
+)
+
+;;}}}
+;;{{{ Multiplication
+
+;; Signed multiplication producing 64-bit results from 32-bit inputs
+(define_insn "mulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "%r"))
+ (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))
+ (clobber (reg:CC 16))]
+ ""
+ "mul %2, %1\\n\\tmov\\tmdh, %0\\n\\tmov\\tmdl, %p0"
+ [(set_attr "length" "6")]
+)
+
+;; Unsigned multiplication producing 64-bit results from 32-bit inputs
+(define_insn "umulsidi3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "%r"))
+ (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))
+ (clobber (reg:CC 16))]
+ ""
+ "mulu %2, %1\\n\\tmov\\tmdh, %0\\n\\tmov\\tmdl, %p0"
+ [(set_attr "length" "6")]
+)
+
+;; Signed multiplication producing 32-bit result from 16-bit inputs
+(define_insn "mulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (sign_extend:SI (match_operand:HI 1 "register_operand" "%r"))
+ (sign_extend:SI (match_operand:HI 2 "register_operand" "r"))))
+ (clobber (reg:CC 16))]
+ ""
+ "mulh %2, %1\\n\\tmov\\tmdl, %0"
+ [(set_attr "length" "4")]
+)
+
+;; Unsigned multiplication producing 32-bit result from 16-bit inputs
+(define_insn "umulhisi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (zero_extend:SI (match_operand:HI 1 "register_operand" "%r"))
+ (zero_extend:SI (match_operand:HI 2 "register_operand" "r"))))
+ (clobber (reg:CC 16))]
+ ""
+ "muluh %2, %1\\n\\tmov\\tmdl, %0"
+ [(set_attr "length" "4")]
+)
+
+;; Signed multiplication producing 32-bit result from 32-bit inputs
+(define_insn "mulsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (mult:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "register_operand" "r")))
+ (clobber (reg:CC 16))]
+ ""
+ "mul %2, %1\\n\\tmov\\tmdl, %0"
+ [(set_attr "length" "4")]
+)
+
+;;}}}
+;;}}}
+;;{{{ Shifts
+
+;; Arithmetic Shift Left
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "0,0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,I,K")))
+ (clobber (reg:CC 16))]
+ ""
+ "@
+ lsl %2, %0
+ lsl %2, %0
+ lsl2 %x2, %0"
+)
+
+;; Arithmetic Shift Right
+(define_insn "ashrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,I,K")))
+ (clobber (reg:CC 16))]
+ ""
+ "@
+ asr %2, %0
+ asr %2, %0
+ asr2 %x2, %0"
+)
+
+;; Logical Shift Right
+(define_insn "lshrsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0,0,0")
+ (match_operand:SI 2 "nonmemory_operand" "r,I,K")))
+ (clobber (reg:CC 16))]
+ ""
+ "@
+ lsr %2, %0
+ lsr %2, %0
+ lsr2 %x2, %0"
+)
+
+;;}}}
+;;{{{ Logical Operations
+
+;; Logical AND, 32-bit integers
+(define_insn "andsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (and:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "register_operand" "0")))
+ (clobber (reg:CC 16))]
+ ""
+ "and %1, %0"
+)
+
+;; Inclusive OR, 32-bit integers
+(define_insn "iorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ior:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "register_operand" "0")))
+ (clobber (reg:CC 16))]
+ ""
+ "or %1, %0"
+)
+
+;; Exclusive OR, 32-bit integers
+(define_insn "xorsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (xor:SI (match_operand:SI 1 "register_operand" "%r")
+ (match_operand:SI 2 "register_operand" "0")))
+ (clobber (reg:CC 16))]
+ ""
+ "eor %1, %0"
+)
+
+;; One's complement, 32-bit integers
+(define_expand "one_cmplsi2"
+ [(set (match_operand:SI 0 "register_operand" "")
+ (not:SI (match_operand:SI 1 "register_operand" "")))]
+ ""
+ "{
+ if (rtx_equal_p (operands[0], operands[1]))
+ {
+ if (reload_in_progress || reload_completed)
+ {
+ rtx reg = gen_rtx_REG (SImode, 0/*COMPILER_SCRATCH_REGISTER*/);
+
+ emit_insn (gen_movsi (reg, constm1_rtx));
+ emit_insn (gen_xorsi3 (operands[0], operands[0], reg));
+ }
+ else
+ {
+ rtx reg = gen_reg_rtx (SImode);
+
+ emit_insn (gen_movsi (reg, constm1_rtx));
+ emit_insn (gen_xorsi3 (operands[0], operands[0], reg));
+ }
+ }
+ else
+ {
+ emit_insn (gen_movsi_internal (operands[0], constm1_rtx));
+ emit_insn (gen_xorsi3 (operands[0], operands[1], operands[0]));
+ }
+ DONE;
+ }"
+)
+
+;;}}}
+;;{{{ Comparisons
+
+;; The actual comparisons, generated by the cbranch and/or cstore expanders
+
+(define_insn "*cmpsi_internal"
+ [(set (reg:CC 16)
+ (compare:CC (match_operand:SI 0 "register_operand" "r,r,r")
+ (match_operand:SI 1 "nonmemory_operand" "r,I,J")))]
+ ""
+ "@
+ cmp %1, %0
+ cmp %1, %0
+ cmp2 %1, %0"
+)
+
+;;}}}
+;;{{{ Branches
+
+;; Define_expands called by the machine independent part of the compiler
+;; to allocate a new comparison register
+
+(define_expand "cbranchsi4"
+ [(set (reg:CC 16)
+ (compare:CC (match_operand:SI 1 "register_operand" "")
+ (match_operand:SI 2 "nonmemory_operand" "")))
+ (set (pc)
+ (if_then_else (match_operator:CC 0 "ordered_comparison_operator"
+ [(reg:CC 16) (const_int 0)])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))]
+ ""
+ ""
+)
+
+
+;; Actual branches. We must allow for the (label_ref) and the (pc) to be
+;; swapped. If they are swapped, it reverses the sense of the branch.
+
+;; This pattern matches the (branch-if-true) branches generated above.
+;; It generates two different instruction sequences depending upon how
+;; far away the destination is.
+
+;; The calculation for the instruction length is derived as follows:
+;; The branch instruction has a 9-bit signed displacement so we have
+;; this inequality for the displacement:
+;;
+;; -256 <= pc < 256
+;; or
+;; -256 + 256 <= pc + 256 < 256 + 256
+;; i.e.
+;; 0 <= pc + 256 < 512
+;;
+;; if we consider the displacement as an unsigned value, then negative
+;; displacements become very large positive displacements, and the
+;; inequality becomes:
+;;
+;; pc + 256 < 512
+;;
+;; In order to allow for the fact that the real branch instruction works
+;; from pc + 2, we increase the offset to 258.
+;;
+;; Note - we do not have to worry about whether the branch is delayed or
+;; not, as branch shortening happens after delay slot reorganization.
+
+(define_insn "*branch_true"
+ [(set (pc)
+ (if_then_else (match_operator:CC 0 "comparison_operator"
+ [(reg:CC 16)
+ (const_int 0)])
+ (label_ref (match_operand 1 "" ""))
+ (pc)))]
+ ""
+ "*
+ {
+ if (get_attr_length (insn) == 2)
+ return \"b%b0%#\\t%l1\";
+ else
+ {
+ static char buffer [100];
+ const char * tmp_reg;
+ const char * ldi_insn;
+
+ tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER];
+
+ ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\";
+
+ /* The code produced here is, for say the EQ case:
+
+ Bne 1f
+ LDI <label>, r0
+ JMP r0
+ 1: */
+
+ sprintf (buffer,
+ \"b%%B0\\t1f\\t;\\n\\t%s\\t%%l1, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\\n1:\",
+ ldi_insn, tmp_reg, tmp_reg);
+
+ return buffer;
+ }
+ }"
+ [(set (attr "length") (if_then_else
+ (ltu
+ (plus
+ (minus
+ (match_dup 1)
+ (pc))
+ (const_int 254))
+ (const_int 506))
+ (const_int 2)
+ (if_then_else (eq_attr "size" "small")
+ (const_int 8)
+ (const_int 10))))
+ (set_attr "delay_type" "delayed")]
+)
+
+
+;; This pattern is a duplicate of the previous one, except that the
+;; branch occurs if the test is false, so the %B operator is used.
+(define_insn "*branch_false"
+ [(set (pc)
+ (if_then_else (match_operator:CC 0 "comparison_operator"
+ [(reg:CC 16)
+ (const_int 0)])
+ (pc)
+ (label_ref (match_operand 1 "" ""))))]
+ ""
+ "*
+ {
+ if (get_attr_length (insn) == 2)
+ return \"b%B0%#\\t%l1 \";
+ else
+ {
+ static char buffer [100];
+ const char * tmp_reg;
+ const char * ldi_insn;
+
+ tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER];
+
+ ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\";
+
+ sprintf (buffer,
+ \"b%%b0\\t1f\\t;\\n\\t%s\\t%%l1, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\\n1:\",
+ ldi_insn, tmp_reg, tmp_reg);
+
+ return buffer;
+ }
+ }"
+ [(set (attr "length") (if_then_else (ltu (plus (minus (match_dup 1) (pc))
+ (const_int 254))
+ (const_int 506))
+ (const_int 2)
+ (if_then_else (eq_attr "size" "small")
+ (const_int 8)
+ (const_int 10))))
+ (set_attr "delay_type" "delayed")]
+)
+
+;;}}}
+;;{{{ Calls & Jumps
+
+;; Subroutine call instruction returning no value. Operand 0 is the function
+;; to call; operand 1 is the number of bytes of arguments pushed (in mode
+;; `SImode', except it is normally a `const_int'); operand 2 is the number of
+;; registers used as operands.
+
+(define_insn "call"
+ [(call (match_operand 0 "call_operand" "Qm")
+ (match_operand 1 "" "g"))
+ (clobber (reg:SI 17))]
+ ""
+ "call%#\\t%0"
+ [(set_attr "delay_type" "delayed")]
+)
+
+;; Subroutine call instruction returning a value. Operand 0 is the hard
+;; register in which the value is returned. There are three more operands, the
+;; same as the three operands of the `call' instruction (but with numbers
+;; increased by one).
+
+;; Subroutines that return `BLKmode' objects use the `call' insn.
+
+(define_insn "call_value"
+ [(set (match_operand 0 "register_operand" "=r")
+ (call (match_operand 1 "call_operand" "Qm")
+ (match_operand 2 "" "g")))
+ (clobber (reg:SI 17))]
+ ""
+ "call%#\\t%1"
+ [(set_attr "delay_type" "delayed")]
+)
+
+;; Normal unconditional jump.
+;; For a description of the computation of the length
+;; attribute see the branch patterns above.
+;;
+;; Although this instruction really clobbers r0, flow
+;; relies on jump being simplejump_p in several places
+;; and as r0 is fixed, this doesn't change anything
+(define_insn "jump"
+ [(set (pc) (label_ref (match_operand 0 "" "")))]
+ ""
+ "*
+ {
+ if (get_attr_length (insn) == 2)
+ return \"bra%#\\t%0\";
+ else
+ {
+ static char buffer [100];
+ const char * tmp_reg;
+ const char * ldi_insn;
+
+ tmp_reg = reg_names [COMPILER_SCRATCH_REGISTER];
+
+ ldi_insn = TARGET_SMALL_MODEL ? \"ldi:20\" : \"ldi:32\";
+
+ sprintf (buffer, \"%s\\t%%0, %s\\t;\\n\\tjmp%%#\\t@%s\\t;\",
+ ldi_insn, tmp_reg, tmp_reg);
+
+ return buffer;
+ }
+ }"
+ [(set (attr "length") (if_then_else (ltu (plus (minus (match_dup 0) (pc))
+ (const_int 254))
+ (const_int 506))
+ (const_int 2)
+ (if_then_else (eq_attr "size" "small")
+ (const_int 6)
+ (const_int 8))))
+ (set_attr "delay_type" "delayed")]
+)
+
+;; Indirect jump through a register
+(define_insn "indirect_jump"
+ [(set (pc) (match_operand:SI 0 "nonimmediate_operand" "r"))]
+ "GET_CODE (operands[0]) != MEM || GET_CODE (XEXP (operands[0], 0)) != PLUS"
+ "jmp%#\\t@%0"
+ [(set_attr "delay_type" "delayed")]
+)
+
+(define_insn "tablejump"
+ [(set (pc) (match_operand:SI 0 "register_operand" "r"))
+ (use (label_ref (match_operand 1 "" "")))]
+ ""
+ "jmp%#\\t@%0"
+ [(set_attr "delay_type" "delayed")]
+)
+
+;;}}}
+;;{{{ Function Prologues and Epilogues
+
+;; Called after register allocation to add any instructions needed for the
+;; prologue. Using a prologue insn is favored compared to putting all of the
+;; instructions in output_function_prologue(), since it allows the scheduler
+;; to intermix instructions with the saves of the caller saved registers. In
+;; some cases, it might be necessary to emit a barrier instruction as the last
+;; insn to prevent such scheduling.
+(define_expand "prologue"
+ [(clobber (const_int 0))]
+ ""
+ "{
+ fr30_expand_prologue ();
+ DONE;
+ }"
+)
+
+;; Called after register allocation to add any instructions needed for the
+;; epilogue. Using an epilogue insn is favored compared to putting all of the
+;; instructions in output_function_epilogue(), since it allows the scheduler
+;; to intermix instructions with the restores of the caller saved registers.
+;; In some cases, it might be necessary to emit a barrier instruction as the
+;; first insn to prevent such scheduling.
+(define_expand "epilogue"
+ [(return)]
+ ""
+ "{
+ fr30_expand_epilogue ();
+ DONE;
+ }"
+)
+
+(define_insn "return_from_func"
+ [(return)
+ (use (reg:SI 17))]
+ "reload_completed"
+ "ret%#"
+ [(set_attr "delay_type" "delayed")]
+)
+
+(define_insn "leave_func"
+ [(set (reg:SI 15) (plus:SI (reg:SI 14) (const_int 4)))
+ (set (reg:SI 14) (mem:SI (minus:SI (reg:SI 15) (const_int 4))))]
+ "reload_completed"
+ "leave"
+)
+
+(define_expand "enter_func"
+ [(parallel
+ [(set (mem:SI (minus:SI (match_dup 1)
+ (const_int 4)))
+ (match_dup 2))
+ (set (match_dup 2)
+ (minus:SI (match_dup 1)
+ (const_int 4)))
+ (set (match_dup 1)
+ (minus:SI (match_dup 1)
+ (match_operand:SI 0 "immediate_operand")))]
+ )]
+ ""
+{
+ operands[1] = stack_pointer_rtx;
+ operands[2] = hard_frame_pointer_rtx;
+})
+
+(define_insn "*enter_func"
+ [(set (mem:SI (minus:SI (reg:SI 15)
+ (const_int 4)))
+ (reg:SI 14))
+ (set (reg:SI 14)
+ (minus:SI (reg:SI 15)
+ (const_int 4)))
+ (set (reg:SI 15)
+ (minus:SI (reg:SI 15)
+ (match_operand 0 "immediate_operand" "i")))]
+ "reload_completed"
+ "enter #%0"
+ [(set_attr "delay_type" "other")]
+)
+
+;;}}}
+;;{{{ Miscellaneous
+
+;; No operation, needed in case the user uses -g but not -O.
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop"
+)
+
+;; Pseudo instruction that prevents the scheduler from moving code above this
+;; point.
+(define_insn "blockage"
+ [(unspec_volatile [(const_int 0)] 0)]
+ ""
+ ""
+ [(set_attr "length" "0")]
+)
+;;}}}
+
+;; Local Variables:
+;; mode: md
+;; folded-file: t
+;; End:
diff --git a/gcc/config/fr30/fr30.opt b/gcc/config/fr30/fr30.opt
new file mode 100644
index 000000000..da6148a6d
--- /dev/null
+++ b/gcc/config/fr30/fr30.opt
@@ -0,0 +1,27 @@
+; Options for the FR30 port of the compiler.
+
+; Copyright (C) 2005, 2007, 2009 Free Software Foundation, Inc.
+;
+; 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/>.
+
+msmall-model
+Target Report Mask(SMALL_MODEL)
+Assume small address space
+
+mno-lsim
+Target RejectNegative
+Assume that run-time support has been provided, so omit -lsim from the linker command line
diff --git a/gcc/config/fr30/lib1funcs.asm b/gcc/config/fr30/lib1funcs.asm
new file mode 100644
index 000000000..7c6345312
--- /dev/null
+++ b/gcc/config/fr30/lib1funcs.asm
@@ -0,0 +1,115 @@
+/* libgcc routines for the FR30.
+ Copyright (C) 1998, 1999, 2009 Free Software Foundation, Inc.
+
+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.
+
+This file 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.
+
+Under Section 7 of GPL version 3, you are granted additional
+permissions described in the GCC Runtime Library Exception, version
+3.1, as published by the Free Software Foundation.
+
+You should have received a copy of the GNU General Public License and
+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/>. */
+
+ .macro FUNC_START name
+ .text
+ .globl __\name
+ .type __\name, @function
+__\name:
+ .endm
+
+ .macro FUNC_END name
+ .size __\name, . - __\name
+ .endm
+
+ .macro DIV_BODY reg number
+ .if \number
+ DIV_BODY \reg, "\number - 1"
+ div1 \reg
+ .endif
+ .endm
+
+#ifdef L_udivsi3
+FUNC_START udivsi3
+ ;; Perform an unsiged division of r4 / r5 and place the result in r4.
+ ;; Does not handle overflow yet...
+ mov r4, mdl
+ div0u r5
+ DIV_BODY r5 32
+ mov mdl, r4
+ ret
+FUNC_END udivsi3
+#endif /* L_udivsi3 */
+
+#ifdef L_divsi3
+FUNC_START divsi3
+ ;; Perform a siged division of r4 / r5 and place the result in r4.
+ ;; Does not handle overflow yet...
+ mov r4, mdl
+ div0s r5
+ DIV_BODY r5 32
+ div2 r5
+ div3
+ div4s
+ mov mdl, r4
+ ret
+FUNC_END divsi3
+#endif /* L_divsi3 */
+
+#ifdef L_umodsi3
+FUNC_START umodsi3
+ ;; Perform an unsiged division of r4 / r5 and places the remainder in r4.
+ ;; Does not handle overflow yet...
+ mov r4, mdl
+ div0u r5
+ DIV_BODY r5 32
+ mov mdh, r4
+ ret
+FUNC_END umodsi3
+#endif /* L_umodsi3 */
+
+#ifdef L_modsi3
+FUNC_START modsi3
+ ;; Perform a siged division of r4 / r5 and place the remainder in r4.
+ ;; Does not handle overflow yet...
+ mov r4, mdl
+ div0s r5
+ DIV_BODY r5 32
+ div2 r5
+ div3
+ div4s
+ mov mdh, r4
+ ret
+FUNC_END modsi3
+#endif /* L_modsi3 */
+
+#ifdef L_negsi2
+FUNC_START negsi2
+ ldi:8 #0, r0
+ sub r4, r0
+ mov r0, r4
+ ret
+FUNC_END negsi2
+#endif /* L_negsi2 */
+
+#ifdef L_one_cmplsi2
+FUNC_START one_cmplsi2
+ ldi:8 #0xff, r0
+ extsb r0
+ eor r0, r4
+ ret
+FUNC_END one_cmplsi2
+#endif /* L_one_cmplsi2 */
+
+
diff --git a/gcc/config/fr30/predicates.md b/gcc/config/fr30/predicates.md
new file mode 100644
index 000000000..9467b287d
--- /dev/null
+++ b/gcc/config/fr30/predicates.md
@@ -0,0 +1,123 @@
+;; Predicate definitions for FR30.
+;; Copyright (C) 2005, 2007 Free Software Foundation, Inc.
+;;
+;; 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/>.
+
+;; Returns true if OP is an integer value suitable for use in an
+;; ADDSP instruction.
+
+(define_predicate "stack_add_operand"
+ (match_code "const_int")
+{
+ return
+ (GET_CODE (op) == CONST_INT
+ && INTVAL (op) >= -512
+ && INTVAL (op) <= 508
+ && ((INTVAL (op) & 3) == 0));
+})
+
+;; Returns true if OP is hard register in the range 8 - 15.
+
+(define_predicate "high_register_operand"
+ (match_code "reg")
+{
+ return
+ (GET_CODE (op) == REG
+ && REGNO (op) <= 15
+ && REGNO (op) >= 8);
+})
+
+;; Returns true if OP is hard register in the range 0 - 7.
+
+(define_predicate "low_register_operand"
+ (match_code "reg")
+{
+ return
+ (GET_CODE (op) == REG
+ && REGNO (op) <= 7);
+})
+
+;; Returns true if OP is suitable for use in a CALL insn.
+
+(define_predicate "call_operand"
+ (match_code "mem")
+{
+ return (GET_CODE (op) == MEM
+ && (GET_CODE (XEXP (op, 0)) == SYMBOL_REF
+ || GET_CODE (XEXP (op, 0)) == REG));
+})
+
+;; Returns TRUE if OP is a valid operand of a DImode operation.
+
+(define_predicate "di_operand"
+ (match_code "const_int,const_double,reg,mem")
+{
+ if (register_operand (op, mode))
+ return TRUE;
+
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
+ return FALSE;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ switch (GET_CODE (op))
+ {
+ case CONST_DOUBLE:
+ case CONST_INT:
+ return TRUE;
+
+ case MEM:
+ return memory_address_p (DImode, XEXP (op, 0));
+
+ default:
+ return FALSE;
+ }
+})
+
+;; Returns TRUE if OP is a DImode register or MEM.
+
+(define_predicate "nonimmediate_di_operand"
+ (match_code "reg,mem")
+{
+ if (register_operand (op, mode))
+ return TRUE;
+
+ if (mode != VOIDmode && GET_MODE (op) != VOIDmode && GET_MODE (op) != DImode)
+ return FALSE;
+
+ if (GET_CODE (op) == SUBREG)
+ op = SUBREG_REG (op);
+
+ if (GET_CODE (op) == MEM)
+ return memory_address_p (DImode, XEXP (op, 0));
+
+ return FALSE;
+})
+
+;; Returns true if OP is an integer value suitable for use in an ADD
+;; or ADD2 instruction, or if it is a register.
+
+(define_predicate "add_immediate_operand"
+ (match_code "reg,const_int")
+{
+ return
+ (GET_CODE (op) == REG
+ || (GET_CODE (op) == CONST_INT
+ && INTVAL (op) >= -16
+ && INTVAL (op) <= 15));
+})
diff --git a/gcc/config/fr30/t-fr30 b/gcc/config/fr30/t-fr30
new file mode 100644
index 000000000..027029223
--- /dev/null
+++ b/gcc/config/fr30/t-fr30
@@ -0,0 +1,56 @@
+# Copyright (C) 1999, 2001, 2007 Free Software Foundation, Inc.
+#
+# 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/>.
+
+LIB1ASMSRC = fr30/lib1funcs.asm
+LIB1ASMFUNCS = _udivsi3 _divsi3 _umodsi3 _modsi3
+
+# Assemble startup files.
+$(T)crti.o: $(srcdir)/config/fr30/crti.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o $(T)crti.o -x assembler $(srcdir)/config/fr30/crti.asm
+
+$(T)crtn.o: $(srcdir)/config/fr30/crtn.asm $(GCC_PASSES)
+ $(GCC_FOR_TARGET) -c -o $(T)crtn.o -x assembler $(srcdir)/config/fr30/crtn.asm
+
+# We want fine grained libraries, so use the new code to build the
+# floating point emulation libraries.
+FPBIT = fp-bit.c
+DPBIT = dp-bit.c
+
+# If any special flags are necessary when building libgcc2 put them here.
+#
+# TARGET_LIBGCC2_CFLAGS
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+ echo '#define FLOAT' > fp-bit.c
+ cat $(srcdir)/config/fp-bit.c >> fp-bit.c
+
+dp-bit.c: $(srcdir)/config/fp-bit.c
+ cat $(srcdir)/config/fp-bit.c > dp-bit.c
+
+# Enable the following if multilibs are needed.
+# See gcc/genmultilib, gcc/gcc.texi and gcc/tm.texi for a
+# description of the options and their values.
+#
+# MULTILIB_OPTIONS =
+# MULTILIB_DIRNAMES =
+# MULTILIB_MATCHES =
+# MULTILIB_EXCEPTIONS =
+# MULTILIB_EXTRA_OPTS =
+#
+# LIBGCC = stmp-multilib
+# INSTALL_LIBGCC = install-multilib