This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: New: CR16 Port (Take 3)


Hello Michael,
Sorry for delay in submitting the modified patch. I have incorporated all suggestions
that I have mentioned in the previous mail (See attached). Only one exception is that
I did not know where to document that this port supports only 32-bit floating point.
It would be helpful, if you can point the right place.
Please find the new patch attached: cr16-port_gcc_16oct07.diff
I have run the "compile-only" gcc testsuite for the new patch. There are no additional
failures due to modification.


Please review the patch and suggest if this is OK for trunk.

Thanks in advance,
Pompa

Pompapathi V Gadad wrote:
Hello Michael,
Thanks for reviewing in such detail. Please see my answers below. I will
incorporate many of your suggestions immediately.
Thanks,
Pompa

About your general comments:
>1) Your formatting of the lisp code in the cr16.md is inconsistant. The
> simplest approach is to go in with gnu emacs, and hit tab at the beginning
> of the line to let emacs reformat it. For example, instead of:
I will make necessary modification.


>3) Some places, particularly in the .md file you don't have the space before
> the '(' in calls. For example instead of:
I will make necessary modification.
>4) You call abort () in several places. Those should be changed to
> gcc_unreachable ().
I guess, this is very important. I will do it right away.


>5) There are several places that when you split up a long line, you have the
> operator at the end of the line instead of at the beginning of the next
> line. For example instead of:
I will make necessary modification.
About your specific comments:
>1) I am somewhat wary of you mov<mode> code. You probably need to define the
> appropriate reload_{out,in}<mode> operations to properly move stuff between
> registers, and do the reloading.
Can you please explain what was the observation. This could be a major change to the port.
Therefore I would want to recode it is carefully, if necessary.


>2) Technically fixing the size of double to 32-bits violates ANSI/ISO C, but
> having supported 16-bit embedded platforms in the past, floating point is
> often just not done in that environment. You might get several test
> failures that want to use 64-bit floating point. I see that you don't
> support trampolines either, you might document this restrictions in the
> texinfo file on CR16 (and any other restrictions that you have).
Well, I can't help. CR16 has no support for 64-bit arithmetic and I guess, it is
not intended as well. I will document the unsupported features/restrictions as well.


>3) SIGNED_INT_FITS_N_BITS and UNSIGNED_INT_FITS_N_BITS uses 'long long'. You
> should use HOST_WIDE_INT instead of long long.
Important point. I will do it right away.


>4) You defined REG_CLASS_FROM_LETTER. At some point in the future, you
> probably should migrate this to using define_register_constraint in the .md
> file.
May be it is right time to migrate. I will plan for this.


>5) On the insv define_expand, you probably should define 2 new predicates and
> eliminate the tests inside of the {}. One predicate would only match a
> const_int 1, and the other would match 0 or 1. So instead of:
Your suggestion is much better. I will incorporate and test it.


>6) cr16_prepare_push_pop_string allocates memory which is never freed up.
> Either use a static buffer, or use asm_printf and print out the string
> directly.
Yes. This is an issue. I will incorporate your suggestion.


>7) The HI division is generic, this might be useful to move into libgcc2 for
> other 16-bit ports (I dunno whether there are more 16 bit ports).
I did not want to change the files that would affect other ports.
May be in future I will submit another patch.


>8) In ashr<mode> and lshr<mode>, you use copy_to_mode_reg, when instead you
> should use predicates to restrict the type to the appropriate types:
I will incorporate your suggestion.





Index: doc/extend.texi
===================================================================
--- doc/extend.texi	(revision 129377)
+++ doc/extend.texi	(working copy)
@@ -2327,7 +2327,7 @@ This attribute is ignored for R8C target
 
 @item interrupt
 @cindex interrupt handler functions
-Use this attribute on the ARM, AVR, C4x, CRX, M32C, M32R/D, m68k, MS1,
+Use this attribute on the ARM, AVR, C4x, CR16, CRX, M32C, M32R/D, m68k, MS1,
 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
Index: doc/invoke.texi
===================================================================
--- doc/invoke.texi	(revision 129377)
+++ doc/invoke.texi	(working copy)
@@ -453,6 +453,11 @@ Objective-C and Objective-C++ Dialects}.
 -msep-data  -mno-sep-data  -mlong-calls  -mno-long-calls @gol
 -mfast-fp -minline-plt}
 
+@emph{CR16 Options}
+@gccoptlist{-mmac @gol
+-mcr16cplus -mcr16c @gol
+-mdata-model=@var{model}}
+
 @emph{CRIS Options}
 @gccoptlist{-mcpu=@var{cpu}  -march=@var{cpu}  -mtune=@var{cpu} @gol
 -mmax-stack-frame=@var{n}  -melinux-stacksize=@var{n} @gol
@@ -8092,6 +8097,7 @@ platform.
 * ARM Options::
 * AVR Options::
 * Blackfin Options::
+* CR16 Options::
 * CRIS Options::
 * CRX Options::
 * Darwin Options::
@@ -8713,6 +8719,33 @@ Enable inlining of PLT entries in functi
 not known to bind locally.  It has no effect without @option{-mfdpic}.
 @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 -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 CRIS Options
 @subsection CRIS Options
 @cindex CRIS Options
Index: doc/md.texi
===================================================================
--- doc/md.texi	(revision 129377)
+++ doc/md.texi	(working copy)
@@ -1750,6 +1750,28 @@ Integer constant in the range -6 @dots{}
 A memory address based on Y or Z pointer with displacement.
 @end table
 
+@item CR16 Architecture---@file{config/cr16/cr16.h}
+@table @code
+
+@item b
+Registers from r0 to r14 (registers without stack pointer)
+
+@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 G
+Floating point constant that is legal for store immediate
+@end table
+
 @item CRX Architecture---@file{config/crx/crx.h}
 @table @code
 
Index: doc/install.texi
===================================================================
--- doc/install.texi	(revision 129377)
+++ doc/install.texi	(working copy)
@@ -2838,6 +2838,31 @@ can also be obtained from:
 @html
 <hr />
 @end html
+
+@html
+<hr />
+@end html
+@heading @anchor{cr16}CR16
+
+The CR16 CompactRISC architecture is a 16-bit architecture. This architecture 
+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 cross-compiler.
+
+@html
+<hr />
+@end html
+
 @heading @anchor{cris}CRIS
 
 CRIS is the CPU architecture in Axis Communications ETRAX system-on-a-chip
Index: config.gcc
===================================================================
--- config.gcc	(revision 129377)
+++ config.gcc	(working copy)
@@ -849,6 +849,11 @@ c4x-* | tic4x-*)
 	c_target_objs="c4x-c.o"
 	cxx_target_objs="c4x-c.o"
 	;;
+cr16-*-elf)
+	tm_file="elfos.h ${tm_file}"
+	extra_parts="crtbegin.o crtend.o"
+	use_collect2=no
+	;;
 cris-*-aout)
 	tm_file="dbxelf.h ${tm_file} cris/aout.h"
 	gas=yes
