public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: "Pompapathi V Gadad" <Pompapathi.V.Gadad@nsc.com>
To: "'Rask Ingemann Lambertsen'" <rask@sygehus.dk>
Cc: "Pompapathi V Gadad" <pompapathi@gmail.com>, 	gcc-patches@gcc.gnu.org
Subject: Re: [Patch] New: CR16 port
Date: Fri, 20 Jul 2007 09:48:00 -0000	[thread overview]
Message-ID: <46A0707B.1050706@nsc.com> (raw)
In-Reply-To: <469B62DD.305@nsc.com>

Hello Rask,
Just a humble reminder to review and comment.
Thanks,
Pompa
Pompapathi V Gadad wrote:
> Hello Rask,
> Thanks for your patience.
> Please find the patch attached only for gcc sub directory, all other 
> patches remain the same 
> (http://gcc.gnu.org/ml/gcc-patches/2007-07/msg01409.html)
> I have removed redundant macros (tIsaLong. tIsaShort, lImmLong and 
> lImmShort), removed redundant define_expand and corrected the doc 
> error in extend.texi.
> I have run the compile-only gcc testsuite and results were same 
> (http://gcc.gnu.org/ml/gcc-testresults/2007-07/msg00675.html)
> Please review the patch and comment.
> Thanks,
> Pompa
>
> Pompapathi V Gadad wrote:
>>
>> 'Rask Ingemann Lambertsen' wrote:
>>> On Mon, Jul 16, 2007 at 02:26:06PM +0530, Pompapathi V Gadad wrote:
>>>
>>>  
>>>> Index: doc/extend.texi
>>>> ===================================================================
>>>> --- doc/extend.texi    (revision 126669)
>>>> +++ doc/extend.texi    (working copy)
>>>> @@ -2100,11 +2100,10 @@ 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,
>>>> -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
>>>> -is present.
>>>> +Use this attribute on the ARM, AVR, C4x, CR16, CRX, M32C, M32R/D, 
>>>> 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 is present.
>>>>  
>>>>  Note, interrupt handlers for the Blackfin, H8/300, H8/300H, H8S, and
>>>>  SH processors can be specified via the @code{interrupt_handler} 
>>>> attribute.
>>>>     
>>>
>>>    You're still modifying the m68k documentation.
>>>   
>> I am extremely sorry, I do not know how m68k changes has gone in to 
>> this patch. I will be careful now on.
>>>  
>>>> Index: config/cr16/cr16.md
>>>>     
>>> [...]
>>>  
>>>> +(define_mode_attr tIsa      [(QI "b") (HI "w") (SI "d") (SF "d")])
>>>> +(define_mode_attr tIsaLong  [                  (SI "d") (SF "d")])
>>>> +(define_mode_attr tIsaShort [(QI "b") (HI "w")                  ])
>>>>     
>>>
>>>    You should be able to use tIsa instead of tIsaLong and tIsaShort
>>> everywhere.
>>>
>>>  
>>>> +(define_mode_attr lImmShort [(QI "4") (HI "4")                  ])
>>>> +(define_mode_attr lImmLong  [                  (SI "6") (SF "6")])
>>>> +(define_mode_attr lImmArith [(QI "4") (HI "4") (SI "6") (SF "6")])
>>>>     
>>>
>>>    And something similiar goes here.
>>>
>>>  
>>>> +;;  Negation Instructions
>>>> +; move 0,r sub x,r. More efficient than xor -1,x add 1,x
>>>> +(define_expand "neg<mode>2"
>>>> +  [(set (match_operand:CR16IM 0 "register_operand" "")
>>>> +        (const_int 0))
>>>> +   (parallel [(set (match_dup 0) +        (minus:CR16IM (match_dup 0)
>>>> +          (match_operand:CR16IM 1 "register_operand" "")))
>>>> +    (clobber (reg:CC CC_REGNUM))]) +  ]
>>>> +  ""
>>>> +  "")
>>>>     
>>>
>>>    You said you would delete this expander. Did it not work?
>>>
>>>   
>> I will make necessary changes and post the pacthes.
>> Thanks a lot,
>> Pompa
>>
>>
>
>
> ------------------------------------------------------------------------
>
> Index: doc/extend.texi
> ===================================================================
> --- doc/extend.texi	(revision 126669)
> +++ doc/extend.texi	(working copy)
> @@ -2100,7 +2100,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 126669)
> +++ doc/invoke.texi	(working copy)
> @@ -450,6 +450,11 @@ Objective-C and Objective-C++ Dialects}.
>  -mno-leaf-id-shared-library  -msep-data  -mno-sep-data  -mlong-calls @gol
>  -mno-long-calls}
>  
> +@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
> @@ -7987,6 +7992,7 @@ platform.
>  * ARM Options::
>  * AVR Options::
>  * Blackfin Options::
> +* CR16 Options::
>  * CRIS Options::
>  * CRX Options::
>  * Darwin Options::
> @@ -8581,6 +8587,33 @@ switches have no effect on how the compi
>  function calls via function pointers.
>  @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 126669)
> +++ doc/md.texi	(working copy)
> @@ -1750,6 +1750,34 @@ 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 t
> +Register from r0 to r11 (all 16-bit registers)
> +
> +@item p
> +Register from r12 to r15 (all 32-bit registers)
> +
> +@item I
> +Signed constant that fits in 4 bits
> +
> +@item J
> +Signed constant that fits in 5 bits
> +
> +@item K
> +Signed constant that fits in 6 bits
> +
> +@item L
> +Unsigned constant that fits in 4 bits
> +
> +@item 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 126669)
> +++ doc/install.texi	(working copy)
> @@ -2787,6 +2787,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 126669)
> +++ config.gcc	(working copy)
> @@ -851,6 +851,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,603 @@
> +/* 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 2, 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 COPYING.  If not, write to
> +   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
> +   Boston, MA 02110-1301, USA.  */
> +
> +#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 REG_CLASS_FROM_LETTER(C)    \
> +    ((C) == 'b' ? NOSP_REGS :       \
> +     (C) == 't' ? SHORT_REGS :      \
> +     (C) == 'p' ? LONG_REGS :       \
> +     NO_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) < ((long long)1<<((N)-1))) && ((imm) >= -((long long)1<<((N)-1)))) ? 1 : 0)
> +
> +#define UNSIGNED_INT_FITS_N_BITS(imm, N) \
> +  (((imm) < ((long long)1<<(N)) && (imm) >= (long long)0) ? 1 : 0)
> +
> +/* The letters I, J, K, L and M in a register constraint string
> +   can be used to stand for particular ranges of immediate operands.
> +   This macro defines what the ranges are.
> +   C is the letter, and VALUE is a constant value.
> +   Return 1 if VALUE is in the range specified by C.
> +   I : signed 4 bit immediate
> +   J : signed 5 bit immediate
> +   K : signed 6 bit immediate
> +   L : unsigned 4 bit immediate
> +   */
> +
> +#define CONST_OK_FOR_LETTER_P(VALUE, C)               \
> +   ((C) == 'I' ? SIGNED_INT_FITS_N_BITS(VALUE, 4) :   \
> +    (C) == 'J' ? SIGNED_INT_FITS_N_BITS(VALUE, 5) :   \
> +    (C) == 'K' ? SIGNED_INT_FITS_N_BITS(VALUE, 6) :   \
> +    (C) == 'L' ? UNSIGNED_INT_FITS_N_BITS(VALUE, 4) : \
> +    0)
> +
> +/* Similar, but for floating constants, and defining letters G and H.
> +   Here VALUE is the CONST_DOUBLE rtx itself.  
> +   G : Float constant that can fit in 4 bits.
> +   H : Not defined.
> +   */
> +
> +#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)  \
> +  ((C) == 'G' ? cr16_const_double_ok (VALUE) :  \
> +   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
> +#define REG_OK_FOR_BASE_P(X)    1
> +#define REG_OK_FOR_INDEX_P(X)   1
> +#endif /* 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
> +#define GO_IF_LEGITIMATE_ADDRESS(MODE, X, LABEL)    \
> +{                                                   \
> +  if (cr16_legitimate_address_p (MODE, X, 0))       \
> +      goto LABEL;                                   \
> +}
> +#endif /* 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 /* ! GCC_CR16_H */
> +
> Index: config/cr16/crti.s
> ===================================================================
> --- config/cr16/crti.s	(revision 0)
> +++ config/cr16/crti.s	(revision 0)
> @@ -0,0 +1,47 @@
> +/* 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 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 2, 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 COPYING.  If not, write to
> +the Free Software Foundation, 59 Temple Place - Suite 330,
> +Boston, MA 02111-1307, USA.  */
> +
> +/* 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,34 @@
> +/* 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 2, 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 COPYING.  If not, write to
> +   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
> +   Boston, MA 02110-1301, USA.  */
> +
> +/* 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,117 @@
> +/* 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 2, 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 COPYING.  If not, write to
> +   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
> +   Boston, MA 02110-1301, USA.  */
> +
> +#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 /* GCC_CR16_PROTOS_H */
> Index: config/cr16/crtn.s
> ===================================================================
> --- config/cr16/crtn.s	(revision 0)
> +++ config/cr16/crtn.s	(revision 0)
> @@ -0,0 +1,41 @@
> +/* 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 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 2, 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 COPYING.  If not, write to
> +the Free Software Foundation, 59 Temple Place - Suite 330,
> +Boston, MA 02111-1307, USA.  */
> +
> +/* 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,111 @@
> +/* 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 2, 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 COPYING.  If not, write to
> +   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
> +   Boston, MA 02110-1301, USA.  */
> +
> +/* 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,945 @@
> +;; 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 2, 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 COPYING.  If not, write to
> +;; the Free Software Foundation, 51 Franklin Street, Fifth Floor,
> +;; Boston, MA 02110-1301, USA.  */
> +
> +;;  Register numbers
> +
> +(define_constants
> +  [(SP_REGNUM 15) ; Stack pointer
> +   (RA_REGNUM 14) ; Return address
> +   (CC_REGNUM 16) ; Condition code register
> +  ]
> +)
> +
> +(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"
> +  (match_code "const_int")
> +  {
> +    return (UNSIGNED_INT_FITS_N_BITS(INTVAL(op), 3)) ? 1 : 0;
> +  }
> +)
> +
> +;; Immediate shall be 4-bits in case operand to be operated on
> +;; is a hi mode operand.
> +(define_predicate "shift_hi_imm_operand"
> +  (match_code "const_int")
> +  {
> +    return (UNSIGNED_INT_FITS_N_BITS(INTVAL(op), 4)) ? 1 : 0;
> +  }
> +)
> +
> +;; Immediate shall be 3-bits in case operand to be operated on
> +;; is a si mode operand.
> +(define_predicate "shift_si_imm_operand"
> +  (match_code "const_int")
> +  {
> +    return (UNSIGNED_INT_FITS_N_BITS(INTVAL(op), 5)) ? 1 : 0;
> +  }
> +)
> +
> +;; Jump immediate cannot be more than 24-bits
> +(define_predicate "jump_imm_operand"
> + (match_code "const_int")
> + {
> +    return (UNSIGNED_INT_FITS_N_BITS(INTVAL(op), 24)) ? 1 : 0;
> + }
> +)
> +
> +;; Call immediate cannot be more than 24-bits
> +(define_predicate "call_imm_operand"
> +  (match_operand 0 "immediate_operand")
> +  {
> +   	if (GET_CODE (op) != CONST_INT) return 1;
> +    return (UNSIGNED_INT_FITS_N_BITS(INTVAL(op), 24)) ? 1 : 0;
> +  }
> +)
> +
> +;; 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
> +      abort();
> +
> +    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
> +      abort();
> +
> +    if (val != 0)
> +      return (val & (val - 1)) == 0; /* true if only one bit is set */
> +    else
> +      return 0;
> +  }
> +)
> +
> +;;  Mode Macro Definitions
> +
> +(define_mode_macro ALLMT  [QI HI SI SF])
> +(define_mode_macro CR16IM [QI HI SI])
> +(define_mode_macro LONG   [      SI SF])
> +(define_mode_macro 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")                  ])
> +
> +(define_mode_attr shImmBits	[(QI "3") (HI "4") (SI "5")         ])
> +
> +; In QI mode we push 2 bytes instead of 1 byte.
> +(define_mode_attr pushCnstr [(QI "X") (HI "<") (SI "<") (SF "<")])
> +; 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_macro 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_macro 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 "const_int_operand" "")
> +             (match_operand 2 "const_int_operand" ""))
> +    (match_operand 3 "const_int_operand" ""))]
> +  "optimize"
> +  {
> +    if (INTVAL(operands[1]) != 1)
> +      FAIL;
> +    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<<INTVAL(operands[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 "nonmemory_operand" "")))]
> +    ""
> +    {
> +      if (GET_CODE (operands[2]) == CONST_INT)
> +        {
> +          /* If the constant is not in range, try placing it in a reg */
> +          if (!UNSIGNED_INT_FITS_N_BITS(INTVAL(operands[2]),<shImmBits>))
> +            operands[2] = copy_to_mode_reg(QImode, operands[2]);
> +        }
> +
> +      if (GET_CODE (operands[2]) != CONST_INT)
> +        operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
> +    }
> +)
> +
> +(define_insn "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 "nonmemory_operand" "")))]
> +    ""
> +    {
> +      if (GET_CODE (operands[2]) == CONST_INT)
> +        {
> +          /* If the constant is not in range, try placing it in a reg */
> +          if (!UNSIGNED_INT_FITS_N_BITS(INTVAL(operands[2]),<shImmBits>))
> +            operands[2] = copy_to_mode_reg(QImode, operands[2]);
> +        }
> +
> +      if (GET_CODE (operands[2]) != CONST_INT)
> +        operands[2] = gen_rtx_NEG (QImode, negate_rtx (QImode, operands[2]));
> +    }
> +)
> +
> +(define_insn "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,1598 @@
> +/* 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 2, 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 COPYING.  If not, write to
> +   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
> +   Boston, MA 02110-1301, USA.  */
> +
> +#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;
> +
> +/* Glbal 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
> +    abort ();
> +}
> +
> +/* 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;
> +    }
> +
> +}
> +
> +/* 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 function 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 function 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:
> +            abort ();
> +        }
> +      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 : abort ();
> +            }
> +            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");
> +    }
> +
> +  abort ();
> +}
> +
> +/* 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:
> +        abort();
> +    }
> +  /* 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;
> +  char *return_str;
> +
> +  /* For reversing on the push instructions if there are more than one. */
> +  char *temp_str;
> +
> +  return_str = (char *) xmalloc (120);
> +  temp_str = (char *) xmalloc (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_str += 2;
> +  return return_str;
> +}
> +
> +/*  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,43 @@
> +; 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 2, 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 COPYING.  If not, write to the Free
> +; Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
> +; 02110-1301, USA.
> +
> +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,48 @@
> +# CR16 Target Makefile
> +# 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.
> +
> +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,37 @@
> +/* 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 2, 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 COPYING.  If not, write to
> +   the Free Software Foundation, 51 Franklin Street, Fifth Floor,
> +   Boston, MA 02110-1301, USA.  */
> +
> +#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
>   

  reply	other threads:[~2007-07-20  8:24 UTC|newest]

Thread overview: 20+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2007-07-10  7:11 Gadad, Pompapathi V
2007-07-11 23:41 ` Rask Ingemann Lambertsen
2007-07-13  9:22   ` Pompapathi V Gadad
2007-07-13 15:23     ` Rask Ingemann Lambertsen
2007-07-14  4:00       ` Pompapathi V Gadad
2007-07-16  9:14         ` Pompapathi V Gadad
2007-07-16 12:25           ` 'Rask Ingemann Lambertsen'
2007-07-16 13:01             ` Pompapathi V Gadad
2007-07-16 13:08               ` Pompapathi V Gadad
2007-07-20  9:48                 ` Pompapathi V Gadad [this message]
2007-07-21 14:33                 ` 'Rask Ingemann Lambertsen'
2007-07-25  9:40                   ` Pompapathi V Gadad
2007-07-30  8:33                     ` 'Rask Ingemann Lambertsen'
2007-07-30  9:14                       ` Pompapathi V Gadad
2007-08-03 13:03                         ` 'Rask Ingemann Lambertsen'
2007-08-06  4:44                           ` Pompapathi V Gadad
2007-08-06 10:43                             ` 'Rask Ingemann Lambertsen'
2007-08-06 10:49                               ` Pompapathi V Gadad
2007-07-21 12:20               ` 'Rask Ingemann Lambertsen'
2007-07-13 15:56 ` Rask Ingemann Lambertsen

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=46A0707B.1050706@nsc.com \
    --to=pompapathi.v.gadad@nsc.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=pompapathi@gmail.com \
    --cc=rask@sygehus.dk \
    /path/to/YOUR_REPLY

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

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