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: Mon, 16 Jul 2007 09:14:00 -0000 [thread overview]
Message-ID: <469B32A6.6090009@nsc.com> (raw)
In-Reply-To: <000001c7c5c6$e81dc4d0$144efea9@gadadsystem1>
[-- Attachment #1: Type: text/plain, Size: 3017 bytes --]
Hello Rask,
>> You could define "LONG" to expand to SI and SF and use something like
>> this:
>> <example pattern >
>> You may have to adjust the predicates a little.
> Yes. I will experiment on these lines and let you know the results as soon
> as possible.
Here is the code that worked after I applied your suggestion.
(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<tIsaLong>\t%1, %0
mov<tIsaLong>\t%1, %0
load<tIsaLong>\t%1, %0
stor<tIsaLong>\t%1, %0"
[(set_attr "length" "2,<lImmLong>,<lImmLong>,<lImmLong>")]
)
(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<tIsaShort>\t%1, %0
mov<tIsaShort>\t%1, %0
load<tIsaShort>\t%1, %0
stor<tIsaShort>\t%1, %0
stor<tIsaShort>\t%1, %0"
[(set_attr "length" "2,<lImmShort>,<lImmShort>,<lImmShort>,<lImmShort>")]
)
The compiler has worked just as it used to work earlier.
I will resubmit the compile-only testsuite to respective mailing list soon.
Please find the updated patches attached.
1) Patch for gcc directory: cr16-port_gcc_16jul07.diff
2) Patch for libgcc directory: cr16-port_libgcc_16jul07.diff
3) Patch for toplevel directory: cr16-port_toplevel_config_16jul07.diff
Patch for toplevel directory has already been submitted and reviewed,
however not committed yet.
Therefore, it is attached here as well.
http://gcc.gnu.org/ml/gcc-patches/2007-07/msg00923.html
ChangeLogs:
gcc/ChangeLog:
2007-07-16 Pompapathi V Gadad <Pompapathi.V.Gadad@nsc.com>
* config.gcc: Add cr16-elf support.
* doc/extend.texi: Document cr16 extensions.
* doc/install.texi: Document cr16 install.
* doc/invoke.texi: Document cr16 options.
* doc/md.texi: Document cr16 constraints.
* config/cr16/cr16.c: New file.
* config/cr16/cr16.h: New file.
* config/cr16/cr16.md: New file.
* config/cr16/cr16.opt: New file.
* config/cr16/cr16-libgcc.s: New file.
* config/cr16/cr16-protos.h: New file.
* config/cr16/crti.s: New file.
* config/cr16/crtn.s: New file.
* config/cr16/divmodhi3.c: New file.
* config/cr16/fixunssfsi.c: New file.
* config/cr16/t-cr16: New file.
libgcc/ChangeLog:
2007-07-07 Pompapathi V Gadad <Pompapathi.V.Gadad@nsc.com>
* config.host: Add National Semiconductor CR16 target (cr16-*-elf).
Toplevel ChangeLog:
2007-07-07 Pompapathi V Gadad <Pompapathi.V.Gadad@nsc.com>
* configure.ac: Add National Semiconductor CR16 target.
* configure: Regenerate
Please review and comment.
Thanks,
Pompa
[-- Attachment #2: cr16-port_gcc_160707.diff --]
[-- Type: text/plain, Size: 120040 bytes --]
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.
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,962 @@
+;; 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 tIsaLong [ (SI "d") (SF "d")])
+(define_mode_attr tIsaShort [(QI "b") (HI "w") ])
+
+(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")])
+
+(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<tIsaShort>\t%1,%0";
+ else
+ return "cbit<tIsaShort>\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<tIsaShort>\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<tIsaShort>\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")]
+)
+
+;; 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))])
+ ]
+ ""
+ "")
+
+;; 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<tIsaLong>\t%1, %0
+ mov<tIsaLong>\t%1, %0
+ load<tIsaLong>\t%1, %0
+ stor<tIsaLong>\t%1, %0"
+ [(set_attr "length" "2,<lImmLong>,<lImmLong>,<lImmLong>")]
+)
+
+; 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<tIsaShort>\t%1, %0
+ mov<tIsaShort>\t%1, %0
+ load<tIsaShort>\t%1, %0
+ stor<tIsaShort>\t%1, %0
+ stor<tIsaShort>\t%1, %0"
+ [(set_attr "length" "2,<lImmShort>,<lImmShort>,<lImmShort>,<lImmShort>")]
+)
+
+;; 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
[-- Attachment #3: cr16-port_libgcc_160707.diff --]
[-- Type: text/plain, Size: 296 bytes --]
Index: config.host
===================================================================
--- config.host (revision 126669)
+++ config.host (working copy)
@@ -262,6 +262,8 @@ c4x-*-rtems* | tic4x-*-rtems*)
;;
c4x-* | tic4x-*)
;;
+cr16-*-elf)
+ ;;
cris-*-aout)
;;
cris-*-elf | cris-*-none)
[-- Attachment #4: cr16-port_toplevel_config_160707.diff --]
[-- Type: text/plain, Size: 1408 bytes --]
Index: configure
===================================================================
--- configure (revision 126669)
+++ configure (working copy)
@@ -2275,6 +2275,9 @@ case "${target}" in
c54x*-*-* | tic54x-*-*)
noconfigdirs="$noconfigdirs target-libstdc++-v3 target-libgloss ${libgcj} gcc gdb newlib"
;;
+ cr16-*-*)
+ noconfigdirs="$noconfigdirs target-libstdc++-v3 target-mudflap ${libgcj}"
+ ;;
cris-*-* | crisv32-*-*)
unsupported_languages="$unsupported_languages java"
case "${target}" in
Index: config.sub
===================================================================
--- config.sub (revision 126669)
+++ config.sub (working copy)
@@ -467,6 +467,10 @@ case $basic_machine in
basic_machine=c38-convex
os=-bsd
;;
+ cr16)
+ basic_machine=cr16-unknown
+ os=-elf
+ ;;
cray | j90)
basic_machine=j90-cray
os=-unicos
Index: configure.ac
===================================================================
--- configure.ac (revision 126669)
+++ configure.ac (working copy)
@@ -553,6 +553,9 @@ case "${target}" in
c54x*-*-* | tic54x-*-*)
noconfigdirs="$noconfigdirs target-libstdc++-v3 target-libgloss ${libgcj} gcc gdb newlib"
;;
+ cr16-*-*)
+ noconfigdirs="$noconfigdirs target-libstdc++-v3 target-mudflap ${libgcj}"
+ ;;
cris-*-* | crisv32-*-*)
unsupported_languages="$unsupported_languages java"
case "${target}" in
next prev parent reply other threads:[~2007-07-16 8:59 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 [this message]
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
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=469B32A6.6090009@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).