Index: config/cr16/cr16.h
===================================================================
--- config/cr16/cr16.h	(revision 0)
+++ config/cr16/cr16.h	(revision 0)
@@ -0,0 +1,560 @@
+/* Definitions of target machine for GNU compiler, for CR16.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+   Originally modeled on CRX design.
+   Used lots of ideas from ARM, CRX, I386, stormy16 ports.
+
+   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
+
+/* Controlling the driver */
+
+#define CC1PLUS_SPEC "%{!frtti:-fno-rtti} \
+    %{!fenforce-eh-specs:-fno-enforce-eh-specs} \
+    %{!fexceptions:-fno-exceptions} \
+    %{!fthreadsafe-statics:-fno-threadsafe-statics}"
+
+#undef  STARTFILE_SPEC
+#define STARTFILE_SPEC "crti.o%s crtbegin.o%s"
+
+#undef  ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+#undef  MATH_LIBRARY
+#define MATH_LIBRARY ""
+
+/* 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__");    \
+  }                                        \
+while (0)
+#endif
+
+#define TARGET_VERSION fputs (" (CR16/ELF)", stderr);
+
+#define CAN_DEBUG_WITHOUT_FP
+
+#define OVERRIDE_OPTIONS  cr16_override_options ()
+
+#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  (!optimize_size ? BIGGEST_ALIGNMENT : BITS_PER_WORD)
+
+/* 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 32
+
+/* 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-aligned so 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       16
+
+#define SHORT_TYPE_SIZE     16
+
+#define LONG_TYPE_SIZE      32
+
+#define LONG_LONG_TYPE_SIZE 32
+
+#define FLOAT_TYPE_SIZE     32
+
+#define DOUBLE_TYPE_SIZE    32
+
+#define LONG_DOUBLE_TYPE_SIZE  32
+
+#define DEFAULT_SIGNED_CHAR 1
+
+#define SIZE_TYPE           "long unsigned int"
+
+#define PTRDIFF_TYPE        "long int"
+
+/* 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
+
+/* Register usage */
+
+/* First 32-bit register is R12 */
+#define CR16_FIRST_DWORD_REGISTER   12
+
+#define FIRST_PSEUDO_REGISTER       17
+
+/* 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  cc */                       \
+    0,  0,  0,  0,  1,  1                           \
+  }
+
+/* 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  cc */                       \
+    0,  0,  0,  1,  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)
+
+/* So far no patterns for moving CCMODE data are available */
+#define AVOID_CCMODE_COPIES
+
+/* 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)                 \
+    ( (((SRC >= CR16_FIRST_DWORD_REGISTER)              \
+         && (DEST >= CR16_FIRST_DWORD_REGISTER))        \
+       || ((SRC < CR16_FIRST_DWORD_REGISTER)            \
+            && (DEST < CR16_FIRST_DWORD_REGISTER)))     \
+      ? (!cr16_interrupt_function_p () || (df_regs_ever_live_p (DEST))) : 0)
+
+#define MODES_TIEABLE_P(MODE1, MODE2)  1
+
+enum reg_class
+{
+  NO_REGS,
+  SHORT_REGS,
+  LONG_REGS,
+  NOSP_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",    \
+    "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  */  \
+    {0x0000FFFF}, /* GENERAL_REGS: 0 - 15  */  \
+    {0x0000FFFF}  /* ALL_REGS :    0 - 15  */  \
+  }
+
+#define REGNO_REG_CLASS(REGNO)  cr16_regno_reg_class (REGNO)
+
+#define BASE_REG_CLASS      GENERAL_REGS
+
+#define INDEX_REG_CLASS     LONG_REGS
+
+#define REGNO_OK_FOR_BASE_P(REGNO)                     \
+  (((REGNO) < FIRST_PSEUDO_REGISTER)                   \
+   || (reg_renumber && ((unsigned) reg_renumber[REGNO] \
+                        < FIRST_PSEUDO_REGISTER)))
+
+/* 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)
+
+#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)
+
+/* 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 FRAME_POINTER_REQUIRED (current_function_calls_alloca)
+
+#define ELIMINABLE_REGS                            \
+  {                                                \
+    { ARG_POINTER_REGNUM,   STACK_POINTER_REGNUM}, \
+    { ARG_POINTER_REGNUM,   FRAME_POINTER_REGNUM}, \
+    { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM}  \
+  }
+
+#define CAN_ELIMINATE(FROM, TO) \
+ ((TO) == STACK_POINTER_REGNUM ? !frame_pointer_needed : 1)
+
+#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)
+
+#define RETURN_POPS_ARGS(FNDECL, FUNTYPE, SIZE)   0
+
+#define FUNCTION_ARG(CUM, MODE, TYPE, NAMED) \
+  ((rtx) cr16_function_arg (&(CUM), (MODE), (TYPE), (NAMED)))
+
+#ifndef CUMULATIVE_ARGS
+struct cumulative_args
+{
+  int ints;
+};
+
+#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_ADVANCE(CUM, MODE, TYPE, NAMED) \
+  cr16_function_arg_advance (&(CUM), (MODE), (TYPE), (NAMED))
+
+#define FUNCTION_ARG_REGNO_P(REGNO)  cr16_function_arg_regno_p (REGNO)
+
+/* Returning function value */
+
+/* On the CR16, the return value is in R0 */
+#define FUNCTION_VALUE(VALTYPE, FUNC) \
+    gen_rtx_REG (TYPE_MODE (VALTYPE), 0)
+
+#define LIBCALL_VALUE(MODE)     gen_rtx_REG (MODE, 0)
+
+#define FUNCTION_VALUE_REGNO_P(N)   ((N) == 0)
+
+#define CR16_STRUCT_VALUE_REGNUM  0
+
+/* 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
+
+#define INITIALIZE_TRAMPOLINE(addr, fnaddr, static_chain)   \
+{                                                           \
+    sorry ("Trampoline support for CR16");                  \
+}
+
+/* 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 REG_OK_FOR_BASE_P(X)    REGNO_OK_FOR_BASE_P (REGNO (X))
+#define REG_OK_FOR_INDEX_P(X)   REGNO_OK_FOR_INDEX_P (REGNO (X))
+#else /* not REG_OK_STRICT */
+#define REG_OK_FOR_BASE_P(X)    1
+#define REG_OK_FOR_INDEX_P(X)   1
+#endif /* not REG_OK_STRICT */
+
+#ifdef REG_OK_STRICT
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL)    \
+{                                                   \
+  if (cr16_legitimate_address_p (MODE, X, 1))       \
+      goto LABEL;                                   \
+}
+#else /* not REG_OK_STRICT */
+#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL)    \
+{                                                   \
+  if (cr16_legitimate_address_p (MODE, X, 0))       \
+      goto LABEL;                                   \
+}
+#endif /* not REG_OK_STRICT */
+
+/* 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 */
+#define LEGITIMIZE_ADDRESS(X, OLDX, MODE, WIN)
+
+/* 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)
+
+/* 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 */
+#define LEGITIMATE_CONSTANT_P(X)  1
+
+/* Relative costs of operations */
+#define MEMORY_MOVE_COST(MODE, CLASS, IN) \
+  cr16_memory_move_cost (MODE, CLASS, IN)
+
+/* Moving to processor register flushes pipeline - thus asymmetric */
+#define REGISTER_MOVE_COST(MODE, FROM, TO) ((TO != GENERAL_REGS) ? 8 : 2)
+/* Assume best case (branch predicted) */
+#define BRANCH_COST       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 */
+
+#define PIC_OFFSET_TABLE_REGNUM  12
+
+#define LEGITIMATE_PIC_OPERAND_P(X)  1
+
+/* Assembler format */
+
+#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"
+
+/* Instruction output */
+
+#define REGISTER_NAMES                                     \
+  {                                                        \
+    "r0",  "r1",  "r2",  "r3",  "r4",  "r5",  "r6",  "r7", \
+    "r8",  "r9",  "r10", "r11", "r12", "r13", "ra",  "sp", \
+    "cc"                                                   \
+  }
+
+#define PRINT_OPERAND(STREAM, X, CODE) \
+  cr16_print_operand (STREAM, X, CODE)
+
+#define PRINT_OPERAND_ADDRESS(STREAM, ADDR) \
+  cr16_print_operand_address (STREAM, ADDR)
+
+/* 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
+
+/* External declarations for variables defined in CR16.C */
+
+extern rtx cr16_compare_op0;    /* operand 0 for comparisons */
+extern rtx cr16_compare_op1;    /* operand 1 for comparisons */
+
+#endif /* End of GCC_CR16_H */
Index: config/cr16/crti.s
===================================================================
--- config/cr16/crti.s	(revision 0)
+++ config/cr16/crti.s	(revision 0)
@@ -0,0 +1,46 @@
+/* Specialized code needed to support construction and destruction of
+   file-scope objects in C++ and Java code, and to support exception handling.
+   Copyright (C) 1999, 2007 Free Software Foundation, Inc.
+   Contributed by Charles-Antoine Gauthier (charles.gauthier@iit.nrc.ca).
+
+   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/>.  */
+
+/* As a special exception, if you link this library with files
+   compiled with GCC to produce an executable, this does not cause
+   the resulting executable to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/*
+ * This file just supplies function prologues for the .init and .fini
+ * sections.  It is linked in before crtbegin.o.
+ */
+
+	.file   "crti.o"
+	.ident  "GNU C crti.o"
+
+	.section .init
+	.globl  _init
+	.type   _init,@function
+_init:
+        push ra
+	.section .fini
+	.globl  _fini
+	.type   _fini,@function
+_fini:
+        push ra
+	
Index: config/cr16/fixunssfsi.c
===================================================================
--- config/cr16/fixunssfsi.c	(revision 0)
+++ config/cr16/fixunssfsi.c	(revision 0)
@@ -0,0 +1,33 @@
+/* Libgcc Target specific implementation.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+   Used of ideas from H8300 port.
+
+   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/>.  */
+
+/* The libgcc2.c implementation gets confused by our type setup */
+
+long __fixunssfsi (float a);
+
+long
+__fixunssfsi (float a)
+{
+  if (a >= (float) 32768L)
+    return (long) (a - 32768L) + 32768L;
+  return (long) a;
+}
+
Index: config/cr16/cr16-protos.h
===================================================================
--- config/cr16/cr16-protos.h	(revision 0)
+++ config/cr16/cr16-protos.h	(revision 0)
@@ -0,0 +1,115 @@
+/* Prototypes for exported functions defined in cr16.c
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+   Originally modeled on CRX design.
+   Used lots of ideas from ARM, CRX, I386, stormy16 ports.
+
+   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
+
+/* 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
+extern void cr16_function_arg_advance (CUMULATIVE_ARGS *, 
+                                       enum machine_mode, tree, int);
+#ifdef RTX_CODE
+extern void cr16_init_cumulative_args (CUMULATIVE_ARGS *, tree, rtx);
+extern rtx cr16_function_arg (struct cumulative_args *, 
+                              enum machine_mode, tree, int);
+#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 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_legitimate_address_p (enum machine_mode, rtx, int);
+
+extern int cr16_const_double_ok (rtx op);
+
+/* Instruction output */
+extern void cr16_print_operand (FILE *, rtx, int);
+extern void cr16_print_operand_address (FILE *, rtx);
+
+/* Misc functions called from cr16.md */
+extern rtx cr16_expand_compare (enum rtx_code, enum machine_mode);
+extern void cr16_expand_branch (enum rtx_code, rtx);
+extern void cr16_expand_scond (enum rtx_code, rtx);
+
+extern void cr16_expand_movmem_single (rtx, rtx, rtx, rtx, rtx, 
+                                       unsigned HOST_WIDE_INT *);
+extern int cr16_expand_movmem (rtx, rtx, rtx, rtx);
+#endif /* RTX_CODE */
+
+/* Routines to compute costs */
+extern int cr16_memory_move_cost (enum machine_mode, enum reg_class, int);
+
+/* 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);
+
+/* Handling the "interrupt" attribute */
+extern int cr16_interrupt_function_p (void);
+
+/* Validate data model option */
+extern void cr16_override_options (void);
+
+extern bool cr16_is_data_model (enum data_model_type);
+
+#endif /* not GCC_CR16_PROTOS_H */
Index: config/cr16/crtn.s
===================================================================
--- config/cr16/crtn.s	(revision 0)
+++ config/cr16/crtn.s	(revision 0)
@@ -0,0 +1,40 @@
+/* Specialized code needed to support construction and destruction of
+   file-scope objects in C++ and Java code, and to support exception handling.
+   Copyright (C) 1999, 2007 Free Software Foundation, Inc.
+   Contributed by Charles-Antoine Gauthier (charles.gauthier@iit.nrc.ca).
+
+   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/>.  */
+
+/* As a special exception, if you link this library with files
+   compiled with GCC to produce an executable, this does not cause
+   the resulting executable to be covered by the GNU General Public License.
+   This exception does not however invalidate any other reasons why
+   the executable file might be covered by the GNU General Public License.  */
+
+/*
+ * This file supplies function epilogues for the .init and .fini sections.
+ * It is linked in after all other files.
+ */
+
+	.file   "crtn.o"
+	.ident  "GNU C crtn.o"
+
+	.section .init
+        popret ra
+
+	.section .fini
+        popret ra
Index: config/cr16/divmodhi3.c
===================================================================
--- config/cr16/divmodhi3.c	(revision 0)
+++ config/cr16/divmodhi3.c	(revision 0)
@@ -0,0 +1,110 @@
+/* Libgcc Target specific implementation - Emulating div and mod.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+   Used ideas from implmentation of udivmodsi4.
+
+   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/>.  */
+
+/* Emulate the division and modulus operation. */
+
+unsigned int
+udivmodhi4 (unsigned int num, unsigned int den, int modwanted)
+{
+  unsigned int bit = 1;
+  unsigned int res = 0;
+
+  while (den < num && bit && !(den & (1 << 15)))
+    {
+      den <<= 1;
+      bit <<= 1;
+    }
+  while (bit)
+    {
+      if (num >= den)
+        {
+          num -= den;
+          res |= bit;
+        }
+      bit >>= 1;
+      den >>= 1;
+    }
+
+  if (modwanted)
+    return num;
+  return res;
+}
+
+int
+__divhi3 (int a, int b)
+{
+  int neg = 0;
+  int res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = !neg;
+    }
+
+  if (b < 0)
+    {
+      b = -b;
+      neg = !neg;
+    }
+
+  res = udivmodhi4 (a, b, 0);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+int
+__modhi3 (int a, int b)
+{
+  int neg = 0;
+  int res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = 1;
+    }
+
+  if (b < 0)
+    b = -b;
+
+  res = udivmodhi4 (a, b, 1);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+int
+__udivhi3 (int a, int b)
+{
+  return udivmodhi4 (a, b, 0);
+}
+
+int
+__umodhi3 (int a, int b)
+{
+  return udivmodhi4 (a, b, 1);
+}
Index: config/cr16/cr16.md
===================================================================
--- config/cr16/cr16.md	(revision 0)
+++ config/cr16/cr16.md	(revision 0)
@@ -0,0 +1,969 @@
+;; GCC machine description for CR16.
+;; Copyright (C) 2007 Free Software Foundation, Inc.
+;; Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+;; Originally modeled on CRX design.
+;; Used lots of ideas from ARM, CRX, I386, stormy16 ports.
+;;
+;; 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
+   (CC_REGNUM 16) ; Condition code register
+  ]
+)
+
+;;  Constraints
+
+(define_constraint "I"
+ "A 4-bit signed constant"
+ (and (match_code "const_int")
+      (match_test "SIGNED_INT_FITS_N_BITS (ival, 4)")))
+
+(define_constraint "J"
+ "A 5-bit signed constant"
+ (and (match_code "const_int")
+      (match_test "SIGNED_INT_FITS_N_BITS (ival, 5)")))
+
+(define_constraint "K"
+ "A 6-bit signed constant"
+ (and (match_code "const_int")
+      (match_test "SIGNED_INT_FITS_N_BITS (ival, 6)")))
+
+(define_constraint "L"
+ "A 4-bit unsigned constant"
+ (and (match_code "const_int")
+      (match_test "UNSIGNED_INT_FITS_N_BITS (ival, 4)")))
+
+(define_constraint "G"
+ "A 4-bit double constant"
+ (and (match_code "const_double")
+      (match_test "cr16_const_double_ok (op)")))
+
+(define_register_constraint "b"
+ "NOSP_REGS"
+ "Non SP registers")
+
+;;  Attributes
+(define_attr "length" "" (const_int 2))
+
+(define_asm_attributes
+  [(set_attr "length" "2")]
+)
+
+;;  Predicates
+
+;; 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;
+  }
+)
+
+;; 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"
+  (and (match_code "const_int")
+       (match_test "UNSIGNED_INT_FITS_N_BITS (INTVAL (op), 3)")))
+
+;; Immediate shall be 4-bits in case operand to be operated on
+;; is a hi mode operand.
+(define_predicate "shift_hi_imm_operand"
+  (and (match_code "const_int")
+       (match_test "UNSIGNED_INT_FITS_N_BITS (INTVAL (op), 4)")))
+
+;; Immediate shall be 5-bits in case operand to be operated on
+;; is a si mode operand.
+(define_predicate "shift_si_imm_operand"
+  (and (match_code "const_int")
+       (match_test "UNSIGNED_INT_FITS_N_BITS (INTVAL (op), 5)")))
+
+;; Reg or shift operand 
+(define_predicate "reg_or_shift_qi_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_code "const_int")
+		    (match_test "UNSIGNED_INT_FITS_N_BITS (INTVAL (op), 3)"))))
+
+(define_predicate "reg_or_shift_hi_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_code "const_int")
+		    (match_test "UNSIGNED_INT_FITS_N_BITS (INTVAL (op), 4)"))))
+
+(define_predicate "reg_or_shift_si_operand"
+  (ior (match_operand 0 "register_operand")
+       (and (match_code "const_int")
+		    (match_test "UNSIGNED_INT_FITS_N_BITS (INTVAL (op), 5)"))))
+
+;; Jump immediate cannot be more than 24-bits
+(define_predicate "jump_imm_operand"
+  (and (match_code "const_int")
+       (match_test "UNSIGNED_INT_FITS_N_BITS (INTVAL (op), 24)")))
+
+;; 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;
+  }
+)
+
+;; CR16C/C+ does not have capability to address
+;; higher bytes of a register. Therefore, reject a register
+;; operand that has non-zero subreg byte
+(define_predicate "register_and_valid_subreg_byte_operand"
+  (match_operand 0 "register_operand")
+  {
+    if ((GET_CODE (op) == SUBREG)
+         && (REGNO (SUBREG_REG (op)) < FIRST_PSEUDO_REGISTER)
+         && (SUBREG_BYTE (op) != 0)
+       )
+      return 0;
+
+    return 1;
+  }
+)
+
+;; 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")))
+
+;; 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"))))
+
+;; 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;
+  }
+)
+
+;; Operand value is 1 
+(define_predicate "const1_operand"
+  (and (match_code "const_int")
+       (match_test "op == const1_rtx")))
+
+
+;;  Mode Macro Definitions
+
+(define_mode_iterator ALLMT  [QI HI SI SF])
+(define_mode_iterator CR16IM [QI HI SI])
+(define_mode_iterator LONG   [      SI SF])
+(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 IJK       [(QI "I") (HI "J") (SI "K")         ])
+(define_mode_attr iF        [(QI "i") (HI "i") (SI "i") (SF "F")])
+(define_mode_attr LL        [(QI "L") (HI "L")                  ])
+
+; In QI mode we push 2 bytes instead of 1 byte.
+(define_mode_attr pushCnstr [(QI "X") (HI "<") (SI "<") (SF "<")])
+; 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")])
+
+
+;;  Code Macro Definitions
+
+(define_code_iterator sz_xtnd [ sign_extend       zero_extend])
+(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 any_cond [eq ne gt gtu lt ltu ge geu le leu])
+
+;;  Bit Set/Clear Instructions
+(define_expand "insv"
+  [(set (zero_extract (match_operand 0 "memory_operand" "")
+          (match_operand 1 "const1_operand" "")
+          (match_operand 2 "const_int_operand" ""))
+    (match_operand 3 "const_int_operand" ""))]
+  "optimize"
+  {
+    if (!const_int_operand(operands[3], VOIDmode))
+      FAIL;
+  } 
+)
+
+(define_insn "insv<mode>"
+  [(set (zero_extract (match_operand:SHORT 0 "memory_operand" "+m")
+           (const_int 1)
+           (match_operand:HI 1 "const_int_operand" "i"))
+    (match_operand:HI 2 "const_int_operand" "i"))]
+  ""
+  {
+    if (INTVAL (operands[2]) & 1)
+      return "sbit<tIsa>\t%1,%0";
+    else
+      return "cbit<tIsa>\t%1,%0";
+  }
+  [(set_attr "length" "2")]
+)
+
+;; In operand %s1, 's' will be evaluated to bit number to set
+(define_insn "set_bit<mode>_mem"
+  [(set (match_operand:SHORT 0 "memory_operand" "=m")
+	(ior:SHORT (match_dup 0)
+               (match_operand:SHORT 1 "one_bit_operand" "i"))
+  )]
+  ""
+  "sbit<tIsa>\t$%s1,%0"
+  [(set_attr "length" "2")]
+)
+
+;; In operand %r1, 'r' will be evaluated to bit number to reset
+(define_insn "clear_bit<mode>_mem"
+  [(set (match_operand:SHORT 0 "memory_operand" "=m")
+    (and:SHORT (match_dup 0)
+               (match_operand:SHORT 1 "rev_one_bit_operand" "i"))
+  )]
+  ""
+  "cbit<tIsa>\t$%r1,%0"
+  [(set_attr "length" "2")]
+)
+
+;;  Addition Instructions
+(define_insn "add<mode>3"
+  [(set (match_operand:CR16IM 0 "register_operand" "=r,r")
+    (plus:CR16IM (match_operand:CR16IM 1 "register_operand" "%0,0")
+                 (match_operand:CR16IM 2 "nonmemory_operand" "r,i")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "add<tIsa>\t%2, %0"
+  [(set_attr "length" "2,<lImmArith>")]
+)
+
+;;  Subtract Instructions
+(define_insn "sub<mode>3"
+  [(set (match_operand:CR16IM 0 "register_operand" "=r,r")
+    (minus:CR16IM (match_operand:CR16IM 1 "register_operand" "0,0")
+                  (match_operand:CR16IM 2 "nonmemory_operand" "r,i")))
+    (clobber (reg:CC CC_REGNUM))]
+  ""
+  "sub<tIsa>\t%2, %0"
+  [(set_attr "length" "2,<lImmArith>")]
+)
+
+;;  Multiply and Accumulate Instructions
+(define_insn "<sPat>madhisi3"
+  [(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" "=r,=r")
+    (mult:HI (match_operand:HI 1 "register_and_valid_subreg_byte_operand" "%0,0")
+             (match_operand:HI 2 "nonmemory_operand" "r,i")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "mulw\t%2, %0"
+  [(set_attr "length" "2,4")]
+)
+
+
+; Only mulsb exists, therefore no use of mode and code macros
+(define_insn "mulqihi3"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+    (mult:HI (sign_extend:HI (match_operand:QI 1 "register_operand" "%0"))
+             (sign_extend:HI (match_operand:QI 2 "register_operand" "r"))))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "mulsb\t%2, %0"
+  [(set_attr "length" "2")]
+)
+
+;;  Logical Instructions - and
+
+(define_insn "and<mode>3"
+  [(set (match_operand:CR16IM 0 "register_operand" "=r,r")
+    (and:CR16IM (match_operand:CR16IM 1 "register_operand" "%0,0")
+                (match_operand:CR16IM 2 "nonmemory_operand" "r,i")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "and<tIsa>\t%2, %0"
+  [(set_attr "length" "2,<lImmArith>")]
+)
+
+;;  Logical Instructions - or
+
+(define_insn "ior<mode>3"
+  [(set (match_operand:CR16IM 0 "register_operand" "=r,r")
+    (ior:CR16IM (match_operand:CR16IM 1 "register_operand" "%0,0")
+                (match_operand:CR16IM 2 "nonmemory_operand" "r,i")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "or<tIsa>\t%2, %0"
+  [(set_attr "length" "2,<lImmArith>")]
+)
+
+;;  Logical Instructions - xor
+
+(define_insn "xor<mode>3"
+  [(set (match_operand:CR16IM 0 "register_operand" "=r,r")
+    (xor:CR16IM (match_operand:CR16IM 1 "register_operand" "%0,0")
+                (match_operand:CR16IM 2 "nonmemory_operand" "r,i")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "xor<tIsa>\t%2, %0"
+  [(set_attr "length" "2,<lImmArith>")]
+)
+
+;;  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_cmpl<mode>2"
+  [(set (match_operand:CR16IM 0 "register_operand" "=r")
+    (not:CR16IM (match_operand:CR16IM 1 "register_operand" "0")))
+   (clobber (reg:CC CC_REGNUM))]
+  ""
+  "xor<tIsa>\t$-1, %0"
+  [(set_attr "length" "2")]
+)
+
+;;  Arithmetic Left and Right Shift Instructions
+
+(define_insn "ashl<mode>3"
+  [(set (match_operand:CR16IM 0 "register_operand" "=r,=r")
+    (ashift:CR16IM (match_operand:CR16IM 1 "register_operand" "0,0")
+                   (match_operand:QI 2 "nonmemory_operand" "r,<IJK>")))]
+  ""
+  "ashu<tIsa>\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 "reg_or_shift_<mode>_operand" "")))]
+    ""
+    {
+      if (GET_CODE (operands[2]) != CONST_INT)
+        operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
+    }
+)
+
+(define_insn "ashr<mode>3_imm_insn"
+    [(set (match_operand:CR16IM 0 "register_operand" "=r")
+      (ashiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "0")
+                       (match_operand:QI 2 "shift_<mode>_imm_operand" "i")))]
+    ""
+    "ashu<tIsa>\t$%n2, %0"
+    [(set_attr "length" "2")]
+)
+
+(define_insn "ashr<mode>3_neg_insn"
+    [(set (match_operand:CR16IM 0 "register_operand" "=r")
+      (ashiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "0")
+                       (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
+    ""
+    "ashu<tIsa>\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_shift_<mode>_operand" "")))]
+    ""
+    {
+      if (GET_CODE (operands[2]) != CONST_INT)
+        operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
+    }
+)
+
+(define_insn "lshr<mode>3_imm_insn"
+    [(set (match_operand:CR16IM 0 "register_operand" "=r")
+      (lshiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "0")
+                       (match_operand:QI 2 "shift_<mode>_imm_operand" "i")))]
+    ""
+    "lsh<tIsa>\t$%n2, %0"
+    [(set_attr "length" "2")]
+)
+
+(define_insn "lshr<mode>3_neg_insn"
+    [(set (match_operand:CR16IM 0 "register_operand" "=r")
+      (lshiftrt:CR16IM (match_operand:CR16IM 1 "register_operand" "0")
+                       (neg:QI (match_operand:QI 2 "register_operand" "r"))))]
+    "" 
+    "lsh<tIsa>\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:ALLMT 0 "nonimmediate_operand" "")
+    (match_operand:ALLMT 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)
+                      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]);
+                  }
+              }
+          }
+      }
+  }
+)
+
+; ALLMT     : QI,HI,SI,SF
+; pushCnstr : Push constraints 
+;                QI : X
+;             HI,SI,SF : <
+; b         : All non-sp registers
+; tpush     : Push count
+;                QI,HI : 1
+;                SI,SF : 2
+; 
+(define_insn "push<mode>_internal"
+  [(set (match_operand:ALLMT 0 "push_operand" "=<pushCnstr>")
+    (match_operand:ALLMT 1 "nosp_reg_operand" "b"))]
+  ""
+  "push\t$<tpush>,%p1"
+  [(set_attr "length" "2")]
+)
+
+; 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
+
+(define_expand "cmp<mode>"
+  [(set (reg:CC CC_REGNUM)
+    (compare:CC (match_operand:CR16IM 0 "register_operand" "")
+                (match_operand:CR16IM 1 "nonmemory_operand" "")))]
+  ""
+  {
+    cr16_compare_op0 = operands[0];
+    cr16_compare_op1 = operands[1];
+    DONE;
+  }
+)
+
+; The instruction generated compares the operands in reverse order
+; Therefore, while printing the asm, the reverse of the 
+; compare condition shall be printed.
+(define_insn "cmp<mode>_internal"
+  [(set (reg:CC CC_REGNUM)
+    (compare:CC (match_operand:CR16IM 0 "register_operand" "r,r")
+                (match_operand:CR16IM 1 "nonmemory_operand" "r,i")))]
+  ""
+  "cmp<tIsa>\t%1, %0"
+  [(set_attr "length" "2,<lImmArith>")]
+)
+
+; TODO START: Enable this block of Compare with 0 and branch
+; when we find a way to check if the label_ref offset is
+; between 2 and 32
+; 
+
+;; Compare with 0 and branch
+;;
+;; beq0b, beq0w
+;; bne0b, bne0w
+;;
+;(define_insn "cmp0bne<mode>"
+;  [ (set (pc)
+;           (if_then_else (ne (match_operand:SHORT 0 "nosp_reg_operand" "r")
+;                     (const_int 0))
+;           (label_ref (match_operand 1 "" ""))
+;               (pc)))
+;      (clobber (reg:CC CC_REGNUM))]
+;  ""
+;  "*
+;  {
+;    /* GPS: Need to check if the label_ref offset is between 2 to 32 */
+;    return \"bne0<tIsa>\\t%0,%l1\";
+;  }"
+;  [(set_attr "length" "2")]
+;)
+
+;(define_insn "cmp0beq<mode>"
+;  [(set (pc)
+;           (if_then_else (eq (match_operand:SHORT 0 "nosp_reg_operand" "r")
+;                     (const_int 0))
+;           (label_ref (match_operand 1 "" ""))
+;               (pc)))
+;      (clobber (reg:CC CC_REGNUM))]
+;  ""
+;  "*
+;  { 
+;    /* GPS: Need to check if the label_ref offset is between 2 to 32 */
+;    return \"beq0<tIsa>\\t%0,%l1\";
+;  }"
+;  [(set_attr "length" "2")]
+;)
+; TODO END
+
+
+;;  Conditional Branch Instructions
+
+(define_expand "b<code>"
+  [(set (pc)
+    (if_then_else (any_cond (reg:CC CC_REGNUM)
+                    (const_int 0))
+      (label_ref (match_operand 0 ""))
+      (pc)))]
+  ""
+  {
+    cr16_expand_branch (<CODE>, operands[0]);
+    DONE;
+  }
+)
+
+; any_cond contains condition code string that does not 
+; match with condition code string of assembler. Therefore,
+; appropriate condition code string shall be printed to
+; asm file in print_operand (see 'd')
+(define_insn "bCOND_internal"
+  [(set (pc)
+    (if_then_else (match_operator 0 "comparison_operator"
+                    [(reg:CC CC_REGNUM)
+                     (const_int 0)])
+       (label_ref (match_operand 1 ""))
+       (pc)))]
+  ""
+  "b%d0\t%l1"
+  [(set_attr "length" "6")]
+)
+
+;;  Scond Instructions
+
+(define_expand "s<code>"
+  [(set (match_operand:HI 0 "register_operand")
+    (any_cond:HI (reg:CC CC_REGNUM) (const_int 0)))]
+  ""
+  {
+    cr16_expand_scond (<CODE>, operands[0]);
+    DONE;
+  }
+)
+
+(define_insn "sCOND_internal"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+    (match_operator:HI 1 "comparison_operator"
+      [(reg:CC CC_REGNUM) (const_int 0)]))]
+  ""
+  "s%d1\t%0"
+  [(set_attr "length" "2")]
+)
+
+;;  Jumps and Branches
+
+(define_insn "indirect_jump_return"
+  [(parallel
+    [(set (pc)
+      (reg:SI RA_REGNUM))
+      (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"
+  [(parallel
+    [(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")]
+)
+
+;;  Function Prologue and Epilogue
+
+(define_expand "prologue"
+  [(const_int 0)]
+  ""
+  {
+    cr16_expand_prologue ();
+    DONE;
+  }
+)
+
+(define_insn "push_for_prologue"
+  [(parallel
+    [(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"
+  [(parallel
+    [(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"
+  [(parallel
+    [(use (reg:SI RA_REGNUM))
+     (return)])
+  ]
+  "reload_completed"
+  "popret\tra"
+  [(set_attr "length" "2")]
+)
+
+;;  Table Jump
+(define_insn "tablejump"
+  [(set (pc)
+    (match_operand:SI 0 "register_operand" "r"))
+    (use (label_ref:SI (match_operand 1 "" "" )))]
+  ""
+  "jump\t%0"
+  [(set_attr "length" "2")]
+)
+
+;;  Call Instructions
+
+(define_expand "call"
+  [(call (match_operand:QI 0 "memory_operand" "")
+         (match_operand 1 "" ""))]
+  ""
+  {
+  	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"
+  [(call (mem:QI (match_operand:SI 0 "call_imm_operand" "i"))
+         (match_operand 1 "" ""))
+   (clobber (match_operand:SI 2 "register_operand" "+r"))]
+  ""
+  {
+    /* 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
+      return "bal (ra), %b0";
+  }
+  [(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 "" "")))]
+  ""
+  {
+    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"
+  [(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"))]
+  ""
+  {
+    /* 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
+      return "bal (ra), %b1";
+  }
+  [(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)]
+  ""
+  ""
+)
Index: config/cr16/cr16.c
===================================================================
--- config/cr16/cr16.c	(revision 0)
+++ config/cr16/cr16.c	(revision 0)
@@ -0,0 +1,1587 @@
+/* Output routines for GCC for CR16.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+   Originally modeled on CRX design.
+   Used lots of ideas from ARM, CRX, I386, stormy16 ports.
+
+   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 "real.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 "toplev.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))
+
+/* 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)
+
+/* Static Variables */
+
+/* Nonzero if the last param processed is passed in a register */
+static int last_parm_in_reg;
+
+/* Will hold the number of the last register the prologue saves, -1 if no
+   register is saved */
+static int last_reg_to_save;
+
+/* Each object in the array is a register number. Mark 1 for registers that
+   need to be saved */
+static int save_regs[FIRST_PSEUDO_REGISTER];
+
+/* Number of bytes saved on the stack for non-scratch registers */
+static int sum_regs = 0;
+
+/* Number of bytes saved on the stack for local variables */
+static int local_vars_size;
+
+/* The sum of 2 sizes: locals vars and padding byte for saving the registers.
+   Used in expand_prologue() and expand_epilogue() */
+static int size_for_adjusting_sp;
+
+/* 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;
+
+/* Global Variables */
+
+/* Table of machine attributes */
+const struct attribute_spec cr16_attribute_table[];
+
+/* Test and compare insns use these globals to generate branch insns */
+rtx cr16_compare_op0 = NULL_RTX;
+rtx cr16_compare_op1 = NULL_RTX;
+
+/* TARGETM Function Prototypes */
+
+static bool cr16_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2);
+static rtx cr16_struct_value_rtx (tree fntype ATTRIBUTE_UNUSED,
+                                  int incoming ATTRIBUTE_UNUSED);
+static bool cr16_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED);
+static int cr16_address_cost (rtx);
+
+/* Stack layout and calling conventions */
+
+#undef  TARGET_FIXED_CONDITION_CODE_REGS
+#define TARGET_FIXED_CONDITION_CODE_REGS cr16_fixed_condition_code_regs
+
+#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
+
+/* Relative costs of operations */
+#undef  TARGET_ADDRESS_COST
+#define TARGET_ADDRESS_COST         cr16_address_cost
+
+/* Target-specific uses of '__attribute__' */
+#undef  TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE      cr16_attribute_table
+
+const struct attribute_spec cr16_attribute_table[] = {
+  /* ISRs have special prologue and epilogue requirements */
+  {"interrupt", 0, 0, false, true, true, NULL},
+  {NULL, 0, 0, false, false, false, NULL}
+};
+
+
+/* Initialize 'targetm' variable which contains pointers to functions 
+   and data relating to the target machine */
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+/* Target hook implementations */
+
+/* Return the fixed registers used for condition codes */
+static bool
+cr16_fixed_condition_code_regs (unsigned int *p1, unsigned int *p2)
+{
+  *p1 = CC_REGNUM;
+  *p2 = INVALID_REGNUM;
+  return true;
+}
+
+/* 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_STRUCT_VALUE_REGNUM);
+}
+
+/* Implements hook TARGET_RETURN_IN_MEMORY */
+static bool
+cr16_return_in_memory (tree type, tree fntype ATTRIBUTE_UNUSED)
+{
+  if (TYPE_MODE (type) == BLKmode)
+    {
+      HOST_WIDE_INT size = int_size_in_bytes (type);
+      return ((size == -1) || (size > 8));
+    }
+  else
+    return false;
+}
+
+/* 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 */
+
+void
+cr16_override_options(void)
+{
+  /* 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; 
+}
+
+
+/* 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 save_regs and the variable sum_regs.  The index
+   of save_regs is numbers of register, each will get 1 if we need to save it
+   in the current function, 0 if not.  sum_regs 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 */
+  last_reg_to_save = -1;
+
+  /* No need to save any registers if the function never returns */
+  if (FUNC_IS_NORETURN_P (current_function_decl))
+    return;
+
+  /* Initialize the number of bytes to be saved */
+  sum_regs = 0;
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    {
+      if (fixed_regs[regno])
+        {
+          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 */
+            save_regs[regno] = 1;
+          else if (df_regs_ever_live_p (regno))
+            /* This reg is used - save it */
+            save_regs[regno] = 1;
+          else
+            /* This reg is not used, and is not a volatile - don't save */
+            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))
+            save_regs[regno] = 1;
+          else
+            save_regs[regno] = 0;
+        }
+    }
+
+  for (regno = 0; regno < FIRST_PSEUDO_REGISTER; regno++)
+    if (save_regs[regno] == 1)
+      {
+        last_reg_to_save = regno;
+        if (regno >= CR16_FIRST_DWORD_REGISTER)
+          sum_regs += CR16_UNITS_PER_DWORD;
+        else
+          sum_regs += 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 */
+  local_vars_size = get_frame_size ();
+
+  /* Align to the stack alignment */
+  padding_locals = local_vars_size % stack_alignment;
+  if (padding_locals)
+    padding_locals = stack_alignment - padding_locals;
+
+  local_vars_size += padding_locals;
+
+  size_for_adjusting_sp 
+	= local_vars_size + (ACCUMULATE_OUTGOING_ARGS ? 
+						 current_function_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 sum_regs */
+  cr16_compute_save_regs ();
+
+  /* Compute this since we need to use local_vars_size */
+  cr16_compute_frame ();
+
+  if (((from) == FRAME_POINTER_REGNUM) && ((to) == STACK_POINTER_REGNUM))
+    return (ACCUMULATE_OUTGOING_ARGS ?
+            current_function_outgoing_args_size : 0);
+  else if (((from) == ARG_POINTER_REGNUM) && ((to) == FRAME_POINTER_REGNUM))
+    return (sum_regs + local_vars_size);
+  else if (((from) == ARG_POINTER_REGNUM) && ((to) == STACK_POINTER_REGNUM))
+    return (sum_regs + local_vars_size +
+            (ACCUMULATE_OUTGOING_ARGS ?
+             current_function_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)
+{
+  /* CC can only hold CCmode values */
+  if (regno == CC_REGNUM)
+    return (GET_MODE_CLASS (mode) == MODE_CC);
+  if (GET_MODE_CLASS (mode) == MODE_CC)
+    return 0;
+  return 1;
+}
+
+/* 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, 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 */
+
+rtx
+cr16_function_arg (CUMULATIVE_ARGS *cum, enum machine_mode mode, tree type,
+                   int named ATTRIBUTE_UNUSED)
+{
+  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)
+        {
+          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)
+        {
+          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 != (tree) 0; param = next_param)
+    {
+      next_param = TREE_CHAIN (param);
+      if ((next_param == (tree) 0) && (TREE_VALUE (param) != void_type_node))
+        {
+          cum->ints = -1;
+          return;
+        }
+    }
+}
+
+/* Implements the macro FUNCTION_ARG_ADVANCE defined in cr16.h */
+
+void
+cr16_function_arg_advance (CUMULATIVE_ARGS *cum, enum machine_mode mode,
+                           tree type, int named ATTRIBUTE_UNUSED)
+{
+  /* 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 (!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)
+                  *data = DM_FAR; /* This will be used only for printing 
+                                     the qualifier. This call is (may be)
+                                     made by cr16_print_operand_address */
+                else
+                  *data = ILLEGAL_DM; /* This call is (may be) made by 
+                                         cr16_legitimate_address_p */
+              }
+          }
+        return;
+
+      case LABEL_REF:
+        *code = 1; /* 1 - indicates non-function symbol */
+        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))
+        return CR16_INVALID; /* CONST is not valid code or data address */
+      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;
+      code = 1; /* 1 - indicates non-function symbol */
+      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 */
+      code = SYMBOL_REF_FUNCTION_P (addr) ? 2 : 0; /* 2 indicates func sym */
+      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)
+                data = DM_FAR; /* This will be used only for printing the 
+                                  qualifier. This call is (may be) made
+                                  by cr16_print_operand_address */
+              else
+                return CR16_INVALID; /* This call is (may be) made by 
+                                        cr16_legitimate_address_p */
+            }
+          else
+            data = DM_DEFAULT;
+        }
+      if (debug_print)
+          fprintf (stderr, "\ndata:%d", data);
+      break;
+
+    case REG:
+    case SUBREG:
+      /* Register relative address */
+      retval = CR16_REG_REL;      /* Assume REG fits in a single register */
+      if (GET_MODE_BITSIZE (GET_MODE (addr)) > BITS_PER_WORD)
+        if (!LONG_REG_P (REGNO (addr)))
+          retval = CR16_REGP_REL; /* REG will result in reg pair */
+      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 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)))))
+                  retval = CR16_REGP_REL; /* REG will result in reg pair */
+              }
+            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  && !(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;
+}
+
+/* Implementation of GO_IF_LEGITIMATE_ADDRESS */
+int
+cr16_legitimate_address_p (enum machine_mode mode ATTRIBUTE_UNUSED,
+                           rtx addr, int strict)
+{
+  enum cr16_addrtype addrtype;
+  struct cr16_address address;
+
+  if (TARGET_DEBUG_ADDR)
+    {
+      fprintf (stderr,
+               "\n======\nGO_IF_LEGITIMATE_ADDRESS, 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_OK_FOR_BASE_P (REGNO (address.base)))
+        {
+          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;
+}
+
+/* Routines to compute costs */
+
+/* Return cost of the memory address x */
+
+static int
+cr16_address_cost (rtx addr)
+{
+  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======\nTARGET_ADDRESS_COST = %d\n", cost);
+      debug_rtx (addr);
+    }
+
+  return 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 */
+
+int
+cr16_memory_move_cost (enum machine_mode mode,
+                       enum reg_class class ATTRIBUTE_UNUSED,
+                       int in ATTRIBUTE_UNUSED)
+{
+  /* One LD or ST takes twice the time of a simple reg-reg move */
+  if (reg_classes_intersect_p (class, 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 */
+
+void
+cr16_print_operand (FILE *file, rtx x, int code)
+{
+  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 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;
+              }
+            default:
+              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 */
+
+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);
+
+  switch (addrtype)
+    {
+      case CR16_REG_REL:
+        if (address.disp)
+          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)
+          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:
+        gcc_unreachable ();
+    }
+  /* Add qualifiers to the address expression that was just printed */
+  if( address.code == 0)
+    {
+      if ( address.data == DM_FAR)
+        fprintf (file, "@l"); /* Addr contains SYMBOL_REF & far data ptr */
+      else if ( address.data == DM_DEFAULT)
+        fprintf (file, "@m"); /* Addr contains SYMBOL_REF & medium data ptr */
+      else if ( address.data == DM_NEAR)
+        fprintf (file, "@s"); /* Addr contains SYMBOL_REF & near data ptr */
+    }
+}
+
+/* Machine description helper functions */
+
+void
+cr16_expand_movmem_single (rtx src, rtx srcbase, rtx dst, rtx dstbase,
+                           rtx tmp_reg, unsigned HOST_WIDE_INT *offset_p)
+{
+  rtx addr, mem;
+  unsigned HOST_WIDE_INT offset = *offset_p;
+
+  /* Load */
+  addr = plus_constant (src, offset);
+  mem = adjust_automodify_address (srcbase, SImode, addr, offset);
+  emit_move_insn (tmp_reg, mem);
+
+  /* Store */
+  addr = plus_constant (dst, offset);
+  mem = adjust_automodify_address (dstbase, SImode, addr, offset);
+  emit_move_insn (mem, tmp_reg);
+
+  *offset_p = offset + 4;
+}
+
+int
+cr16_expand_movmem (rtx dstbase, rtx srcbase, rtx count_exp, rtx align_exp)
+{
+  unsigned HOST_WIDE_INT count = 0, offset, si_moves, i;
+  HOST_WIDE_INT align = 0;
+
+  rtx src, dst;
+  rtx tmp_reg;
+
+  if (GET_CODE (align_exp) == CONST_INT)
+    { /* Only if aligned */
+      align = INTVAL (align_exp);
+      if (align & 3)
+        return 0;
+    }
+
+  if (GET_CODE (count_exp) == CONST_INT)
+    { /* No more than 16 SImode moves */
+      count = INTVAL (count_exp);
+      if (count > 64)
+        return 0;
+    }
+
+  tmp_reg = gen_reg_rtx (SImode);
+
+  /* Create psrs for the src and dest pointers */
+  dst = copy_to_mode_reg (Pmode, XEXP (dstbase, 0));
+  if (dst != XEXP (dstbase, 0))
+    dstbase = replace_equiv_address_nv (dstbase, dst);
+  src = copy_to_mode_reg (Pmode, XEXP (srcbase, 0));
+  if (src != XEXP (srcbase, 0))
+    srcbase = replace_equiv_address_nv (srcbase, src);
+
+  offset = 0;
+
+  /* Emit SImode moves */
+  si_moves = count >> 2;
+  for (i = 0; i < si_moves; i++)
+    cr16_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset);
+
+  /* Special cases */
+  if (count & 3)
+    {
+      offset = count - 4;
+      cr16_expand_movmem_single (src, srcbase, dst, dstbase, tmp_reg, &offset);
+    }
+
+  gcc_assert (offset == count);
+
+  return 1;
+}
+
+rtx
+cr16_expand_compare (enum rtx_code code, enum machine_mode mode)
+{
+  rtx op0, op1, cc_reg, ret;
+
+  op0 = cr16_compare_op0;
+  op1 = cr16_compare_op1;
+
+  /* Emit the compare that writes into CC_REGNUM */
+  cc_reg = gen_rtx_REG (CCmode, CC_REGNUM);
+  ret = gen_rtx_COMPARE (CCmode, op0, op1);
+  emit_insn (gen_rtx_SET (VOIDmode, cc_reg, ret));
+
+  /* Return the rtx for using the result in CC_REGNUM */
+  return (gen_rtx_fmt_ee (code, mode, cc_reg, const0_rtx));
+}
+
+void
+cr16_expand_branch (enum rtx_code code, rtx label)
+{
+  rtx tmp = cr16_expand_compare (code, VOIDmode);
+  tmp = gen_rtx_IF_THEN_ELSE (VOIDmode, tmp,
+                              gen_rtx_LABEL_REF (VOIDmode, label),
+                              pc_rtx);
+  emit_jump_insn (gen_rtx_SET (VOIDmode, pc_rtx, tmp));
+}
+
+void
+cr16_expand_scond (enum rtx_code code, rtx dest)
+{
+  rtx tmp = cr16_expand_compare (code, GET_MODE (dest));
+  emit_move_insn (dest, tmp);
+}
+
+/* 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 save_regs[], going from 0 until last_reg_to_save */
+  int i, start_reg;
+  int word_cnt;
+  int print_ra;
+  static char return_str[120];
+
+  /* For reversing on the push instructions if there are more than one */
+  char temp_str[120];
+
+  /* Initialize */
+  memset (return_str, 0, 3);
+
+  i = 0;
+  while (i <= 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 <= last_reg_to_save))
+        {
+          /* For each non consecutive save register, 
+             a new instruction shall be generated  */
+          if (!save_regs[i])
+            {
+              ++i; /* Move to next reg and break */
+              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 ())
+            /* 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 (!FUNC_IS_NORETURN_P (current_function_decl)
+               && !(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 &return_str[2];
+}
+
+/*  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)
+{
+  cr16_compute_frame ();
+  cr16_compute_save_regs ();
+
+  /* If there is no need in push and adjustment to sp, return */
+  if ((size_for_adjusting_sp + sum_regs) == 0)
+    return;
+
+  if (last_reg_to_save != -1)
+    /* If there are registers to push */
+    emit_insn (gen_push_for_prologue (GEN_INT (sum_regs)));
+
+  if (size_for_adjusting_sp > 0)
+    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                           GEN_INT (-size_for_adjusting_sp)));
+
+  if (frame_pointer_needed)
+    /* Initialize the frame pointer with the value of the stack pointer
+       pointing now to the locals */
+    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 return_reg;
+
+  /* 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 = (save_regs[RETURN_ADDRESS_REGNUM]
+                        && (sum_regs == CR16_UNITS_PER_DWORD));
+
+  /* Return register */
+  return_reg = gen_rtx_REG (Pmode, RETURN_ADDRESS_REGNUM);
+
+  if (frame_pointer_needed)
+    /* Restore the stack pointer with the frame pointers value */
+    emit_move_insn (stack_pointer_rtx, frame_pointer_rtx);
+
+  if (size_for_adjusting_sp > 0)
+    emit_insn (gen_addsi3 (stack_pointer_rtx, stack_pointer_rtx,
+                           GEN_INT (size_for_adjusting_sp)));
+
+  if (cr16_interrupt_function_p ())
+    emit_jump_insn (gen_interrupt_return ());
+  else if (last_reg_to_save == -1)
+    /* Nothing to pop */
+    /* Don't output jump for interrupt routine, only retx */
+    emit_jump_insn (gen_indirect_jump_return ());
+  else if (only_popret_RA)
+    emit_jump_insn (gen_popret_RA_return ());
+  else
+    emit_jump_insn (gen_pop_and_popret_return (GEN_INT (sum_regs)));
+}
Index: config/cr16/cr16.opt
===================================================================
--- config/cr16/cr16.opt	(revision 0)
+++ config/cr16/cr16.opt	(revision 0)
@@ -0,0 +1,42 @@
+; Options for the National Semiconductor CR16 port of the compiler.
+
+; Copyright (C) 2007 Free Software Foundation, Inc.
+; Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+; Originally modeled on CRX design.
+; Used lots of ideas from ARM, CRX, I386, stormy16 ports.
+;
+; 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/>.
+
+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)
+
Index: config/cr16/t-cr16
===================================================================
--- config/cr16/t-cr16	(revision 0)
+++ config/cr16/t-cr16	(revision 0)
@@ -0,0 +1,64 @@
+# CR16 Target Makefile
+# Copyright (C) 1999, 2007 Free Software Foundation, Inc.
+# Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+# Originally modeled on CRX design.
+# Used lots of ideas from ARM, CRX, I386, stormy16 ports.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3, or (at your option)
+# any later version.
+#
+# GCC is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>. 
+
+LIB1ASMSRC = cr16/cr16-libgcc.s
+LIB1ASMFUNCS = _fixunssfdi _floatdisf _fixsfdi _mulsi3 _bswapdi2
+
+LIB2FUNCS_EXTRA = \
+	$(srcdir)/config/cr16/fixunssfsi.c \
+	$(srcdir)/config/cr16/divmodhi3.c
+
+#Need to build all crt stuff with various options!
+EXTRA_MULTILIB_PARTS = crtbegin.o crtend.o crti.o crtn.o
+
+$(T)crti.o: $(srcdir)/config/cr16/crti.s $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+	  -c -o $(T)crti.o -x assembler-with-cpp $(srcdir)/config/cr16/crti.s
+
+$(T)crtn.o: $(srcdir)/config/cr16/crtn.s $(GCC_PASSES)
+	$(GCC_FOR_TARGET) $(GCC_CFLAGS) $(MULTILIB_CFLAGS) $(INCLUDES) \
+	  -c -o $(T)crtn.o -x assembler-with-cpp $(srcdir)/config/cr16/crtn.s
+
+MULTILIB_OPTIONS     = mcr16cplus/mcr16c mdata-model=far/mdata-model=near/mdata-model=medium
+MULTILIB_DIRNAMES    = cr16cplus cr16c data-model-far data-model-near data-model-medium
+MULTILIB_EXCEPTIONS  = mcr16c/mdata-model=far
+MULTILIB_MATCHES     =
+
+LIBGCC = stmp-multilib
+INSTALL_LIBGCC = install-multilib
+
+# For all those using DF, DI without checking if they are supported,
+# simply make them look like SF and SI respectively.
+TARGET_LIBGCC2_CFLAGS = -DDF=SF -D__DI__=__SI__ -DDI=SI
+
+# We want fine grained libraries, so use the new code
+# to build the floating point emulation libraries.
+FPBIT = fp-bit.c
+
+fp-bit.c: $(srcdir)/config/fp-bit.c
+	echo '#define FLOAT' > fp-bit.c
+	echo '#define FLOAT_ONLY' >> fp-bit.c
+	echo '#define SMALL_MACHINE' >> fp-bit.c
+	echo '#define DF SF' >> fp-bit.c
+	echo '#define DI SI' >> fp-bit.c
+	echo '#define CMPtype HItype' >> fp-bit.c
+	cat $(srcdir)/config/fp-bit.c >> fp-bit.c
Index: config/cr16/cr16-libgcc.s
===================================================================
--- config/cr16/cr16-libgcc.s	(revision 0)
+++ config/cr16/cr16-libgcc.s	(revision 0)
@@ -0,0 +1,36 @@
+/* Libgcc Target specific implementation.
+   Copyright (C) 2007 Free Software Foundation, Inc.
+   Contributed by Pompapathi V Gadad (Pompapathi.V.Gadad@nsc.com)
+   Originally modeled on CRX design.
+   Used lots of ideas from ARM, CRX, I386, stormy16 ports.
+
+   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/>.  */
+
+#ifdef  L_mulsi3
+        .text
+        .align  2
+        .globl  ___mulsi3
+___mulsi3:
+    movw     r4,r0
+    movw    r2,r1
+    muluw   r1,(r1,r0)  # extended multiplication between the 2 lower words
+    mulw    r2,r5       # multiply the lower word of each parameter
+    mulw    r3,r4       # with the higher word of the other
+    addw    r4,r1       # add products to the higher part of the final result
+    addw    r5,r1
+    jump    (ra)
+#endif

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]