aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorSumanth G <sumanth.gundapaneni@kpitcummins.com>2012-02-02 10:20:32 +0000
committerJayant Sonar <jayants@gcc.gnu.org>2012-02-02 10:20:32 +0000
commitb25364a0b9e59bb9ef6d7d9740dfb750ec27f40d (patch)
tree6c6a242bece77442e5ca1c66403d5cee85d5584f /gcc
parent903e49f52065e9547a6e534d1bedbc980f77a5b1 (diff)
downloadgcc-b25364a0b9e59bb9ef6d7d9740dfb750ec27f40d.zip
gcc-b25364a0b9e59bb9ef6d7d9740dfb750ec27f40d.tar.gz
gcc-b25364a0b9e59bb9ef6d7d9740dfb750ec27f40d.tar.bz2
Adding GCC port for National Semicondutor's CR16 architecture
Co-Authored-By: Jayant R Sonar <jayant.sonar@kpitcummins.com> From-SVN: r183832
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog20
-rw-r--r--gcc/common/config/cr16/cr16-common.c37
-rw-r--r--gcc/config.gcc5
-rw-r--r--gcc/config/cr16/constraints.md81
-rw-r--r--gcc/config/cr16/cr16-protos.h101
-rw-r--r--gcc/config/cr16/cr16.c2190
-rw-r--r--gcc/config/cr16/cr16.h590
-rw-r--r--gcc/config/cr16/cr16.md1084
-rw-r--r--gcc/config/cr16/cr16.opt51
-rw-r--r--gcc/config/cr16/predicates.md225
-rw-r--r--gcc/config/cr16/t-cr1625
-rw-r--r--gcc/doc/extend.texi2
-rw-r--r--gcc/doc/install.texi23
-rw-r--r--gcc/doc/invoke.texi47
-rw-r--r--gcc/doc/md.texi34
15 files changed, 4514 insertions, 1 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 055e97e..c85aa65 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,23 @@
+2012-02-02 Sumanth G <sumanth.gundapaneni@kpitcummins.com>
+ Jayant R Sonar <jayant.sonar@kpitcummins.com>
+
+ * config.gcc: Add cr16-* support.
+
+ * doc/extend.texi: Document cr16 extensions.
+ * doc/install.texi: Document cr16 install.
+ * doc/invoke.texi: Document cr16 options.
+ * doc/md.texi: Document cr16 constraints.
+
+ * common/config/cr16/cr16-common.c: New file.
+ * config/cr16/cr16.c: New file.
+ * config/cr16/cr16.h: New file.
+ * config/cr16/cr16.md: New file.
+ * config/cr16/cr16.opt: New file.
+ * config/cr16/cr16-protos.h: New file.
+ * config/cr16/predicates.md: New file.
+ * config/cr16/constraints.md: New file.
+ * config/cr16/t-cr16: New file.
+
2012-02-02 Jakub Jelinek <jakub@redhat.com>
PR target/52086
diff --git a/gcc/common/config/cr16/cr16-common.c b/gcc/common/config/cr16/cr16-common.c
new file mode 100644
index 0000000..3baacec
--- /dev/null
+++ b/gcc/common/config/cr16/cr16-common.c
@@ -0,0 +1,37 @@
+/* Common hooks for CR16.
+ Copyright (C) 2012 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "common/common-target.h"
+#include "common/common-target-def.h"
+
+/* Implement TARGET_OPTION_OPTIMIZATION_TABLE. */
+static const struct default_options cr16_option_optimization_table[] =
+ {
+ { OPT_LEVELS_1_PLUS, OPT_fomit_frame_pointer, NULL, 1 },
+ { OPT_LEVELS_NONE, 0, NULL, 0 }
+ };
+
+#undef TARGET_OPTION_OPTIMIZATION_TABLE
+#define TARGET_OPTION_OPTIMIZATION_TABLE cr16_option_optimization_table
+
+struct gcc_targetm_common targetm_common = TARGETM_COMMON_INITIALIZER;
diff --git a/gcc/config.gcc b/gcc/config.gcc
index c82aaf5..65a423a 100644
--- a/gcc/config.gcc
+++ b/gcc/config.gcc
@@ -944,6 +944,11 @@ bfin*-*)
use_collect2=no
use_gcc_stdint=wrap
;;
+cr16-*-elf)
+ tm_file="elfos.h ${tm_file}"
+ tmake_file="${tmake_file} cr16/t-cr16 "
+ use_collect2=no
+ ;;
crisv32-*-elf | crisv32-*-none)
tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}"
tmake_file="cris/t-cris"
diff --git a/gcc/config/cr16/constraints.md b/gcc/config/cr16/constraints.md
new file mode 100644
index 0000000..0e6e112
--- /dev/null
+++ b/gcc/config/cr16/constraints.md
@@ -0,0 +1,81 @@
+;; Predicates of machine description for CR16.
+;; Copyright (C) 2012 Free Software Foundation, Inc.
+;; Contributed by KPIT Cummins Infosystems Limited.
+;;
+;; 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/>.
+
+;; Constraints
+;; Register constraints
+(define_register_constraint "b" "NOSP_REGS"
+ "@no sp registers")
+
+(define_register_constraint "c" "SHORT_REGS"
+ "@short registers")
+
+(define_register_constraint "d" "LONG_REGS"
+ "@long registers")
+
+;; Integer constraints.
+(define_constraint "I"
+ "A signed 4-bit immediate."
+ (and (match_code "const_int")
+ (match_test "SIGNED_INT_FITS_N_BITS (ival, 4)")))
+
+(define_constraint "J"
+ "A signed 5-bit immediate."
+ (and (match_code "const_int")
+ (match_test "SIGNED_INT_FITS_N_BITS (ival, 5)")))
+
+(define_constraint "K"
+ "A signed 6-bit immediate."
+ (and (match_code "const_int")
+ (match_test "SIGNED_INT_FITS_N_BITS (ival, 6)")))
+
+(define_constraint "L"
+ "A unsigned 4-bit immediate."
+ (and (match_code "const_int")
+ (match_test "UNSIGNED_INT_FITS_N_BITS (ival, 4)")))
+
+(define_constraint "M"
+ "A unsigned and customized 4-bit immediate."
+ (and (match_code "const_int")
+ (match_test "(IN_RANGE_P (ival, 0, 15) && ((ival != 9) && (ival != 11)))")))
+
+(define_constraint "N"
+ "A signed 16-bit immediate."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE_P (ival, -32768, 32767)")))
+
+(define_constraint "O"
+ "A unsigned 20-bit immediate."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE_P (ival, 0, 1048575)")))
+
+(define_constraint "Q"
+ "A shift QI immediate."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE_P (ival, 0, 7)")))
+
+(define_constraint "R"
+ "A shift HI immediate."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE_P (ival, 0, 15)")))
+
+(define_constraint "S"
+ "A shift SI immediate."
+ (and (match_code "const_int")
+ (match_test "IN_RANGE_P (ival, 0, 31)")))
diff --git a/gcc/config/cr16/cr16-protos.h b/gcc/config/cr16/cr16-protos.h
new file mode 100644
index 0000000..882fc61
--- /dev/null
+++ b/gcc/config/cr16/cr16-protos.h
@@ -0,0 +1,101 @@
+/* Prototypes for exported functions defined in cr16.c
+ Copyright (C) 2012 Free Software Foundation, Inc.
+ Contributed by KPIT Cummins Infosystems Limited.
+
+ 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/>. */
+
+#ifndef GCC_CR16_PROTOS_H
+#define GCC_CR16_PROTOS_H
+
+#include "target.h"
+
+/* Register usage. */
+extern enum reg_class cr16_regno_reg_class (int);
+extern int cr16_hard_regno_mode_ok (int regno, enum machine_mode);
+
+/* Passing function arguments. */
+extern int cr16_function_arg_regno_p (int);
+
+#ifdef TREE_CODE
+#ifdef RTX_CODE
+
+extern void cr16_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx);
+
+#endif /* RTX_CODE. */
+#endif /* TREE_CODE. */
+
+/* Enumeration giving the various data models we support. */
+enum data_model_type
+{
+ DM_DEFAULT, /* Default data model (in CR16C/C+ - up to 16M). */
+ DM_NEAR, /* Near data model (in CR16C/C+ - up to 1M). */
+ DM_FAR, /* Far data model (in CR16C+ - up to 4G)
+ (in CR16C - up to 16M). */
+ ILLEGAL_DM /* Illegal data model. */
+};
+
+#ifdef RTX_CODE
+
+/* Addressing Modes. */
+struct cr16_address
+{
+ rtx base; /* Base register: Any register or register pair. */
+ rtx index; /* Index register: If one is present. */
+ rtx disp; /* Displacement or Absolute address. */
+ enum data_model_type data; /* data ref type. */
+ int code; /* Whether the address is code address.
+ 0 - data, 1 - code label, 2 - function label. */
+};
+
+enum cr16_addrtype
+{
+ CR16_INVALID,
+ CR16_REG_REL,
+ CR16_REGP_REL,
+ CR16_INDEX_REGP_REL,
+ CR16_ABSOLUTE
+};
+
+extern void notice_update_cc PARAMS ((rtx));
+extern int cr16_operand_bit_pos (int val, int bitval);
+extern void cr16_decompose_const (rtx x, int *code,
+ enum data_model_type *data,
+ bool treat_as_const);
+extern enum cr16_addrtype cr16_decompose_address (rtx addr,
+ struct cr16_address *out,
+ bool debug_print,
+ bool treat_as_const);
+extern int cr16_const_double_ok (rtx op);
+extern int legitimate_pic_operand_p (rtx);
+extern rtx legitimize_pic_address (rtx, enum machine_mode, rtx);
+
+#endif /* RTX_CODE. */
+
+
+/* Prologue/Epilogue functions. */
+extern int cr16_initial_elimination_offset (int, int);
+extern char *cr16_prepare_push_pop_string (int);
+extern void cr16_expand_prologue (void);
+extern void cr16_expand_epilogue (void);
+extern const char *cr16_emit_add_sub_di (rtx *, enum rtx_code);
+extern const char *cr16_emit_logical_di (rtx *, enum rtx_code);
+
+/* Handling the "interrupt" attribute. */
+extern int cr16_interrupt_function_p (void);
+extern bool cr16_is_data_model (enum data_model_type);
+
+#endif /* Not GCC_CR16_PROTOS_H. */
diff --git a/gcc/config/cr16/cr16.c b/gcc/config/cr16/cr16.c
new file mode 100644
index 0000000..65968f8
--- /dev/null
+++ b/gcc/config/cr16/cr16.c
@@ -0,0 +1,2190 @@
+/* Output routines for CR16 processor.
+ Copyright (C) 2012 Free Software Foundation, Inc.
+ Contributed by KPIT Cummins Infosystems Limited.
+
+ 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/>. */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "rtl.h"
+#include "tree.h"
+#include "tm_p.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "output.h"
+#include "insn-codes.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "except.h"
+#include "function.h"
+#include "recog.h"
+#include "expr.h"
+#include "optabs.h"
+#include "diagnostic-core.h"
+#include "basic-block.h"
+#include "target.h"
+#include "target-def.h"
+#include "df.h"
+
+/* Definitions. */
+
+/* Maximum number of register used for passing parameters. */
+#define MAX_REG_FOR_PASSING_ARGS 6
+
+/* Minimum number register used for passing parameters. */
+#define MIN_REG_FOR_PASSING_ARGS 2
+
+/* The maximum count of words supported in the assembly of the architecture in
+ a push/pop instruction. */
+#define MAX_COUNT 8
+
+/* Predicate is true if the current function is a 'noreturn' function,
+ i.e. it is qualified as volatile. */
+#define FUNC_IS_NORETURN_P(decl) (TREE_THIS_VOLATILE (decl))
+
+/* Predicate that holds when we need to save registers even for 'noreturn'
+ functions, to accomodate for unwinding. */
+#define MUST_SAVE_REGS_P() \
+ (flag_unwind_tables || (flag_exceptions && !UI_SJLJ))
+
+/* Nonzero if the rtx X is a signed const int of n bits. */
+#define RTX_SIGNED_INT_FITS_N_BITS(X, n) \
+ ((GET_CODE (X) == CONST_INT \
+ && SIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0)
+
+/* Nonzero if the rtx X is an unsigned const int of n bits. */
+#define RTX_UNSIGNED_INT_FITS_N_BITS(X, n) \
+ ((GET_CODE (X) == CONST_INT \
+ && UNSIGNED_INT_FITS_N_BITS (INTVAL (X), n)) ? 1 : 0)
+
+/* Structure for stack computations. */
+
+/* variable definitions in the struture
+ args_size Number of bytes saved on the stack for local
+ variables
+
+ reg_size Number of bytes saved on the stack for
+ non-scratch registers
+
+ total_size The sum of 2 sizes: locals vars and padding byte
+ for saving the registers. Used in expand_prologue()
+ and expand_epilogue()
+
+ last_reg_to_save Will hold the number of the last register the
+ prologue saves, -1 if no register is saved
+
+ save_regs[16] Each object in the array is a register number.
+ Mark 1 for registers that need to be saved
+
+ num_regs Number of registers saved
+
+ initialized Non-zero if frame size already calculated, not
+ used yet
+
+ function_makes_calls Does the function make calls ? not used yet. */
+
+struct cr16_frame_info
+{
+ unsigned long var_size;
+ unsigned long args_size;
+ unsigned int reg_size;
+ unsigned long total_size;
+ long last_reg_to_save;
+ long save_regs[FIRST_PSEUDO_REGISTER];
+ int num_regs;
+ int initialized;
+ int function_makes_calls;
+};
+
+/* Current frame information calculated by cr16_compute_frame_size. */
+static struct cr16_frame_info current_frame_info;
+
+/* Static Variables. */
+
+/* Data model that was supplied by user via command line option
+ This will be overridden in case of invalid combination
+ of core and data model options are supplied. */
+static enum data_model_type data_model = DM_DEFAULT;
+
+/* TARGETM Function Prototypes and forward declarations */
+static void cr16_print_operand (FILE *, rtx, int);
+static void cr16_print_operand_address (FILE *, rtx);
+
+/* Stack layout and calling conventions. */
+#undef TARGET_STRUCT_VALUE_RTX
+#define TARGET_STRUCT_VALUE_RTX cr16_struct_value_rtx
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY cr16_return_in_memory
+
+/* Target-specific uses of '__attribute__'. */
+#undef TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE cr16_attribute_table
+#undef TARGET_NARROW_VOLATILE_BITFIELD
+#define TARGET_NARROW_VOLATILE_BITFIELD hook_bool_void_false
+
+/* EH related. */
+#undef TARGET_UNWIND_WORD_MODE
+#define TARGET_UNWIND_WORD_MODE cr16_unwind_word_mode
+
+/* Override Options. */
+#undef TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE cr16_override_options
+
+/* Conditional register usuage. */
+#undef TARGET_CONDITIONAL_REGISTER_USAGE
+#define TARGET_CONDITIONAL_REGISTER_USAGE cr16_conditional_register_usage
+
+/* Controlling register spills. */
+#undef TARGET_CLASS_LIKELY_SPILLED_P
+#define TARGET_CLASS_LIKELY_SPILLED_P cr16_class_likely_spilled_p
+
+/* Passing function arguments. */
+#undef TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG cr16_function_arg
+#undef TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE cr16_function_arg_advance
+#undef TARGET_RETURN_POPS_ARGS
+#define TARGET_RETURN_POPS_ARGS cr16_return_pops_args
+
+/* Initialize the GCC target structure. */
+#undef TARGET_FRAME_POINTER_REQUIRED
+#define TARGET_FRAME_POINTER_REQUIRED cr16_frame_pointer_required
+#undef TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE cr16_can_eliminate
+#undef TARGET_LEGITIMIZE_ADDRESS
+#define TARGET_LEGITIMIZE_ADDRESS cr16_legitimize_address
+#undef TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P cr16_legitimate_constant_p
+#undef TARGET_LEGITIMATE_ADDRESS_P
+#define TARGET_LEGITIMATE_ADDRESS_P cr16_legitimate_address_p
+
+/* Returning function value. */
+#undef TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE cr16_function_value
+#undef TARGET_LIBCALL_VALUE
+#define TARGET_LIBCALL_VALUE cr16_libcall_value
+#undef TARGET_FUNCTION_VALUE_REGNO_P
+#define TARGET_FUNCTION_VALUE_REGNO_P cr16_function_value_regno_p
+
+/* printing the values. */
+#undef TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND cr16_print_operand
+#undef TARGET_PRINT_OPERAND_ADDRESS
+#define TARGET_PRINT_OPERAND_ADDRESS cr16_print_operand_address
+
+/* Relative costs of operations. */
+#undef TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST cr16_address_cost
+#undef TARGET_REGISTER_MOVE_COST
+#define TARGET_REGISTER_MOVE_COST cr16_register_move_cost
+#undef TARGET_MEMORY_MOVE_COST
+#define TARGET_MEMORY_MOVE_COST cr16_memory_move_cost
+
+/* Table of machine attributes. */
+static const struct attribute_spec cr16_attribute_table[] = {
+ /* ISRs have special prologue and epilogue requirements. */
+ /* { name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+ affects_type_identity }. */
+ {"interrupt", 0, 0, false, true, true, NULL, false},
+ {NULL, 0, 0, false, false, false, NULL, false}
+};
+
+/* TARGET_ASM_UNALIGNED_xx_OP generates .?byte directive
+ .?byte directive along with @c is not understood by assembler.
+ Therefore, make all TARGET_ASM_UNALIGNED_xx_OP same
+ as TARGET_ASM_ALIGNED_xx_OP. */
+#undef TARGET_ASM_UNALIGNED_HI_OP
+#define TARGET_ASM_UNALIGNED_HI_OP TARGET_ASM_ALIGNED_HI_OP
+#undef TARGET_ASM_UNALIGNED_SI_OP
+#define TARGET_ASM_UNALIGNED_SI_OP TARGET_ASM_ALIGNED_SI_OP
+#undef TARGET_ASM_UNALIGNED_DI_OP
+#define TARGET_ASM_UNALIGNED_DI_OP TARGET_ASM_ALIGNED_DI_OP
+
+/* Target hook implementations. */
+
+/* Implements hook TARGET_RETURN_IN_MEMORY. */
+static bool
+cr16_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+ const HOST_WIDE_INT size = int_size_in_bytes (type);
+ return ((size == -1) || (size > 8));
+}
+
+/* Implement TARGET_CLASS_LIKELY_SPILLED_P. */
+static bool
+cr16_class_likely_spilled_p (reg_class_t rclass)
+{
+ if ((rclass) == SHORT_REGS || (rclass) == DOUBLE_BASE_REGS
+ || (rclass) == LONG_REGS || (rclass) == GENERAL_REGS)
+ return true;
+
+ return false;
+}
+
+static int
+cr16_return_pops_args (tree fundecl ATTRIBUTE_UNUSED,
+ tree funtype ATTRIBUTE_UNUSED,
+ int size ATTRIBUTE_UNUSED)
+{
+ return 0;
+}
+
+/* Returns true if data model selected via command line option
+ is same as function argument. */
+bool
+cr16_is_data_model (enum data_model_type model)
+{
+ return (model == data_model);
+}
+
+/* Parse relevant options and override. */
+static void
+cr16_override_options (void)
+{
+ /* Disable -fdelete-null-pointer-checks option for CR16 target.
+ Programs which rely on NULL pointer dereferences _not_ halting the
+ program may not work properly with this option. So disable this
+ option. */
+ flag_delete_null_pointer_checks = 0;
+
+ /* FIXME: To avoid spill_failure ICE during exception handling,
+ * disable cse_fllow_jumps. The spill error occurs when compiler
+ * can't find a suitable candidate in GENERAL_REGS class to reload
+ * a 32bit register.
+ * Need to find a better way of avoiding this situation. */
+ if (flag_exceptions)
+ flag_cse_follow_jumps = 0;
+
+ /* If -fpic option, data_model == DM_FAR. */
+ if (flag_pic == NEAR_PIC)
+ {
+ data_model = DM_FAR;
+ }
+
+ /* The only option we want to examine is data model option. */
+ if (cr16_data_model)
+ {
+ if (strcmp (cr16_data_model, "medium") == 0)
+ data_model = DM_DEFAULT;
+ else if (strcmp (cr16_data_model, "near") == 0)
+ data_model = DM_NEAR;
+ else if (strcmp (cr16_data_model, "far") == 0)
+ {
+ if (TARGET_CR16CP)
+ data_model = DM_FAR;
+ else
+ error ("data-model=far not valid for cr16c architecture");
+ }
+ else
+ error ("invalid data model option -mdata-model=%s", cr16_data_model);
+ }
+ else
+ data_model = DM_DEFAULT;
+}
+
+/* Implements the macro TARGET_CONDITIONAL_REGISTER_USAGE. */
+static void
+cr16_conditional_register_usage (void)
+{
+ if (flag_pic)
+ {
+ fixed_regs[12] = call_used_regs[12] = 1;
+ }
+}
+
+/* Stack layout and calling conventions routines. */
+
+/* Return nonzero if the current function being compiled is an interrupt
+ function as specified by the "interrupt" attribute. */
+int
+cr16_interrupt_function_p (void)
+{
+ tree attributes;
+
+ attributes = TYPE_ATTRIBUTES (TREE_TYPE (current_function_decl));
+ return (lookup_attribute ("interrupt", attributes) != NULL_TREE);
+}
+
+/* Compute values for the array current_frame_info.save_regs and the variable
+ current_frame_info.reg_size. The index of current_frame_info.save_regs
+ is numbers of register, each will get 1 if we need to save it in the
+ current function, 0 if not. current_frame_info.reg_size is the total sum
+ of the registers being saved. */
+static void
+cr16_compute_save_regs (void)
+{
+ unsigned int regno;
+
+ /* Initialize here so in case the function is no-return it will be -1. */
+ current_frame_info.last_reg_to_save = -1;
+
+ /* Initialize the number of bytes to be saved. */
+ current_frame_info.reg_size = 0;
+
+ /* No need to save any registers if the function never returns. */
+ if (FUNC_IS_NORETURN_P (current_function_decl) && !MUST_SAVE_REGS_P ())
+ return;
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ {
+ if (fixed_regs[regno])
+ {
+ current_frame_info.save_regs[regno] = 0;
+ continue;
+ }
+
+ /* If this reg is used and not call-used (except RA), save it. */
+ if (cr16_interrupt_function_p ())
+ {
+ if (!current_function_is_leaf && call_used_regs[regno])
+ /* This is a volatile reg in a non-leaf interrupt routine - save
+ it for the sake of its sons. */
+ current_frame_info.save_regs[regno] = 1;
+ else if (df_regs_ever_live_p (regno))
+ /* This reg is used - save it. */
+ current_frame_info.save_regs[regno] = 1;
+ else
+ /* This reg is not used, and is not a volatile - don't save. */
+ current_frame_info.save_regs[regno] = 0;
+ }
+ else
+ {
+ /* If this reg is used and not call-used (except RA), save it. */
+ if (df_regs_ever_live_p (regno)
+ && (!call_used_regs[regno] || regno == RETURN_ADDRESS_REGNUM))
+ current_frame_info.save_regs[regno] = 1;
+ else
+ current_frame_info.save_regs[regno] = 0;
+ }
+ }
+
+ /* Save registers so the exception handler can modify them. */
+ if (crtl->calls_eh_return)
+ {
+ unsigned int i;
+
+ for (i = 0;; ++i)
+ {
+ regno = EH_RETURN_DATA_REGNO (i);
+ if (INVALID_REGNUM == regno)
+ break;
+ current_frame_info.save_regs[regno] = 1;
+ }
+ }
+
+ for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+ if (current_frame_info.save_regs[regno] == 1)
+ {
+ current_frame_info.last_reg_to_save = regno;
+ if (regno >= CR16_FIRST_DWORD_REGISTER)
+ current_frame_info.reg_size += CR16_UNITS_PER_DWORD;
+ else
+ current_frame_info.reg_size += UNITS_PER_WORD;
+ }
+}
+
+/* Compute the size of the local area and the size to be adjusted by the
+ prologue and epilogue. */
+static void
+cr16_compute_frame (void)
+{
+ /* For aligning the local variables. */
+ int stack_alignment = STACK_BOUNDARY / BITS_PER_UNIT;
+ int padding_locals;
+
+ /* Padding needed for each element of the frame. */
+ current_frame_info.var_size = get_frame_size ();
+
+ /* Align to the stack alignment. */
+ padding_locals = current_frame_info.var_size % stack_alignment;
+ if (padding_locals)
+ padding_locals = stack_alignment - padding_locals;
+
+ current_frame_info.var_size += padding_locals;
+ current_frame_info.total_size = current_frame_info.var_size
+ + (ACCUMULATE_OUTGOING_ARGS
+ ? crtl->outgoing_args_size : 0);
+}
+
+/* Implements the macro INITIAL_ELIMINATION_OFFSET, return the OFFSET. */
+int
+cr16_initial_elimination_offset (int from, int to)
+{
+ /* Compute this since we need to use current_frame_info.reg_size. */
+ cr16_compute_save_regs ();
+
+ /* Compute this since we need to use current_frame_info.var_size. */
+ cr16_compute_frame ();
+
+ if (((from) == FRAME_POINTER_REGNUM) && ((to) == STACK_POINTER_REGNUM))
+ return (ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : 0);
+ else if (((from) == ARG_POINTER_REGNUM) && ((to) == FRAME_POINTER_REGNUM))
+ return (current_frame_info.reg_size + current_frame_info.var_size);
+ else if (((from) == ARG_POINTER_REGNUM) && ((to) == STACK_POINTER_REGNUM))
+ return (current_frame_info.reg_size + current_frame_info.var_size
+ + (ACCUMULATE_OUTGOING_ARGS ? crtl->outgoing_args_size : 0));
+ else
+ gcc_unreachable ();
+}
+
+/* Register Usage. */
+
+/* Return the class number of the smallest class containing reg number REGNO.
+ This could be a conditional expression or could index an array. */
+enum reg_class
+cr16_regno_reg_class (int regno)
+{
+ if ((regno >= 0) && (regno < CR16_FIRST_DWORD_REGISTER))
+ return SHORT_REGS;
+
+ if ((regno >= CR16_FIRST_DWORD_REGISTER) && (regno < FIRST_PSEUDO_REGISTER))
+ return LONG_REGS;
+
+ return NO_REGS;
+}
+
+/* Return 1 if hard register REGNO can hold a value of machine-mode MODE. */
+int
+cr16_hard_regno_mode_ok (int regno, enum machine_mode mode)
+{
+ if ((GET_MODE_SIZE (mode) >= 4) && (regno == 11))
+ return 0;
+
+ if (mode == DImode || mode == DFmode)
+ {
+ if ((regno > 8) || (regno & 1))
+ return 0;
+ return 1;
+ }
+
+ if ((TARGET_INT32)
+ && ((regno >= 12) && (GET_MODE_SIZE (mode) < 4 )))
+ return 0;
+
+ /* CC can only hold CCmode values. */
+ if (GET_MODE_CLASS (mode) == MODE_CC)
+ return 0;
+ return 1;
+}
+
+/* Returns register number for function return value.*/
+static inline unsigned int
+cr16_ret_register (void)
+{
+ return 0;
+}
+
+/* Implements hook TARGET_STRUCT_VALUE_RTX. */
+static rtx
+cr16_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
+ int incoming ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (Pmode, cr16_ret_register ());
+}
+
+/* Returning function value. */
+
+/* Worker function for TARGET_FUNCTION_VALUE_REGNO_P. */
+static bool
+cr16_function_value_regno_p (const unsigned int regno)
+{
+ return (regno == cr16_ret_register ());
+}
+
+/* Create an RTX representing the place where a
+ library function returns a value of mode MODE. */
+static rtx
+cr16_libcall_value (enum machine_mode mode,
+ const_rtx func ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (mode, cr16_ret_register ());
+}
+
+/* Create an RTX representing the place where a
+ function returns a value of data type VALTYPE. */
+static rtx
+cr16_function_value (const_tree type,
+ const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+ bool outgoing ATTRIBUTE_UNUSED)
+{
+ return gen_rtx_REG (TYPE_MODE (type), cr16_ret_register ());
+}
+
+/* Passing function arguments. */
+
+/* If enough param regs are available for passing the param of type TYPE return
+ the number of registers needed else 0. */
+static int
+enough_regs_for_param (CUMULATIVE_ARGS * cum, const_tree type,
+ enum machine_mode mode)
+{
+ int type_size;
+ int remaining_size;
+
+ if (mode != BLKmode)
+ type_size = GET_MODE_BITSIZE (mode);
+ else
+ type_size = int_size_in_bytes (type) * BITS_PER_UNIT;
+
+ remaining_size = BITS_PER_WORD * (MAX_REG_FOR_PASSING_ARGS
+ - (MIN_REG_FOR_PASSING_ARGS + cum->ints) +
+ 1);
+
+ /* Any variable which is too big to pass in two registers, will pass on
+ stack. */
+ if ((remaining_size >= type_size) && (type_size <= 2 * BITS_PER_WORD))
+ return (type_size + BITS_PER_WORD - 1) / BITS_PER_WORD;
+
+ return 0;
+}
+
+/* Implements the macro FUNCTION_ARG defined in cr16.h. */
+static rtx
+cr16_function_arg (cumulative_args_t cum_v, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+ CUMULATIVE_ARGS *cum = get_cumulative_args (cum_v);
+ cum->last_parm_in_reg = 0;
+
+ /* function_arg () is called with this type just after all the args have
+ had their registers assigned. The rtx that function_arg returns from
+ this type is supposed to pass to 'gen_call' but currently it is not
+ implemented (see macro GEN_CALL). */
+ if (type == void_type_node)
+ return NULL_RTX;
+
+ if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0))
+ return NULL_RTX;
+
+ if (mode == BLKmode)
+ {
+ /* Enable structures that need padding bytes at the end to pass to a
+ function in registers. */
+ if (enough_regs_for_param (cum, type, mode) != 0)
+ {
+ cum->last_parm_in_reg = 1;
+ return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints);
+ }
+ }
+
+ if ((MIN_REG_FOR_PASSING_ARGS + cum->ints) > MAX_REG_FOR_PASSING_ARGS)
+ return NULL_RTX;
+ else
+ {
+ if (enough_regs_for_param (cum, type, mode) != 0)
+ {
+ cum->last_parm_in_reg = 1;
+ return gen_rtx_REG (mode, MIN_REG_FOR_PASSING_ARGS + cum->ints);
+ }
+ }
+
+ return NULL_RTX;
+}
+
+/* Implements the macro INIT_CUMULATIVE_ARGS defined in cr16.h. */
+void
+cr16_init_cumulative_args (CUMULATIVE_ARGS * cum, tree fntype,
+ rtx libfunc ATTRIBUTE_UNUSED)
+{
+ tree param, next_param;
+
+ cum->ints = 0;
+
+ /* Determine if this function has variable arguments. This is indicated by
+ the last argument being 'void_type_mode' if there are no variable
+ arguments. Change here for a different vararg. */
+ for (param = (fntype) ? TYPE_ARG_TYPES (fntype) : 0;
+ param != NULL_TREE; param = next_param)
+ {
+ next_param = TREE_CHAIN (param);
+ if ((next_param == NULL_TREE) && (TREE_VALUE (param) != void_type_node))
+ {
+ cum->ints = -1;
+ return;
+ }
+ }
+}
+
+/* Implements the macro FUNCTION_ARG_ADVANCE defined in cr16.h. */
+static void
+cr16_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode,
+ const_tree type, bool named ATTRIBUTE_UNUSED)
+{
+ CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v);
+
+ /* l holds the number of registers required. */
+ int l = GET_MODE_BITSIZE (mode) / BITS_PER_WORD;
+
+ /* If the parameter isn't passed on a register don't advance cum. */
+ if (!cum->last_parm_in_reg)
+ return;
+
+ if (targetm.calls.must_pass_in_stack (mode, type) || (cum->ints < 0))
+ return;
+
+ if ((mode == SImode) || (mode == HImode)
+ || (mode == QImode) || (mode == DImode))
+ {
+ if (l <= 1)
+ cum->ints += 1;
+ else
+ cum->ints += l;
+ }
+ else if ((mode == SFmode) || (mode == DFmode))
+ cum->ints += l;
+ else if ((mode) == BLKmode)
+ {
+ if ((l = enough_regs_for_param (cum, type, mode)) != 0)
+ cum->ints += l;
+ }
+ return;
+}
+
+/* Implements the macro FUNCTION_ARG_REGNO_P defined in cr16.h.
+ Return nonzero if N is a register used for passing parameters. */
+int
+cr16_function_arg_regno_p (int n)
+{
+ return ((n <= MAX_REG_FOR_PASSING_ARGS) && (n >= MIN_REG_FOR_PASSING_ARGS));
+}
+
+/* Addressing modes.
+ Following set of function implement the macro GO_IF_LEGITIMATE_ADDRESS
+ defined in cr16.h. */
+
+/* Helper function to check if is a valid base register that can
+ hold address. */
+static int
+cr16_addr_reg_p (rtx addr_reg)
+{
+ rtx reg;
+
+ if (REG_P (addr_reg))
+ reg = addr_reg;
+ else if ((GET_CODE (addr_reg) == SUBREG)
+ && REG_P (SUBREG_REG (addr_reg))
+ && (GET_MODE_SIZE (GET_MODE (SUBREG_REG (addr_reg)))
+ <= UNITS_PER_WORD))
+ reg = SUBREG_REG (addr_reg);
+ else
+ return FALSE;
+
+ if (GET_MODE (reg) != Pmode)
+ return FALSE;
+
+ return TRUE;
+}
+
+/* Helper functions: Created specifically for decomposing operand of CONST
+ Recursively look into expression x for code or data symbol.
+ The function expects the expression to contain combination of
+ SYMBOL_REF, CONST_INT, (PLUS or MINUS)
+ LABEL_REF, CONST_INT, (PLUS or MINUS)
+ SYMBOL_REF
+ LABEL_REF
+ All other combinations will result in code = -1 and data = ILLEGAL_DM
+ code data
+ -1 ILLEGAL_DM The expression did not contain SYMBOL_REF or LABEL_REF
+ 0 DM_FAR SYMBOL_REF was found and it was far data reference.
+ 0 DM_DEFAULT SYMBOL_REF was found and it was medium data reference.
+ 1 ILLEGAL_DM LABEL_REF was found.
+ 2 ILLEGAL_DM SYMBOL_REF was found and it was function reference. */
+void
+cr16_decompose_const (rtx x, int *code, enum data_model_type *data,
+ bool treat_as_const)
+{
+ *code = -1;
+ *data = ILLEGAL_DM;
+ switch (GET_CODE (x))
+ {
+ case SYMBOL_REF:
+ *code = SYMBOL_REF_FUNCTION_P (x) ? 2 : 0;
+ /* 2 indicates func sym. */
+ if (*code == 0)
+ {
+ if (CR16_TARGET_DATA_NEAR)
+ *data = DM_DEFAULT;
+ else if (CR16_TARGET_DATA_MEDIUM)
+ *data = DM_FAR;
+ else if (CR16_TARGET_DATA_FAR)
+ {
+ if (treat_as_const)
+ /* This will be used only for printing
+ the qualifier. This call is (may be)
+ made by cr16_print_operand_address. */
+ *data = DM_FAR;
+ else
+ /* This call is (may be) made by
+ cr16_legitimate_address_p. */
+ *data = ILLEGAL_DM;
+ }
+ }
+ return;
+
+ case LABEL_REF:
+ /* 1 - indicates non-function symbol. */
+ *code = 1;
+ return;
+
+ case PLUS:
+ case MINUS:
+ /* Look into the tree nodes. */
+ if (GET_CODE (XEXP (x, 0)) == CONST_INT)
+ cr16_decompose_const (XEXP (x, 1), code, data, treat_as_const);
+ else if (GET_CODE (XEXP (x, 1)) == CONST_INT)
+ cr16_decompose_const (XEXP (x, 0), code, data, treat_as_const);
+ return;
+ default:
+ return;
+ }
+}
+
+/* Decompose Address
+ This function decomposes the address returns the type of address
+ as defined in enum cr16_addrtype. It also fills the parameter *out.
+ The decomposed address can be used for two purposes. One to
+ check if the address is valid and second to print the address
+ operand.
+
+ Following tables list valid address supported in CR16C/C+ architectures.
+ Legend:
+ aN : Absoulte address N-bit address
+ R : One 16-bit register
+ RP : Consecutive two 16-bit registers or one 32-bit register
+ I : One 32-bit register
+ dispN : Signed displacement of N-bits
+
+ ----Code addresses----
+ Branch operands:
+ disp9 : CR16_ABSOLUTE (disp)
+ disp17 : CR16_ABSOLUTE (disp)
+ disp25 : CR16_ABSOLUTE (disp)
+ RP + disp25 : CR16_REGP_REL (base, disp)
+
+ Jump operands:
+ RP : CR16_REGP_REL (base, disp=0)
+ a24 : CR16_ABSOLUTE (disp)
+
+ ----Data addresses----
+ a20 : CR16_ABSOLUTE (disp) near (1M)
+ a24 : CR16_ABSOLUTE (disp) medium (16M)
+ R + d20 : CR16_REG_REL (base, disp) near (1M+64K)
+ RP + d4 : CR16_REGP_REL (base, disp) far (4G)
+ RP + d16 : CR16_REGP_REL (base, disp) far (4G)
+ RP + d20 : CR16_REGP_REL (base, disp) far (4G)
+ I : *** Valid but port does not support this
+ I + a20 : *** Valid but port does not support this
+ I + RP + d14: CR16_INDEX_REGP_REL (base, index, disp) far (4G)
+ I + RP + d20: CR16_INDEX_REGP_REL (base, index, disp) far (4G)
+
+ Decomposing Data model in case of absolute address.
+
+ Target Option Address type Resultant Data ref type
+ ---------------------- ------------ -----------------------
+ CR16_TARGET_MODEL_NEAR ABS20 DM_DEFAULT
+ CR16_TARGET_MODEL_NEAR IMM20 DM_DEFAULT
+ CR16_TARGET_MODEL_NEAR ABS24 Invalid
+ CR16_TARGET_MODEL_NEAR IMM32 Invalid
+
+ CR16_TARGET_MODEL_MEDIUM ABS20 DM_DEFAULT
+ CR16_TARGET_MODEL_MEDIUM IMM20 DM_DEFAULT
+ CR16_TARGET_MODEL_MEDIUM ABS24 DM_FAR
+ CR16_TARGET_MODEL_MEDIUM IMM32 Invalid
+
+ CR16_TARGET_MODEL_FAR ABS20 DM_DEFAULT
+ CR16_TARGET_MODEL_FAR IMM20 DM_DEFAULT
+ CR16_TARGET_MODEL_FAR ABS24 DM_FAR
+ CR16_TARGET_MODEL_FAR IMM32 DM_FAR. */
+enum cr16_addrtype
+cr16_decompose_address (rtx addr, struct cr16_address *out,
+ bool debug_print, bool treat_as_const)
+{
+ rtx base = NULL_RTX, disp = NULL_RTX, index = NULL_RTX;
+ enum data_model_type data = ILLEGAL_DM;
+ int code = -1;
+ enum cr16_addrtype retval = CR16_INVALID;
+
+ switch (GET_CODE (addr))
+ {
+ case CONST_INT:
+ /* Absolute address (known at compile time). */
+ code = 0;
+ if (debug_print)
+ fprintf (stderr, "\ncode:%d", code);
+ disp = addr;
+
+ if (debug_print)
+ {
+ fprintf (stderr, "\ndisp:");
+ debug_rtx (disp);
+ }
+
+ if (UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), 20))
+ {
+ data = DM_DEFAULT;
+ if (debug_print)
+ fprintf (stderr, "\ndata:%d", data);
+ retval = CR16_ABSOLUTE;
+ }
+ else if (UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), 24))
+ {
+ if (!CR16_TARGET_DATA_NEAR)
+ {
+ data = DM_FAR;
+ if (debug_print)
+ fprintf (stderr, "\ndata:%d", data);
+ retval = CR16_ABSOLUTE;
+ }
+ else
+ return CR16_INVALID; /* ABS24 is not support in NEAR model. */
+ }
+ else
+ return CR16_INVALID;
+ break;
+
+ case CONST:
+ /* A CONST is an expression of PLUS or MINUS with
+ CONST_INT, SYMBOL_REF or LABEL_REF. This is the
+ result of assembly-time arithmetic computation. */
+ retval = CR16_ABSOLUTE;
+ disp = addr;
+ /* Call the helper function to check the validity. */
+ cr16_decompose_const (XEXP (addr, 0), &code, &data, treat_as_const);
+ if ((code == 0) && (data == ILLEGAL_DM))
+ /* CONST is not valid code or data address. */
+ return CR16_INVALID;
+ if (debug_print)
+ {
+ fprintf (stderr, "\ndisp:");
+ debug_rtx (disp);
+ fprintf (stderr, "\ncode:%d", code);
+ fprintf (stderr, "\ndata:%d", data);
+ }
+ break;
+
+ case LABEL_REF:
+ retval = CR16_ABSOLUTE;
+ disp = addr;
+ /* 1 - indicates non-function symbol. */
+ code = 1;
+ if (debug_print)
+ {
+ fprintf (stderr, "\ndisp:");
+ debug_rtx (disp);
+ fprintf (stderr, "\ncode:%d", code);
+ }
+ break;
+
+ case SYMBOL_REF:
+ /* Absolute address (known at link time). */
+ retval = CR16_ABSOLUTE;
+ disp = addr;
+ /* This is a code address if symbol_ref is a function. */
+ /* 2 indicates func sym. */
+ code = SYMBOL_REF_FUNCTION_P (addr) ? 2 : 0;
+ if (debug_print)
+ {
+ fprintf (stderr, "\ndisp:");
+ debug_rtx (disp);
+ fprintf (stderr, "\ncode:%d", code);
+ }
+ /* If not function ref then check if valid data ref. */
+ if (code == 0)
+ {
+ if (CR16_TARGET_DATA_NEAR)
+ data = DM_DEFAULT;
+ else if (CR16_TARGET_DATA_MEDIUM)
+ data = DM_FAR;
+ else if (CR16_TARGET_DATA_FAR)
+ {
+ if (treat_as_const)
+ /* This will be used only for printing the
+ qualifier. This call is (may be) made
+ by cr16_print_operand_address. */
+ data = DM_FAR;
+ else
+ /* This call is (may be) made by
+ cr16_legitimate_address_p. */
+ return CR16_INVALID;
+ }
+ else
+ data = DM_DEFAULT;
+ }
+ if (debug_print)
+ fprintf (stderr, "\ndata:%d", data);
+ break;
+
+ case REG:
+ case SUBREG:
+ /* Register relative address. */
+ /* Assume REG fits in a single register. */
+ retval = CR16_REG_REL;
+ if (GET_MODE_BITSIZE (GET_MODE (addr)) > BITS_PER_WORD)
+ if (!LONG_REG_P (REGNO (addr)))
+ /* REG will result in reg pair. */
+ retval = CR16_REGP_REL;
+ base = addr;
+ if (debug_print)
+ {
+ fprintf (stderr, "\nbase:");
+ debug_rtx (base);
+ }
+ break;
+
+ case PLUS:
+ switch (GET_CODE (XEXP (addr, 0)))
+ {
+ case REG:
+ case SUBREG:
+ /* REG + DISP20. */
+ /* All Reg relative addresses having a displacement needs
+ to fit in 20-bits. */
+ disp = XEXP (addr, 1);
+ if (debug_print)
+ {
+ fprintf (stderr, "\ndisp:");
+ debug_rtx (disp);
+ }
+ switch (GET_CODE (XEXP (addr, 1)))
+ {
+ case CONST_INT:
+ /* Shall fit in 20-bits. */
+ if (!UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), 20))
+ return CR16_INVALID;
+ code = 0;
+ if (debug_print)
+ fprintf (stderr, "\ncode:%d", code);
+ break;
+
+ case UNSPEC:
+ switch (XINT (XEXP (addr, 1), 1))
+ {
+ case UNSPEC_LIBRARY_OFFSET:
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ case LABEL_REF:
+ case SYMBOL_REF:
+ case CONST:
+ /* This is also a valid expression for address.
+ However, we cannot ascertain if the resultant
+ displacement will be valid 20-bit value. Therefore,
+ lets not allow such an expression for now. This will
+ be updated when we find a way to validate this
+ expression as legitimate address.
+ Till then fall through CR16_INVALID. */
+ default:
+ return CR16_INVALID;
+ }
+
+ /* Now check if REG can fit into single or pair regs. */
+ retval = CR16_REG_REL;
+ base = XEXP (addr, 0);
+ if (debug_print)
+ {
+ fprintf (stderr, "\nbase:");
+ debug_rtx (base);
+ }
+ if (GET_MODE_BITSIZE (GET_MODE ((XEXP (addr, 0)))) > BITS_PER_WORD)
+ {
+ if (!LONG_REG_P (REGNO ((XEXP (addr, 0)))))
+ /* REG will result in reg pair. */
+ retval = CR16_REGP_REL;
+ }
+ break;
+
+ case PLUS:
+ /* Valid expr:
+ plus
+ /\
+ / \
+ plus idx
+ /\
+ / \
+ reg const_int
+
+ Check if the operand 1 is valid index register. */
+ data = ILLEGAL_DM;
+ if (debug_print)
+ fprintf (stderr, "\ndata:%d", data);
+ switch (GET_CODE (XEXP (addr, 1)))
+ {
+ case REG:
+ case SUBREG:
+ if (!REG_OK_FOR_INDEX_P (XEXP (addr, 1)))
+ return CR16_INVALID;
+ /* OK. REG is a valid index register. */
+ index = XEXP (addr, 1);
+ if (debug_print)
+ {
+ fprintf (stderr, "\nindex:");
+ debug_rtx (index);
+ }
+ break;
+ default:
+ return CR16_INVALID;
+ }
+ /* Check if operand 0 of operand 0 is REGP. */
+ switch (GET_CODE (XEXP (XEXP (addr, 0), 0)))
+ {
+ case REG:
+ case SUBREG:
+ /* Now check if REG is a REGP and not in LONG regs. */
+ if (GET_MODE_BITSIZE (GET_MODE (XEXP (XEXP (addr, 0), 0)))
+ > BITS_PER_WORD)
+ {
+ if (REGNO (XEXP (XEXP (addr, 0), 0))
+ >= CR16_FIRST_DWORD_REGISTER)
+ return CR16_INVALID;
+ base = XEXP (XEXP (addr, 0), 0);
+ if (debug_print)
+ {
+ fprintf (stderr, "\nbase:");
+ debug_rtx (base);
+ }
+ }
+ else
+ return CR16_INVALID;
+ break;
+ default:
+ return CR16_INVALID;
+ }
+ /* Now check if the operand 1 of operand 0 is const_int. */
+ if (GET_CODE (XEXP (XEXP (addr, 0), 1)) == CONST_INT)
+ {
+ disp = XEXP (XEXP (addr, 0), 1);
+ if (debug_print)
+ {
+ fprintf (stderr, "\ndisp:");
+ debug_rtx (disp);
+ }
+ if (!UNSIGNED_INT_FITS_N_BITS (INTVAL (disp), 20))
+ return CR16_INVALID;
+ }
+ else
+ return CR16_INVALID;
+ retval = CR16_INDEX_REGP_REL;
+ break;
+ default:
+ return CR16_INVALID;
+ }
+ break;
+
+ default:
+ return CR16_INVALID;
+ }
+
+ /* Check if the base and index registers are valid. */
+ if (base && !(cr16_addr_reg_p (base)))
+ return CR16_INVALID;
+ if (base && !(CR16_REG_OK_FOR_BASE_P (base)))
+ return CR16_INVALID;
+ if (index && !(REG_OK_FOR_INDEX_P (index)))
+ return CR16_INVALID;
+
+ /* Write the decomposition to out parameter. */
+ out->base = base;
+ out->disp = disp;
+ out->index = index;
+ out->data = data;
+ out->code = code;
+
+ return retval;
+}
+
+/* Return non-zero value if 'x' is legitimate PIC operand
+ when generating PIC code. */
+int
+legitimate_pic_operand_p (rtx x)
+{
+ switch (GET_CODE (x))
+ {
+ case SYMBOL_REF:
+ return 0;
+ break;
+ case LABEL_REF:
+ return 0;
+ break;
+ case CONST:
+ /* REVISIT: Use something like symbol_referenced_p. */
+ if (GET_CODE (XEXP (x, 0)) == PLUS
+ && (GET_CODE (XEXP (XEXP (x, 0), 0)) == SYMBOL_REF
+ || GET_CODE (XEXP (XEXP (x, 0), 0)) == LABEL_REF)
+ && (GET_CODE (XEXP (XEXP (x, 0), 1)) == CONST_INT))
+ return 0;
+ break;
+ case MEM:
+ return legitimate_pic_operand_p (XEXP (x, 0));
+ break;
+ default:
+ break;
+ }
+ return 1;
+}
+
+/* Convert a non-PIC address in `orig' to a PIC address in `reg'.
+
+ Input Output (-f pic) Output (-f PIC)
+ orig reg
+
+ C1 symbol symbol@BRO (r12) symbol@GOT (r12)
+
+ C2 symbol + offset symbol+offset@BRO (r12) symbol+offset@GOT (r12)
+
+ NOTE: @BRO is added using unspec:BRO
+ NOTE: @GOT is added using unspec:GOT. */
+rtx
+legitimize_pic_address (rtx orig, enum machine_mode mode ATTRIBUTE_UNUSED,
+ rtx reg)
+{
+ /* First handle a simple SYMBOL_REF or LABEL_REF. */
+ if (GET_CODE (orig) == SYMBOL_REF || GET_CODE (orig) == LABEL_REF)
+ {
+ if (reg == 0)
+ reg = gen_reg_rtx (Pmode);
+
+ if (flag_pic == NEAR_PIC)
+ {
+ /* Unspec to handle -fpic option. */
+ emit_insn (gen_unspec_bro_addr (reg, orig));
+ emit_insn (gen_addsi3 (reg, reg, pic_offset_table_rtx));
+ }
+ else if (flag_pic == FAR_PIC)
+ {
+ /* Unspec to handle -fPIC option. */
+ emit_insn (gen_unspec_got_addr (reg, orig));
+ }
+ return reg;
+ }
+ else if (GET_CODE (orig) == CONST)
+ {
+ /* To handle (symbol + offset). */
+ rtx base, offset;
+
+ if (GET_CODE (XEXP (orig, 0)) == PLUS
+ && XEXP (XEXP (orig, 0), 0) == pic_offset_table_rtx)
+ return orig;
+
+ if (reg == 0)
+ {
+ gcc_assert (can_create_pseudo_p ());
+ reg = gen_reg_rtx (Pmode);
+ }
+
+ gcc_assert (GET_CODE (XEXP (orig, 0)) == PLUS);
+
+ base = legitimize_pic_address (XEXP (XEXP (orig, 0), 0), Pmode, reg);
+ offset = legitimize_pic_address (XEXP (XEXP (orig, 0), 1), Pmode,
+ base == reg ? 0 : reg);
+
+ /* REVISIT: Optimize for const-offsets. */
+ emit_insn (gen_addsi3 (reg, base, offset));
+
+ return reg;
+ }
+ return orig;
+}
+
+/* Implementation of TARGET_LEGITIMATE_ADDRESS_P. */
+static bool
+cr16_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+ rtx addr, bool strict)
+{
+ enum cr16_addrtype addrtype;
+ struct cr16_address address;
+
+ if (TARGET_DEBUG_ADDR)
+ {
+ fprintf (stderr,
+ "\n======\nTARGET_LEGITIMATE_ADDRESS_P, mode = %s, strict = %d",
+ GET_MODE_NAME (mode), strict);
+ debug_rtx (addr);
+ }
+ addrtype = cr16_decompose_address (addr, &address,
+ (TARGET_DEBUG_ADDR ? 1 : 0), FALSE);
+
+ if (TARGET_DEBUG_ADDR)
+ {
+ const char *typestr;
+
+ switch (addrtype)
+ {
+ case CR16_INVALID:
+ typestr = "invalid";
+ break;
+ case CR16_ABSOLUTE:
+ typestr = "absolute";
+ break;
+ case CR16_REG_REL:
+ typestr = "register relative";
+ break;
+ case CR16_REGP_REL:
+ typestr = "register pair relative";
+ break;
+ case CR16_INDEX_REGP_REL:
+ typestr = "index + register pair relative";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ fprintf (stderr, "\ncr16 address type: %s\n", typestr);
+ }
+
+ if (addrtype == CR16_INVALID)
+ return FALSE;
+
+ if (strict)
+ {
+ if (address.base
+ && !REGNO_MODE_OK_FOR_BASE_P (REGNO (address.base), mode))
+ {
+ if (TARGET_DEBUG_ADDR)
+ fprintf (stderr, "base register not strict\n");
+ return FALSE;
+ }
+ if (address.index && !REGNO_OK_FOR_INDEX_P (REGNO (address.index)))
+ {
+ if (TARGET_DEBUG_ADDR)
+ fprintf (stderr, "index register not strict\n");
+ return FALSE;
+ }
+ }
+
+ /* Return true if addressing mode is register relative. */
+ if (flag_pic)
+ {
+ if (addrtype == CR16_REG_REL || addrtype == CR16_REGP_REL)
+ return TRUE;
+ else
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/* Routines to compute costs. */
+
+/* Return cost of the memory address x. */
+static int
+cr16_address_cost (rtx addr, bool speed ATTRIBUTE_UNUSED)
+{
+ enum cr16_addrtype addrtype;
+ struct cr16_address address;
+ int cost = 2;
+
+ addrtype = cr16_decompose_address (addr, &address, 0, FALSE);
+
+ gcc_assert (addrtype != CR16_INVALID);
+
+ /* CR16_ABSOLUTE : 3
+ CR16_REG_REL (disp !=0) : 4
+ CR16_REG_REL (disp ==0) : 5
+ CR16_REGP_REL (disp !=0) : 6
+ CR16_REGP_REL (disp ==0) : 7
+ CR16_INDEX_REGP_REL (disp !=0) : 8
+ CR16_INDEX_REGP_REL (disp ==0) : 9. */
+ switch (addrtype)
+ {
+ case CR16_ABSOLUTE:
+ cost += 1;
+ break;
+ case CR16_REGP_REL:
+ cost += 2;
+ /* Fall through. */
+ case CR16_REG_REL:
+ cost += 3;
+ if (address.disp)
+ cost -= 1;
+ break;
+ case CR16_INDEX_REGP_REL:
+ cost += 7;
+ if (address.disp)
+ cost -= 1;
+ default:
+ break;
+ }
+
+ if (TARGET_DEBUG_ADDR)
+ {
+ fprintf (stderr, "\n======\nmacro TARGET_ADDRESS_COST = %d\n", cost);
+ debug_rtx (addr);
+ }
+
+ return cost;
+}
+
+
+/* Implement `TARGET_REGISTER_MOVE_COST'. */
+static int
+cr16_register_move_cost (enum machine_mode mode ATTRIBUTE_UNUSED,
+ reg_class_t from ATTRIBUTE_UNUSED, reg_class_t to)
+{
+ return (to != GENERAL_REGS ? 8 : 2);
+}
+
+/* Implement `TARGET_MEMORY_MOVE_COST'. */
+
+/* Return the cost of moving data of mode MODE between a register of class
+ CLASS and memory; IN is zero if the value is to be written to memory,
+ nonzero if it is to be read in. This cost is relative to those in
+ REGISTER_MOVE_COST. */
+static int
+cr16_memory_move_cost (enum machine_mode mode,
+ reg_class_t rclass ATTRIBUTE_UNUSED,
+ bool in ATTRIBUTE_UNUSED)
+{
+ /* One LD or ST takes twice the time of a simple reg-reg move. */
+ if (reg_classes_intersect_p (rclass, GENERAL_REGS))
+ return (4 * HARD_REGNO_NREGS (0, mode));
+ else
+ return (100);
+}
+
+/* Instruction output. */
+
+/* Check if a const_double is ok for cr16 store-immediate instructions. */
+int
+cr16_const_double_ok (rtx op)
+{
+ if (GET_MODE (op) == SFmode)
+ {
+ REAL_VALUE_TYPE r;
+ long l;
+ REAL_VALUE_FROM_CONST_DOUBLE (r, op);
+ REAL_VALUE_TO_TARGET_SINGLE (r, l);
+ return UNSIGNED_INT_FITS_N_BITS (l, 4) ? 1 : 0;
+ }
+
+ return ((UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_LOW (op), 4)) &&
+ (UNSIGNED_INT_FITS_N_BITS (CONST_DOUBLE_HIGH (op), 4))) ? 1 : 0;
+}
+
+/* Returns bit position of first 0 or 1 bit.
+ It is safe to assume val as 16-bit wide. */
+int
+cr16_operand_bit_pos (int val, int bitval)
+{
+ int i;
+ if (bitval == 0)
+ val = ~val;
+
+ for (i = 0; i < 16; i++)
+ if (val & (1 << i))
+ break;
+ return i;
+}
+
+/* Implements the macro PRINT_OPERAND defined in cr16.h. */
+static void
+cr16_print_operand (FILE * file, rtx x, int code)
+{
+ int ptr_dereference = 0;
+
+ switch (code)
+ {
+ case 'd':
+ {
+ const char *cr16_cmp_str;
+ switch (GET_CODE (x))
+ {
+ /* MD: compare (reg, reg or imm) but CR16: cmp (reg or imm, reg)
+ -> swap all non symmetric ops. */
+ case EQ:
+ cr16_cmp_str = "eq";
+ break;
+ case NE:
+ cr16_cmp_str = "ne";
+ break;
+ case GT:
+ cr16_cmp_str = "lt";
+ break;
+ case GTU:
+ cr16_cmp_str = "lo";
+ break;
+ case LT:
+ cr16_cmp_str = "gt";
+ break;
+ case LTU:
+ cr16_cmp_str = "hi";
+ break;
+ case GE:
+ cr16_cmp_str = "le";
+ break;
+ case GEU:
+ cr16_cmp_str = "ls";
+ break;
+ case LE:
+ cr16_cmp_str = "ge";
+ break;
+ case LEU:
+ cr16_cmp_str = "hs";
+ break;
+ default:
+ gcc_unreachable ();
+ }
+ fprintf (file, "%s", cr16_cmp_str);
+ return;
+ }
+ case '$':
+ putc ('$', file);
+ return;
+
+ case 'p':
+ if (GET_CODE (x) == REG)
+ {
+ /* For Push instructions, we should not print register pairs. */
+ fprintf (file, "%s", reg_names[REGNO (x)]);
+ return;
+ }
+ break;
+
+ case 'b':
+ /* Print the immediate address for bal
+ 'b' is used instead of 'a' to avoid compiler calling
+ the GO_IF_LEGITIMATE_ADDRESS which cannot
+ perform checks on const_int code addresses as it
+ assumes all const_int are data addresses. */
+ fprintf (file, "0x%lx", INTVAL (x));
+ return;
+
+ case 'r':
+ /* Print bit position of first 0. */
+ fprintf (file, "%d", cr16_operand_bit_pos (INTVAL (x), 0));
+ return;
+
+ case 's':
+ /* Print bit position of first 1. */
+ fprintf (file, "%d", cr16_operand_bit_pos (INTVAL (x), 1));
+ return;
+ case 'g':
+ /* 'g' is used for implicit mem: dereference. */
+ ptr_dereference = 1;
+ case 'f':
+ case 0:
+ /* default. */
+ switch (GET_CODE (x))
+ {
+ case REG:
+ if (GET_MODE_BITSIZE (GET_MODE (x)) > BITS_PER_WORD)
+ {
+ if (LONG_REG_P (REGNO (x)))
+ fprintf (file, "(%s)", reg_names[REGNO (x)]);
+ else
+ fprintf (file, "(%s,%s)", reg_names[REGNO (x) + 1],
+ reg_names[REGNO (x)]);
+ }
+ else
+ fprintf (file, "%s", reg_names[REGNO (x)]);
+ return;
+
+ case MEM:
+ output_address (XEXP (x, 0));
+ return;
+
+ case CONST_DOUBLE:
+ {
+ REAL_VALUE_TYPE r;
+ long l;
+
+ REAL_VALUE_FROM_CONST_DOUBLE (r, x);
+ REAL_VALUE_TO_TARGET_SINGLE (r, l);
+
+ fprintf (file, "$0x%lx", l);
+ return;
+ }
+ case CONST_INT:
+ {
+ fprintf (file, "$%ld", INTVAL (x));
+ return;
+ }
+ case UNSPEC:
+ switch (XINT (x, 1))
+ {
+ default:
+ gcc_unreachable ();
+ }
+ break;
+
+ default:
+ if (!ptr_dereference)
+ {
+ putc ('$', file);
+ }
+ cr16_print_operand_address (file, x);
+ return;
+ }
+ default:
+ output_operand_lossage ("invalid %%xn code");
+ }
+
+ gcc_unreachable ();
+}
+
+/* Implements the macro PRINT_OPERAND_ADDRESS defined in cr16.h. */
+
+static void
+cr16_print_operand_address (FILE * file, rtx addr)
+{
+ enum cr16_addrtype addrtype;
+ struct cr16_address address;
+
+ /* Decompose the address. Also ask it to treat address as constant. */
+ addrtype = cr16_decompose_address (addr, &address, 0, TRUE);
+
+ if (address.disp && GET_CODE (address.disp) == UNSPEC)
+ {
+ debug_rtx (addr);
+ }
+
+ switch (addrtype)
+ {
+ case CR16_REG_REL:
+ if (address.disp)
+ {
+ if (GET_CODE (address.disp) == UNSPEC)
+ cr16_print_operand (file, address.disp, 0);
+ else
+ output_addr_const (file, address.disp);
+ }
+ else
+ fprintf (file, "0");
+ fprintf (file, "(%s)", reg_names[REGNO (address.base)]);
+ break;
+
+ case CR16_ABSOLUTE:
+ if (address.disp)
+ output_addr_const (file, address.disp);
+ else
+ fprintf (file, "0");
+ break;
+
+ case CR16_INDEX_REGP_REL:
+ fprintf (file, "[%s]", reg_names[REGNO (address.index)]);
+ /* Fall through. */
+ case CR16_REGP_REL:
+ if (address.disp)
+ {
+ if (GET_CODE (address.disp) == UNSPEC)
+ cr16_print_operand (file, address.disp, 0);
+ else
+ output_addr_const (file, address.disp);
+ }
+ else
+ fprintf (file, "0");
+ fprintf (file, "(%s,%s)", reg_names[REGNO (address.base) + 1],
+ reg_names[REGNO (address.base)]);
+ break;
+ default:
+ debug_rtx (addr);
+ gcc_unreachable ();
+ }
+ /* Add qualifiers to the address expression that was just printed. */
+ if (flag_pic < NEAR_PIC && address.code == 0)
+ {
+ if (address.data == DM_FAR)
+ /* Addr contains SYMBOL_REF & far data ptr. */
+ fprintf (file, "@l");
+ else if (address.data == DM_DEFAULT)
+ /* Addr contains SYMBOL_REF & medium data ptr. */
+ fprintf (file, "@m");
+ /* Addr contains SYMBOL_REF & medium data ptr. */
+ else if (address.data == DM_NEAR)
+ /* Addr contains SYMBOL_REF & near data ptr. */
+ fprintf (file, "@s");
+ }
+ else if (flag_pic == NEAR_PIC
+ && (address.code == 0) && (address.data == DM_FAR
+ || address.data == DM_DEFAULT
+ || address.data == DM_NEAR))
+ {
+ fprintf (file, "@l");
+ }
+ else if (flag_pic == NEAR_PIC && address.code == 2)
+ {
+ fprintf (file, "pic");
+ }
+ else if (flag_pic == NEAR_PIC && address.code == 1)
+ {
+ fprintf (file, "@cpic");
+ }
+
+ else if (flag_pic == FAR_PIC && address.code == 2)
+ {
+ /* REVISIT: cr16 register indirect jump expects a 1-bit right shifted
+ address ! GOTc tells assembler this symbol is a text-address
+ This needs to be fixed in such a way that this offset is done
+ only in the case where an address is being used for indirect jump
+ or call. Determining the potential usage of loadd is of course not
+ possible always. Eventually, this has to be fixed in the
+ processor. */
+ fprintf (file, "GOT (%s)", reg_names[PIC_OFFSET_TABLE_REGNUM]);
+ }
+ else if (flag_pic == FAR_PIC && address.code == 1)
+ {
+ fprintf (file, "@cGOT (%s)", reg_names[PIC_OFFSET_TABLE_REGNUM]);
+ }
+
+ else if (flag_pic == FAR_PIC &&
+ (address.data == DM_FAR || address.data == DM_DEFAULT
+ || address.data == DM_NEAR))
+ {
+ fprintf (file, "@GOT (%s)", reg_names[PIC_OFFSET_TABLE_REGNUM]);
+ }
+}
+
+/* Machine description helper functions. */
+
+/* Called from cr16.md. The return value depends on the parameter push_or_pop:
+ When push_or_pop is zero -> string for push instructions of prologue.
+ When push_or_pop is nonzero -> string for pop/popret/retx in epilogue.
+ Relies on the assumptions:
+ 1. RA is the last register to be saved.
+ 2. The maximal value of the counter is MAX_COUNT. */
+char *
+cr16_prepare_push_pop_string (int push_or_pop)
+{
+ /* j is the number of registers being saved, takes care that there won't be
+ more than 8 in one push/pop instruction. */
+
+ /* For the register mask string. */
+ static char one_inst_str[50];
+
+ /* i is the index of current_frame_info.save_regs[], going from 0 until
+ current_frame_info.last_reg_to_save. */
+ int i, start_reg;
+ int word_cnt;
+ int print_ra;
+ char *return_str;
+
+ /* For reversing on the push instructions if there are more than one. */
+ char *temp_str;
+
+ return_str = (char *) xmalloc (160);
+ temp_str = (char *) xmalloc (160);
+
+ /* Initialize. */
+ memset (return_str, 0, 3);
+
+ i = 0;
+ while (i <= current_frame_info.last_reg_to_save)
+ {
+ /* Prepare mask for one instruction. */
+ one_inst_str[0] = 0;
+
+ /* To count number of words in one instruction. */
+ word_cnt = 0;
+ start_reg = i;
+ print_ra = 0;
+ while ((word_cnt < MAX_COUNT)
+ && (i <= current_frame_info.last_reg_to_save))
+ {
+ /* For each non consecutive save register,
+ a new instruction shall be generated. */
+ if (!current_frame_info.save_regs[i])
+ {
+ /* Move to next reg and break. */
+ ++i;
+ break;
+ }
+
+ if (i == RETURN_ADDRESS_REGNUM)
+ print_ra = 1;
+ else
+ {
+ /* Check especially if adding 2 does not cross the MAX_COUNT. */
+ if ((word_cnt + ((i < CR16_FIRST_DWORD_REGISTER) ? 1 : 2))
+ >= MAX_COUNT)
+ break;
+ /* Increase word count by 2 for long registers except RA. */
+ word_cnt += ((i < CR16_FIRST_DWORD_REGISTER) ? 1 : 2);
+ }
+ ++i;
+ }
+
+ /* No need to generate any instruction as
+ no register or RA needs to be saved. */
+ if ((word_cnt == 0) && (print_ra == 0))
+ continue;
+
+ /* Now prepare the instruction operands. */
+ if (word_cnt > 0)
+ {
+ sprintf (one_inst_str, "$%d, %s", word_cnt, reg_names[start_reg]);
+ if (print_ra)
+ strcat (one_inst_str, ", ra");
+ }
+ else
+ strcat (one_inst_str, "ra");
+
+ if (push_or_pop == 1)
+ {
+ /* Pop instruction. */
+ if (print_ra && !cr16_interrupt_function_p ()
+ && !crtl->calls_eh_return)
+ /* Print popret if RA is saved and its not a interrupt
+ function. */
+ strcpy (temp_str, "\n\tpopret\t");
+ else
+ strcpy (temp_str, "\n\tpop\t");
+
+ strcat (temp_str, one_inst_str);
+
+ /* Add the pop instruction list. */
+ strcat (return_str, temp_str);
+ }
+ else
+ {
+ /* Push instruction. */
+ strcpy (temp_str, "\n\tpush\t");
+ strcat (temp_str, one_inst_str);
+
+ /* We need to reverse the order of the instructions if there
+ are more than one. (since the pop will not be reversed in
+ the epilogue. */
+ strcat (temp_str, return_str);
+ strcpy (return_str, temp_str);
+ }
+ }
+
+ if (push_or_pop == 1)
+ {
+ /* POP. */
+ if (cr16_interrupt_function_p ())
+ strcat (return_str, "\n\tretx\n");
+ else if (crtl->calls_eh_return)
+ {
+ /* Add stack adjustment before returning to exception handler
+ NOTE: EH_RETURN_STACKADJ_RTX must refer to (r5, r4). */
+ strcat (return_str, "\n\taddd\t (r5, r4), (sp)\t\n");
+ strcat (return_str, "\n\tjump\t (ra)\n");
+
+ /* But before anything else, undo the adjustment addition done in
+ cr16_expand_epilogue (). */
+ strcpy (temp_str, "\n\tsubd\t (r5, r4), (sp)\t\n");
+ strcat (temp_str, return_str);
+ strcpy (return_str, temp_str);
+ }
+ else if (!FUNC_IS_NORETURN_P (current_function_decl)
+ && !(current_frame_info.save_regs[RETURN_ADDRESS_REGNUM]))
+ strcat (return_str, "\n\tjump\t (ra)\n");
+ }
+
+ /* Skip the newline and the tab in the start of return_str. */
+ return_str += 2;
+ return return_str;
+}
+
+
+/* Generate DWARF2 annotation for multi-push instruction. */
+static void
+cr16_create_dwarf_for_multi_push (rtx insn)
+{
+ rtx dwarf, reg, tmp;
+ int i, j, from, to, word_cnt, dwarf_par_index, inc;
+ enum machine_mode mode;
+ int num_regs = 0, offset = 0, split_here = 0, total_push_bytes = 0;
+
+ for (i = 0; i <= current_frame_info.last_reg_to_save; ++i)
+ {
+ if (current_frame_info.save_regs[i])
+ {
+ ++num_regs;
+ if (i < CR16_FIRST_DWORD_REGISTER)
+ total_push_bytes += 2;
+ else
+ total_push_bytes += 4;
+ }
+ }
+
+ if (!num_regs)
+ return;
+
+ dwarf = gen_rtx_SEQUENCE (VOIDmode, rtvec_alloc (num_regs + 1));
+ dwarf_par_index = num_regs;
+
+ from = current_frame_info.last_reg_to_save + 1;
+ to = current_frame_info.last_reg_to_save;
+ word_cnt = 0;
+
+ for (i = current_frame_info.last_reg_to_save; i >= 0;)
+ {
+ if (!current_frame_info.save_regs[i] || 0 == i || split_here)
+ {
+ /* This block of regs is pushed in one instruction. */
+ if (0 == i && current_frame_info.save_regs[i])
+ from = 0;
+
+ for (j = to; j >= from; --j)
+ {
+ if (j < CR16_FIRST_DWORD_REGISTER)
+ {
+ mode = HImode;
+ inc = 1;
+ }
+ else
+ {
+ mode = SImode;
+ inc = 2;
+ }
+ reg = gen_rtx_REG (mode, j);
+ offset += 2 * inc;
+ tmp = gen_rtx_SET (VOIDmode,
+ gen_frame_mem (mode,
+ plus_constant
+ (stack_pointer_rtx,
+ total_push_bytes - offset)),
+ reg);
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (dwarf, 0, dwarf_par_index--) = tmp;
+ }
+ from = i;
+ to = --i;
+ split_here = 0;
+ word_cnt = 0;
+ continue;
+ }
+
+ if (i != RETURN_ADDRESS_REGNUM)
+ {
+ inc = (i < CR16_FIRST_DWORD_REGISTER) ? 1 : 2;
+ if (word_cnt + inc >= MAX_COUNT || FRAME_POINTER_REGNUM == i)
+ {
+ split_here = 1;
+ from = i;
+ continue;
+ }
+ word_cnt += inc;
+ }
+
+ from = i--;
+ }
+
+ tmp = gen_rtx_SET (SImode, stack_pointer_rtx,
+ gen_rtx_PLUS (SImode, stack_pointer_rtx,
+ GEN_INT (-offset)));
+ RTX_FRAME_RELATED_P (tmp) = 1;
+ XVECEXP (dwarf, 0, 0) = tmp;
+
+ add_reg_note (insn, REG_FRAME_RELATED_EXPR, dwarf);
+}
+
+/*
+CompactRISC CR16 Architecture stack layout:
+
+ 0 +---------------------
+ |
+ .
+ .
+ |
+ +==================== Sp (x) = Ap (x+1)
+ A | Args for functions
+ | | called by X and Dynamically
+ | | Dynamic allocations allocated and
+ | | (alloca, variable deallocated
+ Stack | length arrays).
+ grows +-------------------- Fp (x)
+ down| | Local variables of X
+ ward| +--------------------
+ | | Regs saved for X-1
+ | +==================== Sp (x-1) = Ap (x)
+ | Args for func X
+ | pushed by X-1
+ +-------------------- Fp (x-1)
+ |
+ |
+ V
+*/
+void
+cr16_expand_prologue (void)
+{
+ rtx insn;
+
+ cr16_compute_frame ();
+ cr16_compute_save_regs ();
+
+ /* If there is no need in push and adjustment to sp, return. */
+ if ((current_frame_info.total_size + current_frame_info.reg_size) == 0)
+ return;
+
+ if (current_frame_info.last_reg_to_save != -1)
+ {
+ /* If there are registers to push. */
+ insn = emit_insn (gen_push_for_prologue
+ (GEN_INT (current_frame_info.reg_size)));
+ cr16_create_dwarf_for_multi_push (insn);
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+
+ if (current_frame_info.total_size > 0)
+ {
+ insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (-current_frame_info.total_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ if (frame_pointer_needed)
+ {
+ /* Initialize the frame pointer with the value of the stack pointer
+ pointing now to the locals. */
+ insn = emit_move_insn (frame_pointer_rtx, stack_pointer_rtx);
+ }
+}
+
+/* Generate insn that updates the stack for local variables and padding
+ for registers we save. - Generate the appropriate return insn. */
+void
+cr16_expand_epilogue (void)
+{
+ rtx insn;
+
+ /* Nonzero if we need to return and pop only RA. This will generate a
+ different insn. This differentiate is for the peepholes for call as
+ last statement in function. */
+ int only_popret_RA = (current_frame_info.save_regs[RETURN_ADDRESS_REGNUM]
+ && (current_frame_info.reg_size
+ == CR16_UNITS_PER_DWORD));
+
+ if (frame_pointer_needed)
+ {
+ /* Restore the stack pointer with the frame pointers value. */
+ insn = emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+ }
+
+ if (current_frame_info.total_size > 0)
+ {
+ insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ GEN_INT (current_frame_info.total_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+
+ if (crtl->calls_eh_return)
+ {
+ /* Add this here so that (r5, r4) is actually loaded with the adjustment
+ value; otherwise, the load might be optimized away...
+ NOTE: remember to subtract the adjustment before popping the regs
+ and add it back before returning. */
+ insn = emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+ EH_RETURN_STACKADJ_RTX));
+ }
+
+ if (cr16_interrupt_function_p ())
+ {
+ insn = emit_jump_insn (gen_interrupt_return ());
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else if (crtl->calls_eh_return)
+ {
+ /* Special case, pop what's necessary, adjust SP and jump to (RA). */
+ insn = emit_jump_insn (gen_pop_and_popret_return
+ (GEN_INT (current_frame_info.reg_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else if (current_frame_info.last_reg_to_save == -1)
+ /* Nothing to pop. */
+ /* Don't output jump for interrupt routine, only retx. */
+ emit_jump_insn (gen_jump_return ());
+ else if (only_popret_RA)
+ {
+ insn = emit_jump_insn (gen_popret_RA_return ());
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+ else
+ {
+ insn = emit_jump_insn (gen_pop_and_popret_return
+ (GEN_INT (current_frame_info.reg_size)));
+ RTX_FRAME_RELATED_P (insn) = 1;
+ }
+}
+
+/* Implements FRAME_POINTER_REQUIRED. */
+static bool
+cr16_frame_pointer_required (void)
+{
+ return (cfun->calls_alloca || crtl->calls_eh_return
+ || cfun->has_nonlocal_label || crtl->calls_eh_return);
+}
+
+static bool
+cr16_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to)
+{
+ return (to == STACK_POINTER_REGNUM ? !frame_pointer_needed : true);
+}
+
+
+/* A C compound statement that attempts to replace X with
+ a valid memory address for an operand of mode MODE. WIN
+ will be a C statement label elsewhere in the code.
+ X will always be the result of a call to break_out_memory_refs (),
+ and OLDX will be the operand that was given to that function to
+ produce X.
+ The code generated by this macro should not alter the
+ substructure of X. If it transforms X into a more legitimate form,
+ it should assign X (which will always be a C variable) a new value. */
+static rtx
+cr16_legitimize_address (rtx x, rtx orig_x ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED)
+{
+ if (flag_pic)
+ return legitimize_pic_address (orig_x, mode, NULL_RTX);
+ else
+ return x;
+}
+
+/* Implement TARGET_LEGITIMATE_CONSTANT_P
+ Nonzero if X is a legitimate constant for an immediate
+ operand on the target machine. You can assume that X
+ satisfies CONSTANT_P. In cr16c treat legitimize float
+ constant as an immediate operand. */
+static bool
+cr16_legitimate_constant_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+ rtx x ATTRIBUTE_UNUSED)
+{
+ return 1;
+}
+
+void
+notice_update_cc (rtx exp)
+{
+ if (GET_CODE (exp) == SET)
+ {
+ /* Jumps do not alter the cc's. */
+ if (SET_DEST (exp) == pc_rtx)
+ return;
+
+ /* Moving register or memory into a register:
+ it doesn't alter the cc's, but it might invalidate
+ the RTX's which we remember the cc's came from.
+ (Note that moving a constant 0 or 1 MAY set the cc's). */
+ if (REG_P (SET_DEST (exp))
+ && (REG_P (SET_SRC (exp)) || GET_CODE (SET_SRC (exp)) == MEM))
+ {
+ return;
+ }
+
+ /* Moving register into memory doesn't alter the cc's.
+ It may invalidate the RTX's which we remember the cc's came from. */
+ if (GET_CODE (SET_DEST (exp)) == MEM && REG_P (SET_SRC (exp)))
+ {
+ return;
+ }
+ }
+
+ CC_STATUS_INIT;
+ return;
+}
+
+static enum machine_mode
+cr16_unwind_word_mode (void)
+{
+ return SImode;
+}
+
+/* Helper function for md file. This function is used to emit arithmetic
+ DI instructions. The argument "num" decides which instruction to be
+ printed. */
+const char *
+cr16_emit_add_sub_di (rtx *operands, enum rtx_code code)
+{
+ rtx lo_op[2] ;
+ rtx hi0_op[2] ;
+ rtx hi1_op[2] ;
+
+ lo_op[0] = gen_lowpart (SImode, operands[0]);
+ hi0_op[0] = simplify_gen_subreg (HImode, operands[0], DImode, 4);
+ hi1_op[0] = simplify_gen_subreg (HImode, operands[0], DImode, 6);
+
+ lo_op[1] = gen_lowpart (SImode, operands[2]);
+ hi0_op[1] = simplify_gen_subreg (HImode, operands[2], DImode, 4);
+ hi1_op[1] = simplify_gen_subreg (HImode, operands[2], DImode, 6);
+
+ switch (code)
+ {
+ case PLUS:
+ {
+ output_asm_insn ("addd\t%1, %0", lo_op) ;
+ output_asm_insn ("addcw\t%1, %0", hi0_op) ;
+ output_asm_insn ("addcw\t%1, %0", hi1_op) ;
+ break;
+ }
+ case MINUS:
+ {
+ output_asm_insn ("subd\t%1, %0", lo_op) ;
+ output_asm_insn ("subcw\t%1, %0", hi0_op) ;
+ output_asm_insn ("subcw\t%1, %0", hi1_op) ;
+ break;
+ }
+ default:
+ break;
+ }
+
+ return "";
+}
+
+
+/* Helper function for md file. This function is used to emit logical
+ DI instructions. The argument "num" decides which instruction to be
+ printed. */
+const char *
+cr16_emit_logical_di (rtx *operands, enum rtx_code code)
+{
+ rtx lo_op[2] ;
+ rtx hi_op[2] ;
+
+ lo_op[0] = gen_lowpart (SImode, operands[0]);
+ hi_op[0] = simplify_gen_subreg (SImode, operands[0], DImode, 4);
+
+ lo_op[1] = gen_lowpart (SImode, operands[2]);
+ hi_op[1] = simplify_gen_subreg (SImode, operands[2], DImode, 4);
+
+ switch (code)
+ {
+ case AND:
+ {
+ output_asm_insn ("andd\t%1, %0", lo_op) ;
+ output_asm_insn ("andd\t%1, %0", hi_op) ;
+ return "";
+ }
+ case IOR:
+ {
+ output_asm_insn ("ord\t%1, %0", lo_op) ;
+ output_asm_insn ("ord\t%1, %0", hi_op) ;
+ return "";
+ }
+ case XOR:
+ {
+ output_asm_insn ("xord\t%1, %0", lo_op) ;
+ output_asm_insn ("xord\t%1, %0", hi_op) ;
+ return "";
+ }
+ default:
+ break;
+ }
+
+ return "";
+}
+
+/* Initialize 'targetm' variable which contains pointers to functions
+ and data relating to the target machine. */
+
+struct gcc_target targetm = TARGET_INITIALIZER;
diff --git a/gcc/config/cr16/cr16.h b/gcc/config/cr16/cr16.h
new file mode 100644
index 0000000..01577ca
--- /dev/null
+++ b/gcc/config/cr16/cr16.h
@@ -0,0 +1,590 @@
+/* Definitions of target machine for GNU compiler, for CR16.
+ Copyright (C) 2012 Free Software Foundation, Inc.
+ Contributed by KPIT Cummins Infosystems Limited.
+
+ 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/>. */
+
+#ifndef GCC_CR16_H
+#define GCC_CR16_H
+
+#define OBJECT_FORMAT_ELF
+
+/* Controlling the driver. */
+
+/* The GNU C++ standard library requires that these macros be defined. */
+#undef CPLUSPLUS_CPP_SPEC
+#define CPLUSPLUS_CPP_SPEC "-D_GNU_SOURCE %(cpp)"
+
+#undef STARTFILE_SPEC
+#define STARTFILE_SPEC "crt1.o%s crti.o%s crtbegin.o%s crtlibid.o%s"
+
+#undef ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+#undef MATH_LIBRARY
+#define MATH_LIBRARY ""
+
+#undef LIB_SPEC
+#define LIB_SPEC "-( -lc %{msim*:-lsim}%{!msim*:-lnosys} -) \
+%{msim*:%{!T*:-Tsim.ld}} \
+%{!T*:%{!msim*: %{-Telf32cr16.x}}}"
+
+/* Run-time target specification. */
+#ifndef TARGET_CPU_CPP_BUILTINS
+#define TARGET_CPU_CPP_BUILTINS() \
+do \
+ { \
+ builtin_define ("__CR__"); \
+ builtin_define ("__CR16__"); \
+ builtin_define ("__CR16C__"); \
+ if (TARGET_CR16CP) \
+ builtin_define ("__CR16CP__"); \
+ else \
+ builtin_define ("__CR16CSTD__"); \
+ if (CR16_TARGET_DATA_NEAR) \
+ builtin_define ("__DATA_NEAR__"); \
+ if (CR16_TARGET_DATA_MEDIUM) \
+ builtin_define ("__DATA_MEDIUM__"); \
+ if (CR16_TARGET_DATA_FAR) \
+ builtin_define ("__DATA_FAR__"); \
+ if (TARGET_INT32) \
+ builtin_define ("__INT32__"); \
+ } \
+while (0)
+#endif
+
+/* Force the generation of dwarf .debug_frame sections even if not
+ compiling -g. This guarantees that we can unwind the stack. */
+#define DWARF2_FRAME_INFO 1
+
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+/* Generate .file/.loc directives, so that the assembler generates the
+ line table. */
+#define DWARF2_ASM_LINE_DEBUG_INFO 1
+
+#define CR16_TARGET_DATA_NEAR cr16_is_data_model (DM_NEAR)
+#define CR16_TARGET_DATA_MEDIUM cr16_is_data_model (DM_DEFAULT)
+#define CR16_TARGET_DATA_FAR cr16_is_data_model (DM_FAR)
+
+/* Storage layout. */
+#define BITS_BIG_ENDIAN 0
+
+#define BYTES_BIG_ENDIAN 0
+
+#define WORDS_BIG_ENDIAN 0
+
+#define UNITS_PER_WORD 2
+
+/* Units per 32-bit (DWORD). */
+#define CR16_UNITS_PER_DWORD 4
+
+#define POINTER_SIZE 32
+
+#define PARM_BOUNDARY 16
+
+#define STACK_BOUNDARY (MAX (BIGGEST_ALIGNMENT, PARM_BOUNDARY))
+
+#define FUNCTION_BOUNDARY BIGGEST_ALIGNMENT
+
+/* Biggest alignment on CR16C+ is 32-bit as internal bus is AMBA based
+ where as CR16C is proprietary internal bus architecture. */
+#define BIGGEST_ALIGNMENT ((TARGET_CR16CP) ? 32 : 16)
+
+#define MAX_FIXED_MODE_SIZE 64
+
+/* In CR16 arrays of chars are word-aligned, so strcpy () will be faster. */
+#define DATA_ALIGNMENT(TYPE, ALIGN) \
+ (((TREE_CODE (TYPE) == ARRAY_TYPE) \
+ && (TYPE_MODE (TREE_TYPE (TYPE)) == QImode) \
+ && ((ALIGN) < BITS_PER_WORD)) \
+ ? (BITS_PER_WORD) : (ALIGN))
+
+/* In CR16 strings are word-aligne; strcpy from constants will be faster. */
+#define CONSTANT_ALIGNMENT(CONSTANT, ALIGN) \
+ (((TREE_CODE (CONSTANT) == STRING_CST) && ((ALIGN) < BITS_PER_WORD)) \
+ ? (BITS_PER_WORD) : (ALIGN))
+
+#define STRICT_ALIGNMENT 0
+
+#define PCC_BITFIELD_TYPE_MATTERS 1
+
+/* Layout of source language data types. */
+#define INT_TYPE_SIZE (TARGET_INT32 ? 32 : 16)
+
+#define SHORT_TYPE_SIZE 16
+
+#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
+
+#define SIZE_TYPE "long unsigned int"
+
+#define PTRDIFF_TYPE "long int"
+
+#define WCHAR_TYPE "short unsigned int"
+
+#define WCHAR_TYPE_SIZE 16
+
+/* By default, the C++ compiler will use the lowest bit of the pointer
+ to function to indicate a pointer-to-member-function points to a
+ virtual member function. However, in CR architecture FUNCTION_BOUNDARY
+ indicates function addresses are always even, but function pointers can be
+ odd (after right-shifting them when loading them into a register), and the
+ default doesn't work. In that case, the lowest bit of the delta
+ field will be used (the remainder of the field is shifted to the left). */
+#define TARGET_PTRMEMFUNC_VBIT_LOCATION ptrmemfunc_vbit_in_delta
+
+/* Define DEFAULT_PCC_STRUCT_RETURN to 1 if all structure and union return
+ values must be in memory. */
+#define DEFAULT_PCC_STRUCT_RETURN 0
+
+/* Register usage. */
+
+/* First 32-bit register is R12. */
+#define CR16_FIRST_DWORD_REGISTER 12
+
+#define FIRST_PSEUDO_REGISTER 16
+
+/* 1 for registers that have pervasive standard uses
+ and are not available for the register allocator.
+ On the CR16, only the stack pointer (r15) is such. */
+#define FIXED_REGISTERS \
+ { \
+ /* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10. */ \
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, \
+ /* r11 r12 r13 ra sp. */ \
+ 0, 0, 0, 0, 1 \
+ }
+
+/* 1 for registers not available across function calls.
+ These must include the FIXED_REGISTERS and also any
+ registers that can be used without being saved.
+ The latter must include the registers where values are returned
+ and the register where structure-value addresses are passed.
+
+ On the CR16, calls clobbers r0-r6 (scratch registers),
+ ra (the return address) and sp (the stack pointer). */
+#define CALL_USED_REGISTERS \
+ { \
+ /* r0 r1 r2 r3 r4 r5 r6 r7 r8 r9 r10. */ \
+ 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, \
+ /* r11 r12 r13 ra sp. */ \
+ 0, 0, 0, 1, 1 \
+ }
+
+/* Returns 1 if the register is longer than word size, 0 otherwise. */
+#define LONG_REG_P(REGNO) \
+ (HARD_REGNO_NREGS (REGNO, \
+ GET_MODE_WIDER_MODE (smallest_mode_for_size \
+ (BITS_PER_WORD, MODE_INT))) == 1)
+
+#define HARD_REGNO_NREGS(REGNO, MODE) \
+ ((REGNO >= CR16_FIRST_DWORD_REGISTER) \
+ ? ((GET_MODE_SIZE (MODE) + CR16_UNITS_PER_DWORD - 1) / CR16_UNITS_PER_DWORD)\
+ : ((GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD))
+
+/* Nonzero if it is permissible to store a value of mode @var{mode} in hard
+ register number @var{regno} (or in several registers starting with that
+ one). On the CR16 architecture, all registers can hold all modes,
+ except that double precision floats (and double ints) must fall on
+ even-register boundaries. */
+#define HARD_REGNO_MODE_OK(REGNO, MODE) cr16_hard_regno_mode_ok (REGNO, MODE)
+
+#define NOTICE_UPDATE_CC(EXP, INSN) \
+ notice_update_cc ((EXP))
+
+/* Interrupt functions can only use registers that have already been
+ saved by the prologue, even if they would normally be call-clobbered
+ Check if sizes are same and then check if it is possible to rename. */
+#define HARD_REGNO_RENAME_OK(SRC, DEST) \
+ (!cr16_interrupt_function_p () || (df_regs_ever_live_p (DEST)))
+
+/* Exception handling stuff. */
+
+/*To ensure correct dwarf unwinding. */
+#define LIBGCC2_UNWIND_ATTRIBUTE __attribute__((optimize ("no-gcse","no-dse")))
+
+#define gen_rtx_RA gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM)
+
+/* Use (r8,r7) and (r10,r9) to pass exception handling information. */
+#define EH_RETURN_DATA_REGNO(N) (((N) < 2) ? (N*2 + 7) : INVALID_REGNUM)
+
+#define DWARF2_UNWIND_INFO 1
+
+/* (r5,r4) holds a stack adjustment for returning to a handler. */
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (Pmode, 4)
+
+#define EH_RETURN_HANDLER_RTX \
+ gen_rtx_MEM (Pmode, plus_constant (arg_pointer_rtx, -4))
+
+#define INCOMING_RETURN_ADDR_RTX gen_rtx_RA
+
+#define DWARF_FRAME_RETURN_COLUMN \
+ DWARF_FRAME_REGNUM (RETURN_ADDRESS_REGNUM)
+
+#define INCOMING_FRAME_SP_OFFSET 0
+#define FRAME_POINTER_CFA_OFFSET(FNDECL) 0
+
+/* A C expression whose value is RTL representing the value of the return
+ address for the frame COUNT steps up from the current frame. */
+#define RETURN_ADDR_RTX(COUNT, FRAME) \
+ (0 == COUNT) ? gen_rtx_PLUS (Pmode, gen_rtx_RA, gen_rtx_RA) \
+ : const0_rtx
+
+#define MODES_TIEABLE_P(MODE1, MODE2) \
+ (GET_MODE_CLASS (MODE1) == GET_MODE_CLASS (MODE2))
+
+enum reg_class
+{
+ NO_REGS,
+ SHORT_REGS,
+ LONG_REGS,
+ NOSP_REGS,
+ DOUBLE_BASE_REGS,
+ GENERAL_REGS,
+ ALL_REGS,
+ LIM_REG_CLASSES
+};
+
+#define N_REG_CLASSES (int) LIM_REG_CLASSES
+
+#define REG_CLASS_NAMES \
+ { \
+ "NO_REGS", \
+ "SHORT_REGS", \
+ "LONG_REGS", \
+ "NOSP_REGS", \
+ "DOUBLE_BASE_REGS", \
+ "GENERAL_REGS", \
+ "ALL_REGS" \
+ }
+
+#define REG_CLASS_CONTENTS \
+ { \
+ {0x00000000}, /* NO_REGS */ \
+ {0x00000FFF}, /* SHORT_REGS : 0 - 11 */ \
+ {0x0000F000}, /* LONG_REGS : 12 - 15 */ \
+ {0x00007FFF}, /* NOSP_REGS : 0 - 14 */ \
+ {0x0000F555}, /* DOUBLE_BASE_REGS : 2,4,6,8,10 */ \
+ {0x0000FFFF}, /* GENERAL_REGS : 0 - 15 */ \
+ {0x0000FFFF} /* ALL_REGS : 0 - 15 */ \
+ }
+
+#define TARGET_SMALL_REGISTER_CLASSES_FOR_MODE_P hook_bool_mode_true
+
+#define REGNO_REG_CLASS(REGNO) cr16_regno_reg_class (REGNO)
+
+#define BASE_REG_CLASS GENERAL_REGS
+
+#define MODE_BASE_REG_CLASS(MODE) \
+ (GET_MODE_SIZE (MODE) <= 4 ? (BASE_REG_CLASS) : (DOUBLE_BASE_REGS))
+
+#define INDEX_REG_CLASS LONG_REGS
+
+#define CR16_REGNO_OK_FOR_BASE_P(REGNO) \
+ (((REGNO) < FIRST_PSEUDO_REGISTER) \
+ || (reg_renumber && ((unsigned) reg_renumber[REGNO] \
+ < FIRST_PSEUDO_REGISTER)))
+
+/* Use even-numbered reg for 64-bit accesses. */
+#define REGNO_MODE_OK_FOR_BASE_P(REGNO, MODE) \
+ (CR16_REGNO_OK_FOR_BASE_P(REGNO) && \
+ ((GET_MODE_SIZE (MODE) > 4 && \
+ (REGNO) < CR16_FIRST_DWORD_REGISTER) \
+ ? (0 == ((REGNO) & 1)) \
+ : 1))
+
+/* TODO: For now lets not support index addressing mode. */
+#define REGNO_OK_FOR_INDEX_P(REGNO) \
+ (((REGNO >= CR16_FIRST_DWORD_REGISTER) \
+ && ((REGNO) < FIRST_PSEUDO_REGISTER)) \
+ || (reg_renumber \
+ && (((unsigned) reg_renumber[REGNO] >= CR16_FIRST_DWORD_REGISTER) \
+ && ((unsigned) reg_renumber[REGNO] < FIRST_PSEUDO_REGISTER))) \
+ )
+
+#define PREFERRED_RELOAD_CLASS(X, CLASS) CLASS
+
+/* The maximum number of consecutive registers of class CLASS needed to
+ hold a value of mode MODE.
+ On the CompactRISC architecture, the size of MODE in words.
+ The size of MODE in double words for the class LONG_REGS.
+
+ The following check assumes if the class is not LONG_REGS, then
+ all (NO_REGS, SHORT_REGS, NOSP_REGS and GENERAL_REGS) other classes are
+ short. We may have to check if this can cause any degradation in
+ performance. */
+#define CLASS_MAX_NREGS(CLASS, MODE) \
+ (CLASS == LONG_REGS \
+ ? (GET_MODE_SIZE (MODE) + CR16_UNITS_PER_DWORD - 1) / CR16_UNITS_PER_DWORD\
+ : (GET_MODE_SIZE (MODE) + UNITS_PER_WORD - 1) / UNITS_PER_WORD)
+
+/* Macros to check the range of integers . These macros were used across
+ the port, majorly in constraints.md, predicates.md files. */
+#define SIGNED_INT_FITS_N_BITS(imm, N) \
+ ((((imm) < ((HOST_WIDE_INT) 1 << ((N) - 1))) \
+ && ((imm) >= -((HOST_WIDE_INT) 1 << ((N) - 1)))) ? 1 : 0)
+
+#define UNSIGNED_INT_FITS_N_BITS(imm, N) \
+ (((imm) < ((HOST_WIDE_INT) 1 << (N)) && (imm) >= (HOST_WIDE_INT) 0) ? 1 : 0)
+
+#define IN_RANGE_P(VALUE, LOW, HIGH) \
+ ((((HOST_WIDE_INT)(VALUE)) >= (HOST_WIDE_INT)(LOW)) \
+ && (((HOST_WIDE_INT)(VALUE)) <= ((HOST_WIDE_INT)(HIGH))))
+
+#define IN_RAN(VALUE, LOW, HIGH) \
+ (((((HOST_WIDE_INT)(VALUE)) >= (HOST_WIDE_INT)(LOW)) \
+ && (((HOST_WIDE_INT)(VALUE)) <= ((HOST_WIDE_INT)(HIGH)))) ? 1 : 0)
+
+/* This check is for sbit/cbit instruction. */
+#define OK_FOR_Z(OP) \
+ ((GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == CONST_INT) \
+ || (GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == REG) \
+ || (GET_CODE (OP) == MEM && GET_CODE (XEXP (OP, 0)) == PLUS \
+ && GET_CODE (XEXP ((XEXP (OP, 0)), 0)) == REG \
+ && GET_CODE (XEXP ((XEXP (OP, 0)), 1)) == CONST_INT))
+
+/* Stack layout and calling conventions. */
+#define STACK_GROWS_DOWNWARD
+
+#define STARTING_FRAME_OFFSET 0
+
+#define STACK_POINTER_REGNUM 15
+
+#define FRAME_POINTER_REGNUM 13
+
+#define ARG_POINTER_REGNUM 12
+
+#define STATIC_CHAIN_REGNUM 1
+
+#define RETURN_ADDRESS_REGNUM 14
+
+#define FIRST_PARM_OFFSET(FNDECL) 0
+
+#define ELIMINABLE_REGS \
+ { \
+ { ARG_POINTER_REGNUM, STACK_POINTER_REGNUM}, \
+ { ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM}, \
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM} \
+ }
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET) \
+ do \
+ { \
+ (OFFSET) = cr16_initial_elimination_offset ((FROM), (TO)); \
+ } \
+ while (0)
+
+/* Passing function arguments. */
+
+#define ACCUMULATE_OUTGOING_ARGS 0
+
+#define PUSH_ARGS 1
+
+#define PUSH_ROUNDING(BYTES) (((BYTES) + 1) & ~1)
+
+#ifndef CUMULATIVE_ARGS
+struct cumulative_args
+{
+ int ints;
+ int last_parm_in_reg;
+};
+
+#define CUMULATIVE_ARGS struct cumulative_args
+#endif
+
+/* On the CR16 architecture, Varargs routines should receive their parameters
+ on the stack. */
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, FNDECL, N_NAMED_ARGS) \
+ cr16_init_cumulative_args (&(CUM), (FNTYPE), (LIBNAME))
+
+#define FUNCTION_ARG_REGNO_P(REGNO) cr16_function_arg_regno_p (REGNO)
+
+/* Generating code for profiling - NOT IMPLEMENTED. */
+#undef FUNCTION_PROFILER
+#define FUNCTION_PROFILER(STREAM, LABELNO) \
+{ \
+ sorry ("profiler support for CR16"); \
+}
+
+/* Trampolines for nested functions - NOT SUPPORTED. */
+#define TRAMPOLINE_SIZE 16
+
+/* ADDRESSING MODES. */
+
+#define CONSTANT_ADDRESS_P(X) \
+ (GET_CODE (X) == LABEL_REF \
+ || GET_CODE (X) == SYMBOL_REF \
+ || GET_CODE (X) == CONST \
+ || GET_CODE (X) == CONST_INT)
+
+#define MAX_REGS_PER_ADDRESS 2
+
+#define HAVE_POST_INCREMENT 0
+#define HAVE_POST_DECREMENT 0
+#define HAVE_POST_MODIFY_DISP 0
+#define HAVE_POST_MODIFY_REG 0
+
+#ifdef REG_OK_STRICT
+#define CR16_REG_OK_FOR_BASE_P(X) CR16_REGNO_OK_FOR_BASE_P (REGNO (X))
+#define REG_MODE_OK_FOR_BASE_P(X, MODE) \
+ REGNO_MODE_OK_FOR_BASE_P (REGNO(X), MODE)
+#define REG_OK_FOR_INDEX_P(X) REGNO_OK_FOR_INDEX_P (REGNO (X))
+#else /* not REG_OK_STRICT. */
+#define CR16_REG_OK_FOR_BASE_P(X) 1
+#define REG_MODE_OK_FOR_BASE_P(X, MODE) 1
+#define REG_OK_FOR_INDEX_P(X) 1
+#endif /* not REG_OK_STRICT. */
+
+/* Go to LABEL if ADDR (a legitimate address expression) has
+ an effect that depends on the machine mode it is used for. */
+#define GO_IF_MODE_DEPENDENT_ADDRESS(ADDR, LABEL)
+
+/* Assume best case (branch predicted). */
+#define BRANCH_COST(speed_p, predictable_p) 2
+
+#define SLOW_BYTE_ACCESS 1
+
+/* It is as good or better to call a constant function address than to
+ call an address kept in a register. */
+#define NO_FUNCTION_CSE
+
+/* Dividing the output into sections. */
+
+#define TEXT_SECTION_ASM_OP "\t.section\t.text"
+
+#define DATA_SECTION_ASM_OP "\t.section\t.data"
+
+#define BSS_SECTION_ASM_OP "\t.section\t.bss"
+
+/* Position independent code (PIC). */
+/* NEAR_PIC for -fpic option. */
+
+#define NEAR_PIC 1
+
+/* FAR_PIC for -fPIC option. */
+
+#define FAR_PIC 2
+
+#define PIC_OFFSET_TABLE_REGNUM 12
+
+#define LEGITIMATE_PIC_OPERAND_P(X) legitimate_pic_operand_p (X)
+
+/* Assembler format. */
+
+/* Character to start a comment. */
+#define ASM_COMMENT_START "#"
+
+#define GLOBAL_ASM_OP "\t.globl\t"
+
+#undef USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX "_"
+
+#undef ASM_OUTPUT_LABELREF
+#define ASM_OUTPUT_LABELREF(STREAM, NAME) \
+ asm_fprintf (STREAM, "%U%s", (*targetm.strip_name_encoding) (NAME));
+
+#define ASM_OUTPUT_SYMBOL_REF(STREAM, SYMBOL) \
+ do \
+ { \
+ const char *rn = XSTR (SYMBOL, 0); \
+ assemble_name (STREAM, rn); \
+ if (SYMBOL_REF_FUNCTION_P (SYMBOL)) \
+ { \
+ fprintf ((STREAM), "@c"); \
+ } \
+ } \
+ while (0)
+
+#undef ASM_APP_ON
+#define ASM_APP_ON "#APP\n"
+
+#undef ASM_APP_OFF
+#define ASM_APP_OFF "#NO_APP\n"
+
+/* Switch into a generic section. */
+#define TARGET_ASM_NAMED_SECTION default_elf_asm_named_section
+
+#undef INIT_SECTION_ASM_OP
+#define INIT_SECTION_ASM_OP "\t.section\t.init"
+
+#undef FINI_SECTION_ASM_OP
+#define FINI_SECTION_ASM_OP "\t.section\t.fini"
+
+/* Instruction output. */
+
+#define REGISTER_NAMES \
+ { \
+ "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", \
+ "r8", "r9", "r10", "r11", "r12", "r13", "ra", "sp" \
+ }
+
+/* Output of dispatch tables. */
+
+/* Revisit. No PC relative case as label expressions are not
+ properly supported in binutils else we could have done this:
+ #define CASE_VECTOR_PC_RELATIVE (optimize_size ? 1 : 0). */
+#define CASE_VECTOR_PC_RELATIVE 0
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+ ((GET_MODE (BODY) == QImode) \
+ ? fprintf ((FILE), "\t.byte (.L%d-.L%d) >> 1\n", \
+ VALUE, REL) \
+ : fprintf ((FILE), "\t.word (.L%d-.L%d) >> 1\n", \
+ VALUE, REL))
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(STREAM, VALUE) \
+ asm_fprintf ((STREAM), "\t.long\t.L%d@c\n", (VALUE))
+
+/* Alignment in assembler file. */
+
+#define ASM_OUTPUT_ALIGN(STREAM, POWER) \
+ asm_fprintf ((STREAM), "\t.align\t%d\n", 1 << (POWER))
+
+/* Miscellaneous parameters. */
+
+#define CASE_VECTOR_MODE Pmode
+
+#define MOVE_MAX 4
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC) 1
+
+#define STORE_FLAG_VALUE 1
+
+#define Pmode SImode
+
+#define FUNCTION_MODE QImode
+
+/* Define this boolean macro(s) to indicate whether or not your architecture
+ has (un)conditional branches that can span all of memory. It is used in
+ conjunction with an optimization that partitions hot and cold basic blocks
+ into separate sections of the executable.
+ CR16 contains branch instructions that span whole address space. */
+#define HAS_LONG_COND_BRANCH 1
+#define HAS_LONG_UNCOND_BRANCH 1
+
+#endif /* End of GCC_CR16_H. */
diff --git a/gcc/config/cr16/cr16.md b/gcc/config/cr16/cr16.md
new file mode 100644
index 0000000..5e4530c
--- /dev/null
+++ b/gcc/config/cr16/cr16.md
@@ -0,0 +1,1084 @@
+;; GCC machine description for CR16.
+;; Copyright (C) 2012 Free Software Foundation, Inc.
+;; Contributed by KPIT Cummins Infosystems Limited.
+
+;; 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 numbers
+(define_constants
+ [(SP_REGNUM 15); Stack pointer
+ (RA_REGNUM 14); Return address
+ ]
+)
+
+;; Predicates & Constraints
+(include "predicates.md")
+(include "constraints.md")
+
+;; UNSPEC usage
+(define_constants
+ [(UNSPEC_PIC_ADDR 0)
+ (UNSPEC_PIC_LOAD_ADDR 1)
+ (UNSPEC_LIBRARY_OFFSET 2)
+ (UNSPEC_SH_LIB_PUSH_R12 3)
+ (UNSPEC_SH_LIB_POP_R12 4)
+ (UNSPEC_RETURN_ADDR 5)
+ ]
+)
+
+;; Attributes
+(define_attr "length" "" (const_int 2))
+
+(define_asm_attributes
+ [(set_attr "length" "2")]
+)
+
+;; Mode Macro Definitions
+(define_mode_iterator CR16IM [QI HI SI])
+(define_mode_iterator LONG [SI SF])
+(define_mode_iterator ALLMTD [QI HI SI SF DI DF])
+(define_mode_iterator DOUBLE [DI DF])
+(define_mode_iterator SHORT [QI HI])
+(define_mode_attr tIsa [(QI "b") (HI "w") (SI "d") (SF "d")])
+(define_mode_attr lImmArith [(QI "4") (HI "4") (SI "6") (SF "6")])
+(define_mode_attr lImmArithD [(QI "4") (HI "4") (SI "6") (SF "6") (DI "12") (DF "12")])
+(define_mode_attr iF [(QI "i") (HI "i") (SI "i") (SF "F")])
+(define_mode_attr iFD [(DI "i") (DF "F")])
+(define_mode_attr LL [(QI "L") (HI "L")])
+(define_mode_attr shImmBits [(QI "3") (HI "4") (SI "5")])
+
+; In QI mode we push 2 bytes instead of 1 byte.
+(define_mode_attr pushCnstr [(QI "X") (HI "<") (SI "<") (SF "<") (DI "<") (DF "<")])
+
+; tpush will be used to generate the 'number of registers to push' in the
+; push instruction.
+(define_mode_attr tpush [(QI "1") (HI "1") (SI "2") (SF "2") (DI "4") (DF "4")])
+
+;; Code Macro Definitions
+(define_code_attr sIsa [(sign_extend "") (zero_extend "u")])
+(define_code_attr sPat [(sign_extend "s") (zero_extend "u")])
+(define_code_attr szPat [(sign_extend "") (zero_extend "zero_")])
+(define_code_attr szIsa [(sign_extend "x") (zero_extend "z")])
+
+(define_code_iterator sz_xtnd [ sign_extend zero_extend])
+(define_code_iterator any_cond [eq ne gt gtu lt ltu ge geu le leu])
+(define_code_iterator plusminus [plus minus])
+
+(define_code_attr plusminus_insn [(plus "add") (minus "sub")])
+(define_code_attr plusminus_flag [(plus "PLUS") (minus "MINUS")])
+(define_code_attr comm [(plus "%") (minus "")])
+
+(define_code_iterator any_logic [and ior xor])
+(define_code_attr logic [(and "and") (ior "or") (xor "xor")])
+(define_code_attr any_logic_insn [(and "and") (ior "ior") (xor "xor")])
+(define_code_attr any_logic_flag [(and "AND") (ior "IOR") (xor "XOR")])
+
+(define_mode_iterator QH [QI HI])
+(define_mode_attr qh [(QI "qi") (HI "hi")])
+(define_mode_attr QHsz [(QI "2,2,2") (HI "2,2,4")])
+(define_mode_attr QHsuffix [(QI "b") (HI "w")])
+
+
+;; Function Prologue and Epilogue
+(define_expand "prologue"
+ [(const_int 0)]
+ ""
+ {
+ cr16_expand_prologue ();
+ DONE;
+ }
+)
+
+(define_insn "push_for_prologue"
+ [(set (reg:SI SP_REGNUM)
+ (minus:SI (reg:SI SP_REGNUM)
+ (match_operand:SI 0 "immediate_operand" "i")))]
+ "reload_completed"
+ {
+ return cr16_prepare_push_pop_string (0);
+ }
+ [(set_attr "length" "4")]
+)
+
+(define_expand "epilogue"
+ [(return)]
+ ""
+ {
+ cr16_expand_epilogue ();
+ DONE;
+ }
+)
+
+(define_insn "pop_and_popret_return"
+ [(set (reg:SI SP_REGNUM)
+ (plus:SI (reg:SI SP_REGNUM)
+ (match_operand:SI 0 "immediate_operand" "i")))
+ (use (reg:SI RA_REGNUM))
+ (return)]
+ "reload_completed"
+ {
+ return cr16_prepare_push_pop_string (1);
+ }
+ [(set_attr "length" "4")]
+)
+
+(define_insn "popret_RA_return"
+ [(use (reg:SI RA_REGNUM))
+ (return)]
+ "reload_completed"
+ "popret\tra"
+ [(set_attr "length" "2")]
+)
+
+;; Arithmetic Instuction Patterns
+
+;; Addition-Subtraction "adddi3/subdi3" insns.
+(define_insn "<plusminus_insn>di3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (plusminus:DI (match_operand:DI 1 "register_operand" "<comm>0")
+ (match_operand:DI 2 "register_operand" "r")))]
+ ""
+ {
+ return cr16_emit_add_sub_di (operands, <plusminus_flag>);
+ })
+
+(define_insn "addsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r,r")
+ (plus:SI (match_operand:SI 1 "register_operand" "%0,0,0,0,0")
+ (match_operand:SI 2 "reg_si_int_operand" "r,M,N,O,i")))]
+ ""
+ "addd\t%2, %0"
+ [(set_attr "length" "2,2,4,4,6")]
+)
+
+;; Addition-Subtraction "addhi3/subhi3" insns.
+(define_insn "<plusminus_insn>hi3"
+ [(set (match_operand:HI 0 "register_operand" "=c,c,c")
+ (plusminus:HI (match_operand:HI 1 "register_operand" "<comm>0,0,0")
+ (match_operand:HI 2 "reg_hi_int_operand" "c,M,N")))]
+ ""
+ "<plusminus_insn>w\t%2, %0"
+ [(set_attr "length" "2,2,4")]
+)
+
+;; Addition-Subtraction "addqi3/subqi3" insns.
+(define_insn "<plusminus_insn>qi3"
+ [(set (match_operand:QI 0 "register_operand" "=c,c")
+ (plusminus:QI (match_operand:QI 1 "register_operand" "<comm>0,0")
+ (match_operand:QI 2 "reg_qi_int_operand" "c,M")))]
+ ""
+ "<plusminus_insn>b\t%2, %0"
+ [(set_attr "length" "2,2")]
+)
+
+;; Subtract Instruction
+(define_insn "subsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (minus:SI (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:SI 2 "reg_si_int_operand" "r,i")))]
+ ""
+ "subd\t%2, %0"
+ [(set_attr "length" "4,6")]
+)
+
+;; Multiply and Accumulate Instructions "smachisi3/umachisi3"
+(define_insn "<sPat>maddhisi4"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (plus:SI
+ (mult:SI (sz_xtnd:SI (match_operand:HI 1 "register_operand" "r"))
+ (sz_xtnd:SI (match_operand:HI 2 "register_operand" "r")))
+ (match_operand:SI 3 "register_operand" "0")))]
+ "TARGET_MAC"
+ "mac<sPat>w\t%1, %2, %0"
+ [(set_attr "length" "2")]
+)
+
+;; Multiply Instructions
+(define_insn "mulhi3"
+ [(set (match_operand:HI 0 "register_operand" "=c,c,c")
+ (mult:HI (match_operand:HI 1 "register_operand" "%0,0,0")
+ (match_operand:HI 2 "reg_or_int_operand" "c,M,N")))]
+ ""
+ "mulw\t%2, %0"
+ [(set_attr "length" "2,2,4")]
+)
+
+(define_insn "mulqihi3"
+ [(set (match_operand:HI 0 "register_operand" "=c")
+ (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+ (sign_extend:HI (match_operand:QI 2 "register_operand" "c"))))]
+ ""
+ "mulsb\t%2, %0"
+ [(set_attr "length" "2")]
+)
+
+;; Bit Set/Clear Instructions
+(define_expand "insv"
+ [(set (zero_extract (match_operand 0 "memory_operand" "")
+ (match_operand 1 "immediate_operand" "")
+ (match_operand 2 "immediate_operand" ""))
+ (match_operand 3 "immediate_operand" ""))]
+ "TARGET_BIT_OPS"
+ {
+ if (INTVAL (operands[1]) != 1)
+ FAIL;
+ if (INTVAL (operands[2]) < 0 || INTVAL (operands[2]) > 15)
+ FAIL;
+ if (INTVAL (operands[3]) == 1)
+ {
+ if (GET_MODE (operands[0]) == QImode)
+ {
+ emit_insn (gen_set_bitqi (operands[0], operands[2]));
+ DONE;
+ }
+ else if (GET_MODE (operands[0]) == HImode)
+ {
+ emit_insn (gen_set_bithi (operands[0], operands[2]));
+ DONE;
+ }
+ }
+ if (INTVAL (operands[3]) == 0)
+ {
+ if (GET_MODE (operands[0]) == QImode)
+ {
+ emit_insn (gen_clr_bitqi (operands[0], operands[2]));
+ DONE;
+ }
+ else if (GET_MODE (operands[0]) == HImode)
+ {
+ emit_insn (gen_clr_bithi (operands[0], operands[2]));
+ DONE;
+ }
+ }
+ }
+)
+
+(define_insn "set_bit<mode>"
+ [(set (zero_extract:SHORT (match_operand:SHORT 0 "memory_operand" "+m")
+ (const_int 1)
+ (match_operand 1 "immediate_operand" "i"))
+ (const_int 1))]
+ "TARGET_BIT_OPS"
+ "sbit<tIsa>\t%1,%0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "clr_bit<mode>"
+ [(set (zero_extract:SHORT (match_operand:SHORT 0 "memory_operand" "+m")
+ (const_int 1)
+ (match_operand 1 "immediate_operand" "i"))
+ (const_int 0))]
+ "TARGET_BIT_OPS"
+ "cbit<tIsa>\t%1,%0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "set_bit<mode>_mem"
+ [(set (match_operand:SHORT 0 "bit_operand" "=m")
+ (ior:SHORT (match_dup 0)
+ (match_operand:SHORT 1 "one_bit_operand" "i"))
+ )]
+ "TARGET_BIT_OPS"
+ "sbit<tIsa>\t$%s1,%0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "clear_bit<mode>_mem"
+ [(set (match_operand:SHORT 0 "bit_operand" "=m")
+ (and:SHORT (match_dup 0)
+ (match_operand:SHORT 1 "rev_one_bit_operand" "i"))
+ )]
+ "TARGET_BIT_OPS"
+ "cbit<tIsa>\t$%r1,%0"
+ [(set_attr "length" "2")]
+)
+
+;; Logical Instructions - and/ior/xor "anddi3/iordi3/xordi3"
+(define_insn "<any_logic_insn>di3"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (any_logic:DI (match_operand:DI 1 "register_operand" "%0")
+ (match_operand:DI 2 "register_operand" "r")))]
+ ""
+ {
+ return cr16_emit_logical_di (operands, <any_logic_flag>);
+ })
+
+; Logical and/ior/xor "andsi3/iorsi3/xorsi3"
+(define_insn "<any_logic_insn>si3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+ (any_logic:SI (match_operand:SI 1 "register_operand" "%0,0,0,0")
+ (match_operand:SI 2 "reg_si_int_operand" "r,M,N,i")))]
+ ""
+ "<logic>d\t%2, %0"
+ [(set_attr "length" "2,2,4,6")]
+)
+
+; Logical and/ior/xor in HImode "andhi3/iorhi3/xorhi3"
+; Logical and/ior/xor in QImode "andqi3/iorqi3/xorqi3"
+(define_insn "<any_logic_insn><qh>3"
+ [(set (match_operand:QH 0 "register_operand" "=c,c,c")
+ (any_logic:QH (match_operand:QH 1 "register_operand" "%0,0,0")
+ (match_operand:QH 2 "reg_hi_int_operand" "c,M,N")))]
+ ""
+ "<logic><QHsuffix>\t%2, %0"
+ [(set_attr "length" "<QHsz>")]
+)
+
+;; Sign and Zero Extend Instructions
+(define_insn "<szPat>extendhisi2"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (sz_xtnd:SI (match_operand:HI 1 "register_operand" "r")))]
+ ""
+ "mov<szIsa>w\t%1, %0"
+ [(set_attr "length" "4")]
+)
+
+(define_insn "<szPat>extendqihi2"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (sz_xtnd:HI (match_operand:QI 1 "register_operand" "r")))]
+ ""
+ "mov<szIsa>b\t%1, %0"
+ [(set_attr "length" "4")]
+)
+
+;; One's Complement
+(define_insn "one_cmpldi2"
+ [(set (match_operand:DI 0 "register_operand" "=r")
+ (not:DI (match_operand:DI 1 "register_operand" "0")))]
+ ""
+ {
+ rtx xoperand ;
+ int reg0 = REGNO (operands[0]);
+
+ xoperand = gen_rtx_REG (SImode, reg0 + 2);
+ output_asm_insn ("xord\t$-1, %0", operands);
+ output_asm_insn ("xord\t$-1, %0", &xoperand);
+ return "" ;
+ }
+ [(set_attr "length" "12")]
+)
+
+(define_insn "one_cmpl<mode>2"
+ [(set (match_operand:CR16IM 0 "register_operand" "=r")
+ (not:CR16IM (match_operand:CR16IM 1 "register_operand" "0")))]
+ ""
+ "xor<tIsa>\t$-1, %0"
+ [(set_attr "length" "2")]
+)
+
+;; Arithmetic Left and Right Shift Instructions
+(define_insn "ashlqi3"
+ [(set (match_operand:QI 0 "register_operand" "=c,c")
+ (ashift:QI (match_operand:QI 1 "register_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "c,I")))]
+ ""
+ "ashub\t%2, %0"
+ [(set_attr "length" "2,2")]
+)
+
+(define_insn "ashlhi3"
+ [(set (match_operand:HI 0 "register_operand" "=c,c")
+ (ashift:HI (match_operand:HI 1 "register_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "c,J")))]
+ ""
+ "ashuw\t%2, %0"
+ [(set_attr "length" "2,2")]
+)
+
+(define_insn "ashlsi3"
+ [(set (match_operand:SI 0 "register_operand" "=r,r")
+ (ashift:SI (match_operand:SI 1 "register_operand" "0,0")
+ (match_operand:QI 2 "nonmemory_operand" "r,K")))]
+ ""
+ "ashud\t%2, %0"
+ [(set_attr "length" "2,2")]
+)
+
+(define_expand "ashr<mode>3"
+ [(set (match_operand:CR16IM 0 "register_operand" "")
+ (ashiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "")
+ (match_operand:QI 2 "nonmemory_operand" "")))]
+ ""
+ {
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ /* If the constant is not in range, try placing it in a reg */
+ if (!UNSIGNED_INT_FITS_N_BITS(INTVAL (operands[2]),<shImmBits>))
+ operands[2] = copy_to_mode_reg(QImode, operands[2]);
+ }
+
+ if (GET_CODE (operands[2]) != CONST_INT)
+ operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
+ }
+)
+
+(define_insn "ashrqi3_imm_insn"
+ [(set (match_operand:QI 0 "register_operand" "=c")
+ (ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
+ (match_operand:QI 2 "shift_qi_imm_operand" "i")))]
+ ""
+ "ashub\t$%n2, %0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "ashrhi3_imm_insn"
+ [(set (match_operand:HI 0 "register_operand" "=c")
+ (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:QI 2 "shift_hi_imm_operand" "i")))]
+ ""
+ "ashuw\t$%n2, %0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "ashrsi3_imm_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:QI 2 "shift_si_imm_operand" "i")))]
+ ""
+ "ashud\t$%n2, %0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "ashrqi3_neg_insn"
+ [(set (match_operand:QI 0 "register_operand" "=c")
+ (ashiftrt:QI (match_operand:QI 1 "register_operand" "0")
+ (neg:QI (match_operand:QI 2 "register_operand" "c"))))]
+ ""
+ "ashub\t%2,%0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "ashrhi3_neg_insn"
+ [(set (match_operand:HI 0 "register_operand" "=c")
+ (ashiftrt:HI (match_operand:HI 1 "register_operand" "0")
+ (neg:QI (match_operand:QI 2 "register_operand" "c"))))]
+ ""
+ "ashuw\t%2,%0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "ashrdi3_neg_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (ashiftrt:SI (match_operand:SI 1 "register_operand" "0")
+ (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
+ ""
+ "ashud\t%2,%0"
+ [(set_attr "length" "2")]
+)
+
+(define_expand "lshr<mode>3"
+ [(set (match_operand:CR16IM 0 "register_operand" "")
+ (lshiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "")
+ (match_operand:QI 2 "reg_or_int_operand" "")))]
+ ""
+ {
+ if (GET_CODE (operands[2]) == CONST_INT)
+ {
+ /* If the constant is not in range, try placing it in a reg */
+ if (!UNSIGNED_INT_FITS_N_BITS(INTVAL (operands[2]),<shImmBits>))
+ operands[2] = copy_to_mode_reg(QImode, operands[2]);
+ }
+
+ if (GET_CODE (operands[2]) != CONST_INT)
+ operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
+ }
+)
+
+(define_insn "lshrqi3_imm_insn"
+ [(set (match_operand:QI 0 "register_operand" "=c")
+ (lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
+ (match_operand:QI 2 "shift_qi_operand" "Q")))]
+ ""
+ "lshb\t$%n2, %0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "lshrhi3_imm_insn"
+ [(set (match_operand:HI 0 "register_operand" "=c")
+ (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
+ (match_operand:QI 2 "shift_hi_operand" "R")))]
+ ""
+ "lshw\t$%n2, %0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "lshrsi3_imm_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
+ (match_operand:QI 2 "shift_si_operand" "S")))]
+ ""
+ "lshd\t$%n2, %0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "lshrqi3_neg_insn"
+ [(set (match_operand:QI 0 "register_operand" "=c")
+ (lshiftrt:QI (match_operand:QI 1 "register_operand" "0")
+ (neg:QI (match_operand:QI 2 "register_operand" "c"))))]
+ ""
+ "lshb\t%2,%0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "lshrhi3_neg_insn"
+ [(set (match_operand:HI 0 "register_operand" "=c")
+ (lshiftrt:HI (match_operand:HI 1 "register_operand" "0")
+ (neg:QI (match_operand:QI 2 "register_operand" "c"))))]
+ ""
+ "lshw\t%2,%0"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "lshrsi3_neg_insn"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (lshiftrt:SI (match_operand:SI 1 "register_operand" "0")
+ (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
+ ""
+ "lshd\t%2,%0"
+ [(set_attr "length" "2")]
+)
+
+;; Move Instructions
+
+;; Move any non-immediate operand 0 to a general operand 1.
+;; This applies only before starting the reload process
+;; Operand 0 is not a register operand of type mode MODE
+;; If Operand 0 is a push operand of type mode MODE
+;; then, if Operand 1 is a non-SP register
+;; then, Operand 1 = copy_to_mode_reg (<MODE>mode, Operand 1)
+;; endif
+;; else
+;; if Operand 1 is either register or 4-bit immediate constant
+;; then, Operand 1 = copy_to_mode_reg (<MODE>mode, Operand 1)
+;; endif
+;; endif
+;;
+;; What does copy_to_mode_reg (mode, rtx val) do?
+;; Copy the value into new temp reg and return the reg where the
+;; mode of the new reg is always mode MODE when value is constant
+;;
+;; Why should copy_to_mode_reg be called?
+;; All sorts of move are nor supported by CR16. Therefore,
+;; when unsupported move is encountered, the additional instructions
+;; will be introduced for the purpose.
+;;
+;; A new move insn is inserted for Op 1 when one of the following
+;; conditions is met.
+;; Case 1: Op 0 is push_operand
+;; Op 1 is SP register
+;;
+;; Case 2: Op 0 is not push_operand
+;; Op 1 is neither register nor unsigned 4-bit immediate
+
+(define_expand "mov<mode>"
+ [(set (match_operand:ALLMTD 0 "nonimmediate_operand" "")
+ (match_operand:ALLMTD 1 "general_operand" ""))]
+ ""
+ {
+ if (!(reload_in_progress || reload_completed))
+ {
+ /* Only if Op0 is a register operand. */
+ if (!register_operand (operands[0], <MODE>mode))
+ {
+ if (push_operand (operands[0], <MODE>mode))
+ {
+ /* Use copy_to_mode_reg only if the register needs
+ to be pushed is SP as CR16 does not support pushing SP. */
+ if (!nosp_reg_operand (operands[1], <MODE>mode))
+ operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]);
+ }
+ else
+ {
+ /* Use copy_to_mode_reg if op1 is not register operand
+ subject to conditions inside. */
+ if (!register_operand (operands[1], <MODE>mode))
+ {
+ /* CR16 does not support moving immediate to SI or SF
+ type memory. */
+ if (<MODE>mode == SImode || <MODE>mode == SFmode ||
+ <MODE>mode == DImode || <MODE>mode == DFmode)
+ operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]);
+ else
+ /* moving imm4 is supported by CR16 instruction. */
+ if (!u4bits_operand (operands[1], <MODE>mode))
+ operands[1] = copy_to_mode_reg (<MODE>mode, operands[1]);
+ }
+ }
+ }
+
+ /* If operand-1 is a symbol, convert it into a BRO or GOT Format. */
+ if (flag_pic && ! legitimate_pic_operand_p (operands[1]))
+ {
+ operands[1] = legitimize_pic_address (operands[1], <MODE>mode, 0);
+ }
+ }
+ }
+)
+
+; ALLMT : QI,HI,SI,SF
+; pushCnstr : Push constraints
+; QI : X
+; HI,SI,SF,DI,DF : <
+; b : All non-sp registers
+; tpush : Push count
+; QI,HI : 1
+; SI,SF : 2
+; DI,DF : 4
+(define_insn "push<mode>_internal"
+ [(set (match_operand:ALLMTD 0 "push_operand" "=<pushCnstr>")
+ (match_operand:ALLMTD 1 "nosp_reg_operand" "b"))]
+ ""
+ "push\t$<tpush>,%p1"
+ [(set_attr "length" "2")]
+)
+
+; (DI, DF) move
+(define_insn "*mov<mode>_double"
+ [(set (match_operand:DOUBLE 0 "nonimmediate_operand" "=r, r, r, m")
+ (match_operand:DOUBLE 1 "general_operand" "r, <iFD>, m, r"))]
+ "register_operand (operands[0], DImode)
+ || register_operand (operands[0], DFmode)
+ || register_operand (operands[1], DImode)
+ || register_operand (operands[1], DFmode)"
+ {
+ if (0 == which_alternative) {
+ rtx xoperands[2] ;
+ int reg0 = REGNO (operands[0]);
+ int reg1 = REGNO (operands[1]);
+
+ xoperands[0] = gen_rtx_REG (SImode, reg0 + 2);
+ xoperands[1] = gen_rtx_REG (SImode, reg1 + 2);
+ if ((reg1 + 2) != reg0)
+ {
+ output_asm_insn ("movd\t%1, %0", operands);
+ output_asm_insn ("movd\t%1, %0", xoperands);
+ }
+ else
+ {
+ output_asm_insn ("movd\t%1, %0", xoperands);
+ output_asm_insn ("movd\t%1, %0", operands);
+ }}
+
+ else if (1 == which_alternative) {
+ rtx lo_operands[2] ;
+ rtx hi_operands[2] ;
+
+ lo_operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]));
+ hi_operands[0] = gen_rtx_REG (SImode, REGNO (operands[0]) + 2);
+ lo_operands[1] = simplify_gen_subreg (SImode, operands[1],
+ VOIDmode == GET_MODE (operands[1])
+ ? DImode : GET_MODE (operands[1]), 0);
+ hi_operands[1] = simplify_gen_subreg (SImode, operands[1],
+ VOIDmode == GET_MODE (operands[1])
+ ? DImode : GET_MODE (operands[1]), 4);
+ output_asm_insn ("movd\t%1, %0", lo_operands);
+ output_asm_insn ("movd\t%1, %0", hi_operands);}
+
+ else if (2 == which_alternative) {
+ rtx xoperands[2] ;
+ int reg0 = REGNO (operands[0]), reg1 = -2 ;
+ rtx addr ;
+
+ if (MEM_P (operands[1]))
+ addr = XEXP (operands[1], 0);
+ else
+ addr = NULL_RTX ;
+ switch (GET_CODE (addr))
+ {
+ case REG:
+ case SUBREG:
+ reg1 = REGNO (addr);
+ break ;
+ case PLUS:
+ switch (GET_CODE (XEXP (addr, 0))) {
+ case REG:
+ case SUBREG:
+ reg1 = REGNO (XEXP (addr, 0));
+ break ;
+ case PLUS:
+ reg1 = REGNO (XEXP (XEXP (addr, 0), 0));
+ break ;
+ default:
+ inform (DECL_SOURCE_LOCATION (cfun->decl), "unexpected expression; addr:");
+ debug_rtx (addr);
+ inform (DECL_SOURCE_LOCATION (cfun->decl), "operands[1]:");
+ debug_rtx (operands[1]);
+ inform (DECL_SOURCE_LOCATION (cfun->decl), "generated code might now work\n");
+ break ;}
+ break ;
+ default:
+ break ;
+ }
+
+ xoperands[0] = gen_rtx_REG (SImode, reg0 + 2);
+ xoperands[1] = offset_address (operands[1], GEN_INT (4), 2);
+ gcc_assert ((reg0 + 1) != reg1);
+ if (reg0 != reg1 && (reg1 + 1) != reg0)
+ {
+ output_asm_insn ("loadd\t%1, %0", operands);
+ output_asm_insn ("loadd\t%1, %0", xoperands);
+ }
+ else
+ {
+ output_asm_insn ("loadd\t%1, %0", xoperands);
+ output_asm_insn ("loadd\t%1, %0", operands);
+ }}
+ else
+ {
+ rtx xoperands[2] ;
+ xoperands[0] = offset_address (operands[0], GEN_INT (4), 2);
+ xoperands[1] = gen_rtx_REG (SImode, REGNO (operands[1]) + 2);
+ output_asm_insn ("stord\t%1, %0", operands);
+ output_asm_insn ("stord\t%1, %0", xoperands);
+ }
+ return "" ;
+ }
+ [(set_attr "length" "4, <lImmArithD>, <lImmArithD>, <lImmArithD>")]
+)
+
+; All long (SI, SF) register move, load and store operations
+; The print_operand will take care of printing the register pair
+; when mode is SI/SF and register is in SHORT_REGS
+(define_insn "*mov<mode>_long"
+ [(set (match_operand:LONG 0 "nonimmediate_operand" "=r, r, r, m")
+ (match_operand:LONG 1 "general_operand" "r, <iF>, m, r"))]
+ "register_operand (operands[0], <MODE>mode)
+ || register_operand (operands[1], <MODE>mode)"
+ "@
+ mov<tIsa>\t%1, %0
+ mov<tIsa>\t%1, %0
+ load<tIsa>\t%1, %0
+ stor<tIsa>\t%1, %0"
+ [(set_attr "length" "2,<lImmArith>,<lImmArith>,<lImmArith>")]
+)
+
+;; All short (QI, HI) register move, load and store operations
+(define_insn "*mov<mode>_short"
+ [(set (match_operand:SHORT 0 "nonimmediate_operand" "=r, r, r, m, m")
+ (match_operand:SHORT 1 "general_operand" "r, <iF>, m, r, <LL>"))]
+ "(register_operand (operands[0], <MODE>mode))
+ || (store_operand (operands[0], <MODE>mode)
+ && (register_operand (operands[1], <MODE>mode)
+ || u4bits_operand (operands[1], <MODE>mode)))"
+ "@
+ mov<tIsa>\t%1, %0
+ mov<tIsa>\t%1, %0
+ load<tIsa>\t%1, %0
+ stor<tIsa>\t%1, %0
+ stor<tIsa>\t%1, %0"
+ [(set_attr "length" "2,<lImmArith>,<lImmArith>,<lImmArith>,<lImmArith>")]
+)
+
+;; Compare Instructions
+; Instruction generated compares the operands in reverse order
+; Therefore, while printing the asm, the reverse of the
+; compare condition shall be printed.
+(define_insn "cbranch<mode>4"
+ [(set (pc)
+ (if_then_else (match_operator 0 "ordered_comparison_operator"
+ [(match_operand:CR16IM 1 "register_operand" "r,r")
+ (match_operand:CR16IM 2 "nonmemory_operand" "r,n")])
+ (label_ref (match_operand 3 "" ""))
+ (pc)))
+ (clobber (cc0))]
+ ""
+ "cmp<tIsa>\t%2, %1\;b%d0\t%l3"
+ [(set_attr "length" "6,6")]
+)
+
+(define_expand "cmp<mode>"
+ [(parallel [(set (cc0)
+ (compare (match_operand:CR16IM 0 "register_operand" "")
+ (match_operand:CR16IM 1 "nonmemory_operand" "")))
+ (clobber (match_scratch:HI 2 "=r"))] ) ]
+ ""
+ "")
+
+;; Scond Instructions
+(define_expand "cstore<mode>4"
+ [(set (cc0)
+ (compare (match_operand:CR16IM 2 "register_operand" "")
+ (match_operand:CR16IM 3 "nonmemory_operand" "")))
+ (set (match_operand:HI 0 "register_operand")
+ (match_operator:HI 1 "ordered_comparison_operator"
+ [(cc0) (const_int 0)]))]
+ ""
+ ""
+)
+
+(define_insn "*cmp<mode>_insn"
+ [(set (cc0)
+ (compare (match_operand:CR16IM 0 "register_operand" "r,r")
+ (match_operand:CR16IM 1 "nonmemory_operand" "r,n")))]
+ ""
+ "cmp<tIsa>\t%1, %0"
+ [(set_attr "length" "2,4")]
+)
+
+(define_insn "sCOND_internal"
+ [(set (match_operand:HI 0 "register_operand" "=r")
+ (match_operator:HI 1 "ordered_comparison_operator"
+ [(cc0) (const_int 0)]))]
+ ""
+ "s%d1\t%0"
+ [(set_attr "length" "2")]
+)
+
+;; Jumps and Branches
+(define_insn "indirect_jump_return"
+ [(set (pc)
+ (reg:SI RA_REGNUM))
+ (return)]
+ "reload_completed"
+ "jump\t (ra)"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "jump_return"
+ [(unspec:SI [(const_int 0)] UNSPEC_RETURN_ADDR)
+ (return)]
+ "reload_completed"
+ "jump\t(ra)"
+ [(set_attr "length" "2")]
+)
+
+(define_insn "indirect_jump"
+ [(set (pc)
+ (match_operand:SI 0 "reg_or_sym_operand" "r,i"))]
+ ""
+ "@
+ jump\t%0
+ br\t%a0"
+ [(set_attr "length" "2,6")]
+)
+
+(define_insn "interrupt_return"
+ [(unspec_volatile [(const_int 0)] 0)
+ (return)]
+ ""
+ {
+ return cr16_prepare_push_pop_string (1);
+ }
+ [(set_attr "length" "14")]
+)
+
+(define_insn "jump_to_imm"
+ [(set (pc)
+ (match_operand 0 "jump_imm_operand" "i"))]
+ ""
+ "br\t%c0"
+ [(set_attr "length" "6")]
+)
+
+(define_insn "jump"
+ [(set (pc)
+ (label_ref (match_operand 0 "" "")))]
+ ""
+ "br\t%l0"
+ [(set_attr "length" "6")]
+)
+
+;; Table Jump
+(define_insn "tablejump"
+ [(set (pc)
+ (match_operand:SI 0 "register_operand" "r"))
+ (use (label_ref:SI (match_operand 1 "" "")))]
+ "!flag_pic"
+ "jump\t%0"
+ [(set_attr "length" "2")]
+)
+
+;; Call Instructions
+(define_expand "call"
+ [(call (match_operand:QI 0 "memory_operand" "")
+ (match_operand 1 "" ""))]
+ ""
+ {
+ if (flag_pic && ! legitimate_pic_operand_p (operands[0]))
+ {
+ operands[0] = gen_const_mem (QImode,
+ legitimize_pic_address (XEXP (operands[0], 0), Pmode, 0));
+ emit_call_insn (gen_cr16_call (operands[0], operands[1]));
+ }
+ else
+ emit_call_insn (gen_cr16_call (operands[0], operands[1]));
+ DONE;
+ }
+)
+
+(define_expand "cr16_call"
+ [(parallel
+ [(call (match_operand:QI 0 "memory_operand" "")
+ (match_operand 1 "" ""))
+ (clobber (reg:SI RA_REGNUM))])]
+ ""
+ ""
+)
+
+(define_insn "cr16_call_insn_branch_pic"
+ [(call (mem:QI (match_operand:SI 0 "call_imm_operand" "i"))
+ (match_operand 1 "" ""))
+ (clobber (match_operand:SI 2 "register_operand" "+r"))]
+ "flag_pic == FAR_PIC"
+ {
+ if (GET_CODE (operands[0]) != CONST_INT)
+ return "loadd\t%g0, %2 \n\tjal %2";
+ else
+ return "jal %2";
+ }
+ [(set_attr "length" "8")]
+)
+
+(define_insn "cr16_call_insn_branch"
+ [(call (mem:QI (match_operand:SI 0 "call_imm_operand" "i"))
+ (match_operand 1 "" ""))
+ (clobber (match_operand:SI 2 "register_operand" "+r"))]
+ "flag_pic == 0 || flag_pic == NEAR_PIC"
+ {
+ /* Print the immediate address for bal
+ 'b' is used instead of 'a' to avoid compiler calling
+ the GO_IF_LEGITIMATE_ADDRESS which cannot
+ perform checks on const_int code addresses as it
+ assumes all const_int are data addresses.
+ */
+ if (GET_CODE (operands[0]) != CONST_INT)
+ return "bal (ra), %a0";
+ else
+ operands[4] = GEN_INT ((INTVAL (operands[0]))>>1);
+ return "movd\t%g4,\t(r1,r0)\n\tjal\t(r1,r0)";
+ }
+ [(set_attr "length" "6")]
+)
+
+(define_insn "cr16_call_insn_jump"
+ [(call (mem:QI (match_operand:SI 0 "register_operand" "r"))
+ (match_operand 1 "" ""))
+ (clobber (match_operand:SI 2 "register_operand" "+r"))]
+ ""
+ "jal\t%0"
+ [(set_attr "length" "2")]
+)
+
+;; Call Value Instructions
+
+(define_expand "call_value"
+ [(set (match_operand 0 "general_operand" "")
+ (call (match_operand:QI 1 "memory_operand" "")
+ (match_operand 2 "" "")))]
+ ""
+ {
+ if (flag_pic && !legitimate_pic_operand_p (operands[1]))
+ {
+ operands[1] = gen_const_mem (QImode,
+ legitimize_pic_address (XEXP (operands[1], 0), Pmode, 0));
+ emit_call_insn (gen_cr16_call_value (operands[0], operands[1], operands[2]));
+ }
+ else
+ emit_call_insn (gen_cr16_call_value (operands[0], operands[1], operands[2]));
+ DONE;
+ }
+)
+
+(define_expand "cr16_call_value"
+ [(parallel
+ [(set (match_operand 0 "general_operand" "")
+ (call (match_operand 1 "memory_operand" "")
+ (match_operand 2 "" "")))
+ (clobber (reg:SI RA_REGNUM))])]
+ ""
+ ""
+)
+
+(define_insn "cr16_call_value_insn_branch_pic"
+ [(set (match_operand 0 "" "=g")
+ (call (mem:QI (match_operand:SI 1 "call_imm_operand" "i"))
+ (match_operand 2 "" "")))
+ (clobber (match_operand:SI 3 "register_operand" "+r"))]
+ "flag_pic == FAR_PIC"
+ {
+ if (GET_CODE (operands[1]) != CONST_INT)
+ return "loadd\t%g1, %3 \n\tjal %3";
+ else
+ return "jal %3";
+ }
+ [(set_attr "length" "8")]
+)
+
+(define_insn "cr16_call_value_insn_branch"
+ [(set (match_operand 0 "" "=g")
+ (call (mem:QI (match_operand:SI 1 "call_imm_operand" "i"))
+ (match_operand 2 "" "")))
+ (clobber (match_operand:SI 3 "register_operand" "+r"))]
+ "flag_pic == 0 || flag_pic == NEAR_PIC"
+ {
+ /* Print the immediate address for bal
+ 'b' is used instead of 'a' to avoid compiler calling
+ the GO_IF_LEGITIMATE_ADDRESS which cannot
+ perform checks on const_int code addresses as it
+ assumes all const_int are data addresses.
+ */
+ if (GET_CODE (operands[1]) != CONST_INT)
+ return "bal (ra), %a1";
+ else
+ {
+ operands[4] = GEN_INT ((INTVAL (operands[1]))>>1);
+ return "movd\t%g4,\t(r1,r0)\n\tjal\t(r1,r0)";
+ }
+ }
+ [(set_attr "length" "6")]
+)
+
+
+(define_insn "cr16_call_value_insn_jump"
+ [(set (match_operand 0 "" "=g")
+ (call (mem:QI (match_operand:SI 1 "register_operand" "r"))
+ (match_operand 2 "" "")))
+ (clobber (match_operand:SI 3 "register_operand" "+r"))]
+ ""
+ "jal\t%1"
+ [(set_attr "length" "2")]
+)
+
+
+;; Nop
+(define_insn "nop"
+ [(const_int 0)]
+ ""
+ "nop\t"
+)
+
+;; PIC
+/* When generating pic, we need to load the symbol offset into a register.
+ So that the optimizer does not confuse this with a normal symbol load
+ we use an unspec. The offset will be loaded from a constant pool entry,
+ since that is the only type of relocation we can use. */
+
+(define_insn "unspec_bro_addr"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "" "")] UNSPEC_PIC_ADDR))]
+ ""
+ "movd \t%f1, %0"
+ [(set_attr "length" "4")]
+)
+
+(define_insn "unspec_got_addr"
+ [(set (match_operand:SI 0 "register_operand" "=r")
+ (unspec:SI [(match_operand 1 "" "")] UNSPEC_PIC_LOAD_ADDR))]
+ ""
+ "loadd \t%g1, %0"
+ [(set_attr "length" "6")]
+)
diff --git a/gcc/config/cr16/cr16.opt b/gcc/config/cr16/cr16.opt
new file mode 100644
index 0000000..a006b01
--- /dev/null
+++ b/gcc/config/cr16/cr16.opt
@@ -0,0 +1,51 @@
+; Options for the National Semiconductor CR16 port of the compiler.
+; Copyright (C) 2012 Free Software Foundation, Inc.
+; Contributed by KPIT Cummins Infosystems Limited.
+;
+; 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/>.
+
+msim
+Target
+-msim Use simulator runtime
+
+mbit-ops
+Target Report Mask(BIT_OPS)
+Generate SBIT, CBIT instructions
+
+mmac
+Target Report Mask(MAC)
+Support multiply accumulate instructions
+
+mdebug-addr
+Target RejectNegative Var(TARGET_DEBUG_ADDR) Undocumented
+
+mdata-model=
+Target RejectNegative JoinedOrMissing Var(cr16_data_model)
+Treat data references as near, far or medium. medium is default
+
+mcr16c
+Target RejectNegative Mask(CR16C)
+Generate code for CR16C architecture
+
+mcr16cplus
+Target RejectNegative InverseMask(CR16C,CR16CP)
+Generate code for CR16C+ architecture (Default)
+
+mint32
+Target RejectNegative Mask(INT32)
+Treat integers as 32-bit.
+
diff --git a/gcc/config/cr16/predicates.md b/gcc/config/cr16/predicates.md
new file mode 100644
index 0000000..d399c33
--- /dev/null
+++ b/gcc/config/cr16/predicates.md
@@ -0,0 +1,225 @@
+;; Predicates of machine description for CR16.
+;; Copyright (C) 2012 Free Software Foundation, Inc.
+;; Contributed by KPIT Cummins Infosystems Limited.
+;;
+;; 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/>.
+
+;; Predicates
+
+;; Predicates for sbit/cbit instructions
+;; bit operand used for the generation of bit insn generation
+(define_predicate "bit_operand"
+ (match_code "mem")
+{
+ return ((GET_CODE (op) == MEM && OK_FOR_Z (op)));
+})
+
+;; Unsigned 4-bits constant int or double value.
+(define_predicate "u4bits_operand"
+ (match_code "const_int,const_double")
+{
+ if (GET_CODE (op) == CONST_DOUBLE)
+ return cr16_const_double_ok (op);
+ return (UNSIGNED_INT_FITS_N_BITS(INTVAL (op), 4)) ? 1 : 0;
+})
+
+;; Operand is a constant integer where
+;; only one bit is set to 1.
+(define_predicate "one_bit_operand"
+ (match_code "const_int")
+{
+ unsigned int val;
+
+ val = INTVAL (op);
+ if (mode == QImode)
+ val &= 0xff;
+ else if (mode == HImode)
+ val &= 0xffff;
+ else
+ gcc_unreachable();
+
+ if (val != 0)
+ return (val & (val - 1)) == 0; /* true if only one bit is set. */
+ else
+ return 0;
+})
+
+;; Operand is a constant integer where
+;; only one bit is set to 0.
+(define_predicate "rev_one_bit_operand"
+ (match_code "const_int")
+{
+ unsigned int val;
+
+ val = ~INTVAL (op); /* Invert and use. */
+ if (mode == QImode)
+ val &= 0xff;
+ else if (mode == HImode)
+ val &= 0xffff;
+ else
+ gcc_unreachable();
+
+ if (val != 0)
+ return (val & (val - 1)) == 0; /* true if only one bit is set. */
+ else
+ return 0;
+})
+
+;; Predicates for shift instructions
+;; Immediate operand predicate for count in shift operations.
+;; Immediate shall be 3-bits in case operand to be operated on
+;; is a qi mode operand.
+(define_predicate "shift_qi_imm_operand"
+ (match_code "const_int")
+{
+ return (UNSIGNED_INT_FITS_N_BITS(INTVAL (op), 3)) ? 1 : 0;
+})
+
+;; Immediate shall be 4-bits in case operand to be operated on
+;; is a hi mode operand.
+(define_predicate "shift_hi_imm_operand"
+ (match_code "const_int")
+{
+ return (UNSIGNED_INT_FITS_N_BITS(INTVAL (op), 4)) ? 1 : 0;
+})
+
+;; Immediate shall be 3-bits in case operand to be operated on
+;; is a si mode operand.
+(define_predicate "shift_si_imm_operand"
+ (match_code "const_int")
+{
+ return (UNSIGNED_INT_FITS_N_BITS(INTVAL (op), 5)) ? 1 : 0;
+})
+
+;; Predicates for jump/call instructions
+;; Jump immediate cannot be more than 24-bits
+(define_predicate "jump_imm_operand"
+ (match_code "const_int")
+{
+ return (UNSIGNED_INT_FITS_N_BITS(INTVAL (op), 24)) ? 1 : 0;
+})
+
+;; Call immediate cannot be more than 24-bits
+(define_predicate "call_imm_operand"
+ (match_operand 0 "immediate_operand")
+{
+ if (GET_CODE (op) != CONST_INT) return 1;
+ return (UNSIGNED_INT_FITS_N_BITS(INTVAL (op), 24)) ? 1 : 0;
+})
+
+;; Operand is register or 4-bit immediate operand
+(define_predicate "reg_or_u4bits_operand"
+ (ior (match_operand 0 "u4bits_operand")
+ (match_operand 0 "register_operand")))
+
+;; Operand is a register or symbol reference
+(define_predicate "reg_or_sym_operand"
+ (ior (match_code "symbol_ref")
+ (match_operand 0 "register_operand")))
+
+;; Operand is a non stack pointer register
+(define_predicate "nosp_reg_operand"
+ (and (match_operand 0 "register_operand")
+ (match_test "REGNO (op) != SP_REGNUM")))
+
+(define_predicate "hard_reg_operand"
+ (and (match_operand 0 "register_operand")
+ (match_test "REGNO (op) <= 15")))
+
+;; Operand is a memory reference and
+;; not a push operand.
+(define_predicate "store_operand"
+ (and (match_operand 0 "memory_operand")
+ (not (match_operand 0 "push_operand"))))
+
+;; Helper predicate
+(define_predicate "reg_or_int_operand"
+ (ior (match_code "const_int")
+ (match_operand 0 "register_operand")))
+
+;;
+;;
+;; Atithmetic/logical predicates
+
+;; QI Helper
+(define_predicate "arith_qi_operand"
+ (match_code "const_int")
+{
+ return (IN_RAN(INTVAL (op), 0, 15) && ((INTVAL (op) != 9)
+ || (INTVAL (op) != 11))) ? 1 : 0 ;
+})
+
+;;QI Reg, subreg(reg) or const_int.
+(define_predicate "reg_qi_int_operand"
+ (ior (match_operand 0 "arith_qi_operand")
+ (match_operand 0 "register_operand")))
+
+;; HI Helper
+(define_predicate "arith_hi_operand"
+ (match_code "const_int")
+{
+ return (IN_RAN(INTVAL (op), -32768, 32768) ) ? 1 : 0 ;
+})
+
+;;HI Reg, subreg(reg) or const_int.
+(define_predicate "reg_hi_int_operand"
+ (ior (match_operand 0 "arith_hi_operand")
+ (match_operand 0 "register_operand")))
+
+;;SI Reg, subreg(reg) or const_int.
+(define_predicate "reg_si_int_operand"
+ (ior (match_operand 0 "const_int_operand")
+ (match_operand 0 "register_operand")))
+
+;;
+;; Shift predicates
+
+;; QI Helper
+(define_predicate "shift_qi_operand"
+ (match_code "const_int")
+{
+ return (IN_RAN(INTVAL (op), 0, 7) ) ? 1 : 0;
+})
+
+;;QI Reg, subreg(reg) or const_int.
+(define_predicate "shift_reg_qi_int_operand"
+ (ior (match_operand 0 "shift_qi_operand")
+ (match_operand 0 "register_operand")))
+
+;; HI Helper
+(define_predicate "shift_hi_operand"
+ (match_code "const_int")
+{
+ return (IN_RAN(INTVAL (op), 0, 15) ) ? 1 : 0 ;
+})
+
+;;HI Reg, subreg(reg) or const_int.
+(define_predicate "shift_reg_hi_int_operand"
+ (ior (match_operand 0 "shift_hi_operand")
+ (match_operand 0 "register_operand")))
+
+;; SI Helper
+(define_predicate "shift_si_operand"
+ (match_code "const_int")
+{
+ return (IN_RAN(INTVAL (op), 0, 31) ) ? 1 : 0;
+})
+
+;;SI Reg, subreg(reg) or const_int.
+(define_predicate "shift_reg_si_int_operand"
+ (ior (match_operand 0 "shift_si_operand")
+ (match_operand 0 "register_operand")))
diff --git a/gcc/config/cr16/t-cr16 b/gcc/config/cr16/t-cr16
new file mode 100644
index 0000000..ff9b677
--- /dev/null
+++ b/gcc/config/cr16/t-cr16
@@ -0,0 +1,25 @@
+# CR16 Target Makefile
+# Copyright (C) 2012 Free Software Foundation, Inc.
+# Contributed by KPIT Cummins Infosystems Limited.
+#
+# 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/>.
+
+MULTILIB_OPTIONS = fPIC mint32
+MULTILIB_DIRNAMES = far-pic int32
+MULTILIB_MATCHES =
+MULTILIB_EXTRA_OPTS = mcr16cplus mdata-model=far
+
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index b8c4696..e821041 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -2723,7 +2723,7 @@ This attribute is ignored for R8C target.
@item interrupt
@cindex interrupt handler functions
-Use this attribute on the ARM, AVR, Epiphany, M32C, M32R/D, m68k, MeP, MIPS,
+Use this attribute on the ARM, AVR, CR16, Epiphany, M32C, M32R/D, m68k, MeP, MIPS,
RL78, RX and Xstormy16 ports to indicate that the specified function is an
interrupt handler. The compiler will generate function entry and exit
sequences suitable for use in an interrupt handler when this attribute
diff --git a/gcc/doc/install.texi b/gcc/doc/install.texi
index da84758..4a85397 100644
--- a/gcc/doc/install.texi
+++ b/gcc/doc/install.texi
@@ -3272,6 +3272,29 @@ is available at @uref{http://blackfin.uclinux.org}
@html
<hr />
@end html
+@heading @anchor{cr16}CR16
+
+The CR16 CompactRISC architecture is a 16-bit architecture. This architecture is
+used in embedded applications.
+
+@ifnothtml
+@xref{CR16 Options,, CR16 Options, gcc, Using and Porting the GNU Compiler
+Collection (GCC)},
+@end ifnothtml
+
+@ifhtml
+See ``CR16 Options'' in the main manual for a list of CR16-specific options.
+@end ifhtml
+
+Use @samp{configure --target=cr16-elf --enable-languages=c,c++} to configure
+GCC@ for building a CR16 elf cross-compiler.
+
+Use @samp{configure --target=cr16-uclinux --enable-languages=c,c++} to configure
+GCC@ for building a CR16 uclinux cross-compiler.
+
+@html
+<hr />
+@end html
@heading @anchor{cris}CRIS
CRIS is the CPU architecture in Axis Communications ETRAX system-on-a-chip
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 9eb9d32..6105710 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -524,6 +524,12 @@ Objective-C and Objective-C++ Dialects}.
-melf -maout -melinux -mlinux -sim -sim2 @gol
-mmul-bug-workaround -mno-mul-bug-workaround}
+@emph{CR16 Options}
+@gccoptlist{-mmac @gol
+-mcr16cplus -mcr16c @gol
+-msim -mint32 -mbit-ops
+-mdata-model=@var{model}}
+
@emph{Darwin Options}
@gccoptlist{-all_load -allowable_client -arch -arch_errors_fatal @gol
-arch_only -bind_at_load -bundle -bundle_loader @gol
@@ -10307,6 +10313,7 @@ platform.
* Blackfin Options::
* C6X Options::
* CRIS Options::
+* CR16 Options::
* Darwin Options::
* DEC Alpha Options::
* DEC Alpha/VMS Options::
@@ -11634,6 +11641,46 @@ Like @option{-sim}, but pass linker options to locate initialized data at
0x40000000 and zero-initialized data at 0x80000000.
@end table
+@node CR16 Options
+@subsection CR16 Options
+@cindex CR16 Options
+
+These options are defined specifically for the CR16 ports.
+
+@table @gcctabopt
+
+@item -mmac
+@opindex mmac
+Enable the use of multiply-accumulate instructions. Disabled by default.
+
+@item -mcr16cplus
+@itemx -mcr16c
+@opindex mcr16cplus
+@opindex mcr16c
+Generate code for CR16C or CR16C+ architecture. CR16C+ architecture
+is default.
+
+@item -msim
+@opindex msim
+Links the library libsim.a which is in compatible with simulator. Applicable
+to elf compiler only.
+
+@item -mint32
+@opindex mint32
+Choose integer type as 32-bit wide.
+
+@item -mbit-ops
+@opindex mbit-ops
+Generates sbit/cbit instructions for bit manipulations.
+
+@item -mdata-model=@var{model}
+@opindex mdata-model
+Choose a data model. The choices for @var{model} are @samp{near},
+@samp{far} or @samp{medium}. @samp{medium} is default.
+However, @samp{far} is not valid when -mcr16c option is chosen as
+CR16C architecture does not support far data model.
+@end table
+
@node Darwin Options
@subsection Darwin Options
@cindex Darwin options
diff --git a/gcc/doc/md.texi b/gcc/doc/md.texi
index afdc3e3..92c1b28 100644
--- a/gcc/doc/md.texi
+++ b/gcc/doc/md.texi
@@ -1843,6 +1843,40 @@ Matches control register values to switch fp mode, which are encapsulated in
@code{UNSPEC_FP_MODE}.
@end table
+@item CR16 Architecture---@file{config/cr16/cr16.h}
+@table @code
+
+@item b
+Registers from r0 to r14 (registers without stack pointer)
+
+@item t
+Register from r0 to r11 (all 16-bit registers)
+
+@item p
+Register from r12 to r15 (all 32-bit registers)
+
+@item I
+Signed constant that fits in 4 bits
+
+@item J
+Signed constant that fits in 5 bits
+
+@item K
+Signed constant that fits in 6 bits
+
+@item L
+Unsigned constant that fits in 4 bits
+
+@item M
+Signed constant that fits in 32 bits
+
+@item N
+Check for 64 bits wide constants for add/sub instructions
+
+@item G
+Floating point constant that is legal for store immediate
+@end table
+
@item Hewlett-Packard PA-RISC---@file{config/pa/pa.h}
@table @code
@item a