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


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

New port^2: Renesas RL78


[Second posting: I think I've addressed all the feedback I can, I
moved the three non-target "bugs" to separate threads, added wwwdocs
patches, lots of comments, etc]

The Renesas RL78 is a new low-power 8/16 bit microcontroller, with an
architecture much like the original Z80.  However, it has four
register banks and a 1 Mb address space with default 16 bit pointers
and segment registers to access outside the default segments (code:
first 64k, data: last 64k).  The RL78 family is a direct descendant of
the 78K0R and R8C families (78K0R cpu core, R8C peripherals).

Because of the small number of real registers and weird addressing
modes, the port uses "virtual registers" - two of the banks are used
with patterns gcc likes until after reload, with fake "virtual" insn
patterns.  After reload, a target-specific pass converts each virtual
insn into a real insn by shuffling data between virtual registers and
real ones as needed.

http://www.renesas.com/pr/mcu/rl78/

Target: rl78-elf  (w/ binutils/newlib/sim)

There are a few [presumed] bugs in gcc that this port trips over.
They've been posted in separate emails.


libstdc++-v3

	* include/tr1/beta_function.tcc: Use 16-bit compatible "big"
	constants (65535U instead of 1000000) for max iterations.
	* include/tr1/gamma.tcc: Likewise.
	* include/tr1/hypergeometric.tcc: Likewise.

.

	* configure.ac (rl78-*-*) New case.
	* configure: Regenerate.

libgcc

	* config.host (rl78-*-elf): New case.
	* config/rl78: New directory for the Renesas RL78.

gcc

	* config.gcc (rl78-*-elf): New case.
	* doc/extend.texi: Add RL78 documentation.
	* doc/invoke.texi: Likewise.
	* doc/md.texi: Likewise.
	* doc/contrib.texi: Add RL78.
	* doc/install.texi: Add rl78-*-elf.
	* config/rl78: New directory for the Renesas RL78.

contrib

	* config-list.mk (LIST): Add rl78-elf.

wwwdocs

	* backends.html: Add rl78.
	* index.html: Mention rl78 port.
	* readings.html: Add rl78.

Index: libstdc++-v3/include/tr1/beta_function.tcc
===================================================================
--- libstdc++-v3/include/tr1/beta_function.tcc	(revision 180992)
+++ libstdc++-v3/include/tr1/beta_function.tcc	(working copy)
@@ -153,13 +153,13 @@ namespace tr1
     _Tp
     __beta_product(_Tp __x, _Tp __y)
     {
 
       _Tp __bet = (__x + __y) / (__x * __y);
 
-      unsigned int __max_iter = 1000000;
+      unsigned int __max_iter = 65535U;
       for (unsigned int __k = 1; __k < __max_iter; ++__k)
         {
           _Tp __term = (_Tp(1) + (__x + __y) / __k)
                      / ((_Tp(1) + __x / __k) * (_Tp(1) + __y / __k));
           __bet *= __term;
         }
Index: libstdc++-v3/include/tr1/gamma.tcc
===================================================================
--- libstdc++-v3/include/tr1/gamma.tcc	(revision 180992)
+++ libstdc++-v3/include/tr1/gamma.tcc	(working copy)
@@ -352,13 +352,13 @@ namespace tr1
      */
     template<typename _Tp>
     _Tp
     __psi_series(const _Tp __x)
     {
       _Tp __sum = -__numeric_constants<_Tp>::__gamma_e() - _Tp(1) / __x;
-      const unsigned int __max_iter = 100000;
+      const unsigned int __max_iter = 65535U;
       for (unsigned int __k = 1; __k < __max_iter; ++__k)
         {
           const _Tp __term = __x / (__k * (__k + __x));
           __sum += __term;
           if (std::abs(__term / __sum) < std::numeric_limits<_Tp>::epsilon())
             break;
Index: libstdc++-v3/include/tr1/hypergeometric.tcc
===================================================================
--- libstdc++-v3/include/tr1/hypergeometric.tcc	(revision 180992)
+++ libstdc++-v3/include/tr1/hypergeometric.tcc	(working copy)
@@ -79,13 +79,13 @@ namespace tr1
     __conf_hyperg_series(const _Tp __a, const _Tp __c, const _Tp __x)
     {
       const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
 
       _Tp __term = _Tp(1);
       _Tp __Fac = _Tp(1);
-      const unsigned int __max_iter = 100000;
+      const unsigned int __max_iter = 65535U;
       unsigned int __i;
       for (__i = 0; __i < __max_iter; ++__i)
         {
           __term *= (__a + _Tp(__i)) * __x
                   / ((__c + _Tp(__i)) * _Tp(1 + __i));
           if (std::abs(__term) < __eps)
@@ -268,13 +268,13 @@ namespace tr1
                     const _Tp __c, const _Tp __x)
     {
       const _Tp __eps = std::numeric_limits<_Tp>::epsilon();
 
       _Tp __term = _Tp(1);
       _Tp __Fabc = _Tp(1);
-      const unsigned int __max_iter = 100000;
+      const unsigned int __max_iter = 65535U;
       unsigned int __i;
       for (__i = 0; __i < __max_iter; ++__i)
         {
           __term *= (__a + _Tp(__i)) * (__b + _Tp(__i)) * __x
                   / ((__c + _Tp(__i)) * _Tp(1 + __i));
           if (std::abs(__term) < __eps)
Index: configure.ac
===================================================================
--- configure.ac	(revision 180992)
+++ configure.ac	(working copy)
@@ -498,12 +498,18 @@ case "${target}" in
     # No hosted I/O support.
     noconfigdirs="$noconfigdirs target-libssp"
     ;;
   powerpc-*-aix* | rs6000-*-aix*)
     noconfigdirs="$noconfigdirs target-libssp"
     ;;
+  rl78-*-*)
+    # libssp uses a misaligned load to trigger a fault, but the RL78
+    # doesn't fault for those - instead, it gives a build-time error
+    # for explicit misaligned loads.
+    noconfigdirs="$noconfigdirs target-libssp"
+    ;;
 esac
 
 # Disable libstdc++-v3 for some systems.
 case "${target}" in
   *-*-vxworks*)
     # VxWorks uses the Dinkumware C++ library.
Index: contrib/config-list.mk
===================================================================
--- contrib/config-list.mk	(revision 180992)
+++ contrib/config-list.mk	(working copy)
@@ -49,13 +49,13 @@ LIST = alpha-linux-gnu alpha-freebsd6 al
   powerpc-eabialtivec powerpc-xilinx-eabi powerpc-eabi \
   powerpc-rtems4.11OPT-enable-threads=yes powerpc-linux_spe \
   powerpc-linux_paired powerpc64-linux_altivec \
   powerpc-wrs-vxworks powerpc-wrs-vxworksae powerpc-lynxos powerpcle-elf \
   powerpcle-eabisim powerpcle-eabi rs6000-ibm-aix4.3 rs6000-ibm-aix5.1.0 \
   rs6000-ibm-aix5.2.0 rs6000-ibm-aix5.3.0 rs6000-ibm-aix6.0 \
-  rx-elf s390-linux-gnu s390x-linux-gnu s390x-ibm-tpf sh-elf \
+  rl78-elf rx-elf s390-linux-gnu s390x-linux-gnu s390x-ibm-tpf sh-elf \
   shle-linux sh-netbsdelf sh-superh-elf sh5el-netbsd sh64-netbsd sh64-linux \
   sh64-elfOPT-with-newlib sh-rtems sh-wrs-vxworks sparc-elf \
   sparc-leon-elf sparc-rtems sparc-linux-gnu \
   sparc-leon3-linux-gnuOPT-enable-target=all sparc-netbsdelf \
   sparc64-sun-solaris2.10OPT-with-gnu-ldOPT-with-gnu-asOPT-enable-threads=posix \
   sparc-wrs-vxworks sparc64-elf sparc64-rtems sparc64-linux sparc64-freebsd6 \
Index: configure
===================================================================
--- configure	(revision 180992)
+++ configure	(working copy)
@@ -3062,12 +3062,16 @@ case "${target}" in
     # No hosted I/O support.
     noconfigdirs="$noconfigdirs target-libssp"
     ;;
   powerpc-*-aix* | rs6000-*-aix*)
     noconfigdirs="$noconfigdirs target-libssp"
     ;;
+  rl78-*-*)
+    # Dereferencing -1 is a compile-time error
+    noconfigdirs="$noconfigdirs target-libssp"
+    ;;
 esac
 
 # Disable libstdc++-v3 for some systems.
 case "${target}" in
   *-*-vxworks*)
     # VxWorks uses the Dinkumware C++ library.
Index: libgcc/config.host
===================================================================
--- libgcc/config.host	(revision 180992)
+++ libgcc/config.host	(working copy)
@@ -913,12 +913,15 @@ rs6000-ibm-aix5.1.* | powerpc-ibm-aix5.1
 	tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-ibm-ldouble rs6000/t-slibgcc-aix"
 	;;
 rs6000-ibm-aix[56789].* | powerpc-ibm-aix[56789].*)
 	md_unwind_header=rs6000/aix-unwind.h
 	tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-ibm-ldouble rs6000/t-slibgcc-aix"
 	;;
+rl78-*-elf)
+	tmake_file="$tm_file t-fdpbit rl78/t-rl78"
+	;;
 rx-*-elf)
 	tmake_file="rx/t-rx t-fdpbit"
 	tm_file="$tm_file rx/rx-abi.h rx/rx-lib.h"
 	;;
 s390-*-linux*)
 	tmake_file="${tmake_file} s390/t-crtstuff s390/t-linux s390/32/t-floattodi"
Index: libgcc/config/rl78/rl78-divmod.h
===================================================================
--- libgcc/config/rl78/rl78-divmod.h	(revision 0)
+++ libgcc/config/rl78/rl78-divmod.h	(revision 0)
@@ -0,0 +1,118 @@
+/* libgcc routines for RL78
+   Copyright (C) 2005, 2009, 2011
+   Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+UINT_TYPE C3(udivmod,NAME_MODE,4) (UINT_TYPE, UINT_TYPE, word_type);
+SINT_TYPE C3(__div,NAME_MODE,3)   (SINT_TYPE, SINT_TYPE);
+SINT_TYPE C3(__mod,NAME_MODE,3)   (SINT_TYPE, SINT_TYPE);
+UINT_TYPE C3(__udiv,NAME_MODE,3)  (UINT_TYPE, UINT_TYPE);
+UINT_TYPE C3(__umod,NAME_MODE,3)  (UINT_TYPE, UINT_TYPE);
+
+UINT_TYPE
+C3(udivmod,NAME_MODE,4) (UINT_TYPE num, UINT_TYPE den, word_type modwanted)
+{
+  UINT_TYPE bit = 1;
+  UINT_TYPE res = 0;
+
+  while (den < num && bit && !(den & (1L << BITS_MINUS_1)))
+    {
+      den <<= 1;
+      bit <<= 1;
+    }
+  while (bit)
+    {
+      if (num >= den)
+	{
+	  num -= den;
+	  res |= bit;
+	}
+      bit >>= 1;
+      den >>= 1;
+    }
+  if (modwanted)
+    return num;
+  return res;
+}
+
+SINT_TYPE
+C3(__div,NAME_MODE,3) (SINT_TYPE a, SINT_TYPE b)
+{
+  word_type neg = 0;
+  SINT_TYPE res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = !neg;
+    }
+
+  if (b < 0)
+    {
+      b = -b;
+      neg = !neg;
+    }
+
+  res = C3(udivmod,NAME_MODE,4) (a, b, 0);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+SINT_TYPE
+C3(__mod,NAME_MODE,3) (SINT_TYPE a, SINT_TYPE b)
+{
+  word_type neg = 0;
+  SINT_TYPE res;
+
+  if (a < 0)
+    {
+      a = -a;
+      neg = 1;
+    }
+
+  if (b < 0)
+    b = -b;
+
+  res = C3(udivmod,NAME_MODE,4) (a, b, 1);
+
+  if (neg)
+    res = -res;
+
+  return res;
+}
+
+UINT_TYPE
+C3(__udiv,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b)
+{
+  return C3(udivmod,NAME_MODE,4) (a, b, 0);
+}
+
+UINT_TYPE
+C3(__umod,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b)
+{
+  return C3(udivmod,NAME_MODE,4) (a, b, 1);
+}
Index: libgcc/config/rl78/lib2mul.c
===================================================================
--- libgcc/config/rl78/lib2mul.c	(revision 0)
+++ libgcc/config/rl78/lib2mul.c	(revision 0)
@@ -0,0 +1,49 @@
+/* libgcc routines for RL78
+   Copyright (C) 2005, 2009, 2011
+   Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef unsigned int  uint32_type   __attribute__ ((mode (SI)));
+typedef unsigned int  uint16_type   __attribute__ ((mode (HI)));
+typedef unsigned int  uint08_type   __attribute__ ((mode (QI)));
+
+#define C3B(a,b,c) a##b##c
+#define C3(a,b,c) C3B(a,b,c)
+
+
+#define UINT_TYPE	uint16_type
+#define BITS_MINUS_1	15
+#define NAME_MODE	hi
+
+/*#include "rl78-mul.h"*/
+
+#undef UINT_TYPE
+#undef BITS_MINUS_1
+#undef NAME_MODE
+
+#define UINT_TYPE	uint08_type
+#define BITS_MINUS_1	7
+#define NAME_MODE	qi
+
+#include "rl78-mul.h"
Index: libgcc/config/rl78/lib2shift.c
===================================================================
--- libgcc/config/rl78/lib2shift.c	(revision 0)
+++ libgcc/config/rl78/lib2shift.c	(revision 0)
@@ -0,0 +1,113 @@
+/* Shift functions for the GCC support library for the Renesas RL78 processors.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef          int  sint32_type   __attribute__ ((mode (SI)));
+typedef unsigned int  uint32_type   __attribute__ ((mode (SI)));
+typedef          int  sint16_type   __attribute__ ((mode (HI)));
+typedef unsigned int  uint16_type   __attribute__ ((mode (HI)));
+
+uint32_type __ashlsi3 (uint32_type in, char bit);
+sint32_type __ashrsi3 (sint32_type in, char bit);
+int __clrsbhi2 (sint16_type x);
+extern int __clrsbsi2 (sint32_type x);
+
+typedef struct
+{
+  union
+  {
+    uint32_type u;
+    uint16_type h[2];
+  } u;
+} dd;
+
+uint32_type
+__ashlsi3 (uint32_type in, char bit)
+{
+  uint16_type h, l;
+  dd d;
+
+  if (bit > 32)
+    return 0;
+  if (bit < 0)
+    return in;
+
+  d.u.u = in;
+  h = d.u.h[1];
+  l = d.u.h[0];
+
+  if (bit > 15)
+    {
+      h = l;
+      l = 0;
+      bit -= 16;
+    }
+
+  while (bit)
+    {
+      h = (h << 1) | (l >> 15);
+      l <<= 1;
+      bit --;
+    }
+
+  d.u.h[1] = h;
+  d.u.h[0] = l;
+  return d.u.u;
+}
+
+sint32_type
+__ashrsi3 (sint32_type in, char bit)
+{
+  sint16_type h;
+  uint16_type l;
+  dd d;
+
+  if (bit > 32)
+    return 0;
+  if (bit < 0)
+    return in;
+
+  d.u.u = in;
+  h = d.u.h[1];
+  l = d.u.h[0];
+
+  while (bit)
+    {
+      l = (h << 15) | (l >> 1);
+      h >>= 1;
+      bit --;
+    }
+
+  d.u.h[1] = h;
+  d.u.h[0] = l;
+  return d.u.u;
+}
+
+int
+__clrsbhi2 (sint16_type x)
+{
+  if (x == 0)
+    return 15;
+  return __clrsbsi2 ((sint32_type) x) - 16;
+}
Index: libgcc/config/rl78/lshrsi3.S
===================================================================
--- libgcc/config/rl78/lshrsi3.S	(revision 0)
+++ libgcc/config/rl78/lshrsi3.S	(revision 0)
@@ -0,0 +1,131 @@
+;   Copyright (C) 2011 Free Software Foundation, Inc.
+;   Contributed by Red Hat.
+; 
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+; 
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+; 
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+; <http://www.gnu.org/licenses/>.
+
+r8	=	0xffef0
+r16	=	0xffee8
+r9	=	0xffef1
+r17	=	0xffee9
+r10	=	0xffef2
+r18	=	0xffeea
+r11	=	0xffef3
+r19	=	0xffeeb
+r12	=	0xffef4
+r20	=	0xffeec
+r13	=	0xffef5
+r21	=	0xffeed
+r14	=	0xffef6
+r22	=	0xffeee
+r15	=	0xffef7
+r23	=	0xffeef
+	
+	.text
+	.global	___lshrsi3
+	.type	___lshrsi3, @function
+___lshrsi3:
+
+	;; input:
+	;; 
+	;; [zero]
+	;; [count]   <= $sp+8
+	;; [in MSB]
+	;; [in]
+	;; [in]
+	;; [in LSB]  <- $sp+4
+
+	;; output:
+	;; 
+	;; [r8..r11] result
+
+	;; registers:
+	;;
+	;; AX - temp for shift/rotate
+	;; B  - count
+
+	mov	a, [sp+8]	; A now contains the count
+
+	cmp	a, #0x20
+	bc	$.Lcount_is_normal
+
+	;; count is out of bounds, just return zero.
+	movw	r8, #0
+	movw	r10, #0
+	ret
+
+.Lcount_is_normal:
+	cmp0	a
+	bnz	$.Lcount_is_nonzero
+
+	;; count is zero, just copy IN to OUT
+	movw	ax, [sp+4]
+	movw	r8, ax
+	movw	ax, [sp+6]
+	movw	r10, ax
+	ret
+
+.Lcount_is_nonzero:
+	mov	b, a		; B now contains the count also
+	bf	a.4, $.Lcount_lt_16
+
+	;; count >= 16, shift 16 at a time.
+	movw	r10, #0
+	movw	ax, [sp+6]
+	movw	r8, ax
+	mov	a, b
+	and	a, #0x0f
+	sknz
+	ret
+
+	mov	b, a		; B now contains the remaining count
+	inc	b
+	br	$.Lloop_top
+
+.Lcount_lt_16:	
+	;; count is nonzero.  Do one 
+	movw	ax, [sp+6]
+	shrw	ax,1
+	movw	r10, ax
+	mov	a, [sp+5]
+	rorc	a,1
+	mov	r9, a
+	mov	a, [sp+4]
+	rorc	a,1
+	mov	r8, a
+
+	;; we did one shift above; do as many more as we need now.
+.Lloop_top:	
+	dec	b
+	sknz
+	ret
+
+	movw	ax, r10
+	shrw	ax,1
+	movw	r10, ax
+	mov	a, r9
+	rorc	a,1
+	mov	r9, a
+	mov	a, r8
+	rorc	a,1
+	mov	r8, a
+
+	br	$.Lloop_top
+
+	.size	___lshrsi3, .-___lshrsi3
Index: libgcc/config/rl78/trampoline.S
===================================================================
--- libgcc/config/rl78/trampoline.S	(revision 0)
+++ libgcc/config/rl78/trampoline.S	(revision 0)
@@ -0,0 +1,139 @@
+/* libgcc routines for RL78
+   Copyright (C) 2011
+   Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+/* RL78 Trampoline support
+
+  Since the RL78's RAM is not in the first 64k, we cannot "just" use a
+  function pointer to point to a trampoline on the stack.  So, we
+  create N fixed trampolines that read from an array, and allocate
+  them as needed.
+
+*/
+
+r8	=	0xffef0
+r10	=	0xffef2
+r14	=	0xffef6
+
+	.data
+	.p2align	1
+trampoline_array:
+
+	.macro stub n
+
+	.text
+trampoline_\n:
+        .type   trampoline_\n, @function
+	movw	ax, !trampoline_chain_\n
+	movw	r14, ax
+	movw	ax, !trampoline_addr_\n
+	br	ax
+	.size	trampoline_\n, .-trampoline_\n
+
+	.data
+trampoline_frame_\n:
+	.short	0
+trampoline_stub_\n:
+	.short	trampoline_\n
+trampoline_chain_\n:
+	.short	0
+trampoline_addr_\n:
+	.short	0
+
+#define TO_FRAME 0
+#define TO_STUB  2
+#define TO_CHAIN 4
+#define TO_ADDR  6
+#define TO_SIZE  8
+
+	.endm
+
+	stub	0
+	stub	1
+	stub	2
+	stub	3
+	stub	4
+	stub	5
+
+trampoline_array_end:
+
+/* Given the function pointer in R8 and the static chain
+   pointer in R10, allocate a trampoline and return its address in
+   R8. */
+
+	.text
+	.global ___trampoline_init
+        .type   ___trampoline_init, @function
+___trampoline_init:
+
+	movw	hl, #trampoline_array
+1:
+	movw	ax, [hl + TO_ADDR]
+	cmpw	ax, #0
+	bz	$2f
+
+	movw	ax, hl
+	addw	ax, #TO_SIZE
+	movw	hl, ax
+	cmpw	ax, #trampoline_array_end
+	bnz	$1b
+	brk			; no more slots?
+
+2:	movw	ax, r8
+	movw	[hl + TO_ADDR], ax
+	movw	ax, r10
+	movw	[hl + TO_CHAIN], ax
+	movw	ax, sp
+	movw	[hl + TO_FRAME], ax
+
+	movw	ax, [hl + TO_STUB]
+	movw	r8, ax
+
+	ret
+	.size	___trampoline_init, . - ___trampoline_init
+
+	.global	___trampoline_uninit
+        .type   ___trampoline_uninit, @function
+___trampoline_uninit:
+	movw	hl, #trampoline_array
+	movw	ax, sp
+	movw	bc, ax
+1:
+	movw	ax, [hl + TO_FRAME]
+	cmpw	ax, bc
+	bc	$2f
+
+	clrw	ax
+	movw	[hl + TO_ADDR], ax
+
+2:
+	movw	ax, hl
+	addw	ax, #TO_SIZE
+	movw	hl, ax
+	cmpw	ax, #trampoline_array_end
+	bnz	$1b
+
+	ret
+	.size	___trampoline_uninit, . - ___trampoline_uninit
Index: libgcc/config/rl78/lib2div.c
===================================================================
--- libgcc/config/rl78/lib2div.c	(revision 0)
+++ libgcc/config/rl78/lib2div.c	(revision 0)
@@ -0,0 +1,81 @@
+/* libgcc routines for RL78
+   Copyright (C) 2005, 2009, 2011
+   Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+typedef          int  sint32_type   __attribute__ ((mode (SI)));
+typedef unsigned int  uint32_type   __attribute__ ((mode (SI)));
+typedef          int  sint16_type   __attribute__ ((mode (HI)));
+typedef unsigned int  uint16_type   __attribute__ ((mode (HI)));
+typedef          int  sint08_type   __attribute__ ((mode (QI)));
+typedef unsigned int  uint08_type   __attribute__ ((mode (QI)));
+typedef int           word_type     __attribute__ ((mode (__word__)));
+
+#define C3B(a,b,c) a##b##c
+#define C3(a,b,c) C3B(a,b,c)
+
+#define UINT_TYPE	uint32_type
+#define SINT_TYPE	sint32_type
+#define BITS_MINUS_1	31
+#define NAME_MODE	si
+
+#include "rl78-divmod.h"
+
+#undef UINT_TYPE
+#undef SINT_TYPE
+#undef BITS_MINUS_1
+#undef NAME_MODE
+
+#define UINT_TYPE	uint16_type
+#define SINT_TYPE	sint16_type
+#define BITS_MINUS_1	15
+#define NAME_MODE	hi
+
+#include "rl78-divmod.h"
+
+#undef UINT_TYPE
+#undef SINT_TYPE
+#undef BITS_MINUS_1
+#undef NAME_MODE
+
+#define UINT_TYPE	uint08_type
+#define SINT_TYPE	sint08_type
+#define BITS_MINUS_1	7
+#define NAME_MODE	qi
+
+#include "rl78-divmod.h"
+
+/* See the comment by the definition of LIBGCC2_UNITS_PER_WORD in
+   m32c.h for why we are creating extra versions of some of the
+   functions defined in libgcc2.c.  */
+
+#define LIBGCC2_UNITS_PER_WORD 2
+
+#define L_clzsi2
+#define L_ctzsi2
+#define L_ffssi2
+#define L_paritysi2
+#define L_popcountsi2
+
+#include "libgcc2.c"
Index: libgcc/config/rl78/mulsi3.S
===================================================================
--- libgcc/config/rl78/mulsi3.S	(revision 0)
+++ libgcc/config/rl78/mulsi3.S	(revision 0)
@@ -0,0 +1,235 @@
+;   Copyright (C) 2011 Free Software Foundation, Inc.
+;   Contributed by Red Hat.
+; 
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+; 
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+; 
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+; <http://www.gnu.org/licenses/>.
+
+;; 32x32=32 multiply
+
+; real
+; GAS defines r0..r7 as aliases for real registers; we want the saddr
+; forms here.
+r_0	=	0xffef8
+r_1	=	0xffef9
+r_2	=	0xffefa
+r_3	=	0xffefb
+r_4	=	0xffefc
+r_5	=	0xffefd
+r_6	=	0xffefe
+r_7	=	0xffeff
+; clobberable
+r8	=	0xffef0
+r9	=	0xffef1
+r10	=	0xffef2
+r11	=	0xffef3
+r12	=	0xffef4
+r13	=	0xffef5
+r14	=	0xffef6
+r15	=	0xffef7
+; preserved
+r16	=	0xffee8
+r17	=	0xffee9
+r18	=	0xffeea
+r19	=	0xffeeb
+r20	=	0xffeec
+r21	=	0xffeed
+r22	=	0xffeee
+r23	=	0xffeef
+
+
+;----------------------------------------------------------------------
+
+; Register use:
+;	RB0	RB1	RB2
+; AX	op2L	res32L	res32H
+; BC	op2H	(resH)	op1
+; DE	count	(resL-tmp)
+; HL	[sp+4]
+
+	.text
+	nop
+	.global	___mulsi3		; (USI a, USI b)
+___mulsi3:
+	;; A is at [sp+4]
+	;; B is at [sp+8]
+	;; result is in R8..R11
+
+	movw	ax, sp
+	addw	ax, #4
+	movw	hl, ax
+
+	sel	rb2
+	push	ax
+	push	bc
+	sel	rb0
+
+	clrw	ax
+	movw	r8, ax
+	movw	r16, ax
+
+	movw	ax, [hl+6]
+	cmpw	ax, #0
+	bz	$1f
+	cmpw	ax, #0xffff
+	bnz	$2f
+	movw	ax, [hl]
+	sel	rb1
+	subw	ax, r_0
+	sel	rb0
+	br	$1f
+2:	
+	movw	bc, ax
+	movw	ax, [hl]
+	cmpw	ax, #0
+	skz
+	call	!.Lmul_hi
+1:	
+
+	movw	ax, [hl+2]
+	cmpw	ax, #0
+	bz	$1f
+	cmpw	ax, #0xffff
+	bnz	$2f
+	movw	ax, [hl+4]
+	sel	rb1
+	subw	ax, r_0
+	sel	rb0
+	br	$1f
+2:	
+	movw	bc, ax
+	movw	ax, [hl+4]
+	cmpw	ax, #0
+	skz
+	call	!.Lmul_hi
+1:	
+
+	movw	ax, r8
+	movw	r16, ax
+	clrw	ax
+	movw	r8, ax
+
+	;; now do R16:R8 += op1L * op2L
+
+	;; op1 is in AX.0 (needs to shrw)
+	;; op2 is in BC.2 and BC.1 (bc can shlw/rolcw)
+	;; res is in AX.2 and AX.1 (needs to addw)
+
+	movw	ax, [hl]
+	movw	r10, ax		; BC.1
+	movw	ax, [hl+4]
+
+	cmpw	ax, r10
+	bc	$.Lmul_hisi_top
+	movw	bc, r10
+	movw	r10, ax
+	movw	ax, bc
+
+
+.Lmul_hisi_top:
+	movw	bc, #0
+
+.Lmul_hisi_loop:
+	shrw	ax, 1
+	bnc	$.Lmul_hisi_no_add
+	sel	rb1
+	addw	ax, bc
+	sel	rb2
+	sknc
+	incw	ax
+	addw	ax, r_2
+.Lmul_hisi_no_add:	
+	sel	rb1
+	shlw	bc, 1
+	sel	rb0
+	rolwc	bc, 1
+	cmpw	ax, #0
+	bz	$.Lmul_hisi_done
+
+	shrw	ax, 1
+	bnc	$.Lmul_hisi_no_add2
+	sel	rb1
+	addw	ax, bc
+	sel	rb2
+	sknc
+	incw	ax
+	addw	ax, r_2
+.Lmul_hisi_no_add2:
+	sel	rb1
+	shlw	bc, 1
+	sel	rb0
+	rolwc	bc, 1
+	cmpw	ax, #0
+	bnz	$.Lmul_hisi_loop
+
+.Lmul_hisi_done:
+
+	movw	ax, r16
+	movw	r10, ax
+	
+	sel	rb2
+	pop	bc
+	pop	ax
+	sel	rb0
+
+	ret
+
+;----------------------------------------------------------------------
+
+	;; R8 += AX * BC
+.Lmul_hi:
+	cmpw	ax, bc
+	skc
+	xchw	ax, bc
+	br	$.Lmul_hi_loop
+	
+.Lmul_hi_top:
+	sel	rb1
+	addw	ax, r_2
+	sel	rb0
+.Lmul_hi_no_add:	
+	shlw	bc, 1
+.Lmul_hi_loop:
+	shrw	ax, 1
+	bc	$.Lmul_hi_top
+	cmpw	ax, #0
+	bz	$.Lmul_hi_done
+
+	shlw	bc, 1
+	shrw	ax, 1
+	bc	$.Lmul_hi_top
+	cmpw	ax, #0
+	bnz	$.Lmul_hi_no_add
+
+.Lmul_hi_done:
+	ret
+
+;----------------------------------------------------------------------
+
+	.global	___mulhi3
+___mulhi3:
+	sel	rb1
+	clrw	ax
+	sel	rb0
+	movw	ax, sp
+	addw	ax, #4
+	movw	hl, ax
+	movw	ax, [hl+2]
+	movw	bc, ax
+	movw	ax, [hl]
+	br	$.Lmul_hi
Index: libgcc/config/rl78/rl78-mul.h
===================================================================
--- libgcc/config/rl78/rl78-mul.h	(revision 0)
+++ libgcc/config/rl78/rl78-mul.h	(revision 0)
@@ -0,0 +1,43 @@
+/* libgcc routines for RL78
+   Copyright (C) 2005, 2009, 2011
+   Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   Under Section 7 of GPL version 3, you are granted additional
+   permissions described in the GCC Runtime Library Exception, version
+   3.1, as published by the Free Software Foundation.
+
+   You should have received a copy of the GNU General Public License and
+   a copy of the GCC Runtime Library Exception along with this program;
+   see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+   <http://www.gnu.org/licenses/>.  */
+
+UINT_TYPE C3(__mul,NAME_MODE,3)   (UINT_TYPE, UINT_TYPE);
+UINT_TYPE
+C3(__mul,NAME_MODE,3) (UINT_TYPE a, UINT_TYPE b)
+{
+  UINT_TYPE rv = 0;
+
+  char bit;
+
+  for (bit=0; b && bit<sizeof(UINT_TYPE)*8; bit++)
+    {
+      if (b & 1)
+	rv += a;
+      a <<= 1;
+      b >>= 1;
+    }
+  return rv;
+}
Index: libgcc/config/rl78/t-rl78
===================================================================
--- libgcc/config/rl78/t-rl78	(revision 0)
+++ libgcc/config/rl78/t-rl78	(revision 0)
@@ -0,0 +1,28 @@
+# Makefile fragment for building LIBGCC for the Renesas RL78 target.
+# Copyright (C) 2011 Free Software Foundation, Inc.
+# Contributed by Red Hat.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 3, or (at your
+# option) any later version.
+#
+# GCC is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See
+# the GNU General Public License for more details.
+#
+# You should have received a copy of the  GNU General Public
+# License along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+LIB2ADD = \
+	$(srcdir)/config/rl78/trampoline.S \
+	$(srcdir)/config/rl78/lib2div.c \
+	$(srcdir)/config/rl78/lib2mul.c \
+	$(srcdir)/config/rl78/lib2shift.c \
+	$(srcdir)/config/rl78/lshrsi3.S \
+	$(srcdir)/config/rl78/mulsi3.S \
+	$(srcdir)/config/rl78/cmpsi2.S
Index: libgcc/config/rl78/cmpsi2.S
===================================================================
--- libgcc/config/rl78/cmpsi2.S	(revision 0)
+++ libgcc/config/rl78/cmpsi2.S	(revision 0)
@@ -0,0 +1,122 @@
+;   Copyright (C) 2011 Free Software Foundation, Inc.
+;   Contributed by Red Hat.
+; 
+; This file is free software; you can redistribute it and/or modify it
+; under the terms of the GNU General Public License as published by the
+; Free Software Foundation; either version 3, or (at your option) any
+; later version.
+; 
+; This file is distributed in the hope that it will be useful, but
+; WITHOUT ANY WARRANTY; without even the implied warranty of
+; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+; General Public License for more details.
+; 
+; Under Section 7 of GPL version 3, you are granted additional
+; permissions described in the GCC Runtime Library Exception, version
+; 3.1, as published by the Free Software Foundation.
+;
+; You should have received a copy of the GNU General Public License and
+; a copy of the GCC Runtime Library Exception along with this program;
+; see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
+; <http://www.gnu.org/licenses/>.
+
+
+; clobberable
+r8	=	0xffef0
+
+	.text
+
+	;;   int __cmpsi2 (signed long A, signed long B)
+	;;
+	;; Performs a signed comparison of A and B.
+	;; If A is less than B it returns 0.  If A is greater
+	;; than B it returns 2.  If they are equal it returns 1.
+
+	.global	___cmpsi2
+        .type   ___cmpsi2, @function
+___cmpsi2:
+	;; A is at [sp+4]
+	;; B is at [sp+8]
+	;; Result put in R8
+
+	;; Initialise default return value.
+	onew	bc
+	
+	;;  Compare the high words.
+	movw	ax, [sp + 10]
+	movw	de, ax
+	movw	ax, [sp + 6]
+	cmpw	ax, de
+	skz
+	br	!!.Lconvert_to_signed
+
+.Lcompare_bottom_words:	
+	;; The top words are equal - compare the bottom words.
+	;; Note - code from __ucmpsi2 branches into here.
+	movw   ax, [sp + 8]
+	movw   de, ax
+	movw   ax, [sp + 4]
+	cmpw   ax, de
+	sknz
+	br	!!.Lless_than_or_greater_than
+	;; The words are equal - return 1.
+	;; Note - we could branch to the return code at the end of the
+	;; function but a branch instruction takes 4 bytes, and the
+	;; return sequence itself is only 4 bytes long...
+	movw	ax, bc
+	movw	r8, ax
+	ret
+
+.Lconvert_to_signed:	
+	;; The top words are different.  Unfortunately the comparison
+	;; is always unsigned, so to get a signed result we XOR the CY
+	;; flag with the top bits of AX and DE.
+	xor1	cy, a.7
+	mov	a, d
+	xor1	cy, a.7
+	;; Fall through.
+
+.Lless_than_or_greater_than:
+	;; We now have a signed less than/greater than result in CY.
+	;; Return 0 for less than, 2 for greater than.
+	;; Note - code from __ucmpsi2 branches into here.
+	incw	bc
+	sknc
+	clrw	bc
+
+	;; Get the result value, currently in BC, into r8
+	movw	ax, bc
+	movw	r8, ax
+	ret
+
+	.size	___cmpsi2, . - ___cmpsi2
+	
+	
+	;;   int __ucmpsi2 (unsigned long A, unsigned long B)
+	;;
+	;; Performs an unsigned comparison of A and B.
+	;; If A is less than B it returns 0.  If A is greater
+	;; than B it returns 2.  If they are equal it returns 1.
+
+	.global	___ucmpsi2
+        .type   ___ucmpsi2, @function
+___ucmpsi2:
+	;; A is at [sp+4]
+	;; B is at [sp+8]
+	;; Result put in R8..R9
+
+	;; Initialise default return value.
+	onew	bc
+
+	;;  Compare the high words.
+	movw	ax, [sp + 10]
+	movw	de, ax
+	movw	ax, [sp + 6]
+	cmpw	ax, de
+	skz
+	;; Note: These branches go into the __cmpsi2 code!
+	br	!!.Lless_than_or_greater_than
+	br	!!.Lcompare_bottom_words
+
+	.size	___ucmpsi2, . - ___ucmpsi2
+	
\ No newline at end of file
Index: gcc/doc/extend.texi
===================================================================
--- gcc/doc/extend.texi	(revision 180992)
+++ gcc/doc/extend.texi	(working copy)
@@ -1218,13 +1218,13 @@ Fixed-point types are supported by the D
 @cindex named address spaces
 
 As an extension, the GNU C compiler supports named address spaces as
 defined in the N1275 draft of ISO/IEC DTR 18037.  Support for named
 address spaces in GCC will evolve as the draft technical report changes.
 Calling conventions for any target might also change.  At present, only
-the SPU and M32C targets support other address spaces.  On the SPU target, for
+the SPU, M32C, and RL78 targets support other address spaces.  On the SPU target, for
 example, variables may be declared as belonging to another address space
 by qualifying the type with the @code{__ea} address space identifier:
 
 @smallexample
 extern int __ea i;
 @end smallexample
@@ -1240,12 +1240,17 @@ document for more details.
 
 On the M32C target, with the R8C and M16C cpu variants, variables
 qualified with @code{__far} are accessed using 32-bit addresses in
 order to access memory beyond the first 64k bytes.  If @code{__far} is
 used with the M32CM or M32C cpu variants, it has no effect.
 
+On the RL78 target, variables qualified with @code{__far} are accessed
+with 32-bit pointers (20 bit addresses) rather than the default 16-bit
+addresses.  Non-far variables are assumed to appear in the topmost 64K
+of the address space.
+
 @node Zero Length
 @section Arrays of Length Zero
 @cindex arrays of length zero
 @cindex zero-length arrays
 @cindex length-zero arrays
 @cindex flexible array members
@@ -2549,13 +2554,13 @@ then be sure to write this declaration i
 
 This attribute is ignored for R8C target.
 
 @item interrupt
 @cindex interrupt handler functions
 Use this attribute on the ARM, AVR, M32C, M32R/D, m68k, MeP, MIPS,
-RX and Xstormy16 ports to indicate that the specified function is an
+RL78, RX and Xstormy16 ports to indicate that the specified function is an
 interrupt handler.  The compiler will generate function entry and exit
 sequences suitable for use in an interrupt handler when this attribute
 is present.
 
 Note, interrupt handlers for the Blackfin, H8/300, H8/300H, H8S, MicroBlaze,
 and SH processors can be specified via the @code{interrupt_handler} attribute.
@@ -2607,12 +2612,16 @@ void __attribute__ ((interrupt, keep_int
                      use_debug_exception_return)) v6 ();
 void __attribute__ ((interrupt, use_shadow_register_set,
                      keep_interrupts_masked,
                      use_debug_exception_return)) v7 ();
 @end smallexample
 
+On RL78, use @code{brk_interrupt} instead of @code{interrupt} for
+handlers intended to be used with the @code{BRK} opcode (i.e.  those
+that must end with @code{RETB} instead of @code{RETI}).
+
 @item ifunc ("@var{resolver}")
 @cindex @code{ifunc} attribute
 The @code{ifunc} attribute is used to mark a function as an indirect
 function using the STT_GNU_IFUNC symbol type extension to the ELF
 standard.  This allows the resolution of the symbol value to be
 determined dynamically at load time, and an optimized version of the
Index: gcc/doc/invoke.texi
===================================================================
--- gcc/doc/invoke.texi	(revision 180992)
+++ gcc/doc/invoke.texi	(working copy)
@@ -818,12 +818,15 @@ See RS/6000 and PowerPC Options.
 -mrecip -mrecip=@var{opt} -mno-recip -mrecip-precision @gol
 -mno-recip-precision @gol
 -mveclibabi=@var{type} -mfriz -mno-friz @gol
 -mpointers-to-nested-functions -mno-pointers-to-nested-functions @gol
 -msave-toc-indirect -mno-save-toc-indirect}
 
+@emph{RL78 Options}
+@gccoptlist{-msim -mmul=none -mmul=g13 -mmul=rl78}
+
 @emph{RX Options}
 @gccoptlist{-m64bit-doubles  -m32bit-doubles  -fpu  -nofpu@gol
 -mcpu=@gol
 -mbig-endian-data -mlittle-endian-data @gol
 -msmall-data @gol
 -msim  -mno-sim@gol
@@ -10254,12 +10257,13 @@ platform.
 * MMIX Options::
 * MN10300 Options::
 * PDP-11 Options::
 * picoChip Options::
 * PowerPC Options::
 * RS/6000 and PowerPC Options::
+* RL78 Options::
 * RX Options::
 * S/390 and zSeries Options::
 * Score Options::
 * SH Options::
 * Solaris 2 Options::
 * SPARC Options::
@@ -16717,12 +16721,35 @@ Generate (do not generate) code to save 
 stack location in the function prologue if the function calls through
 a pointer on AIX and 64-bit Linux systems.  If the TOC value is not
 saved in the prologue, it is saved just before the call through the
 pointer.  The @option{-mno-save-toc-indirect} option is the default.
 @end table
 
+@node RL78 Options
+@subsection RL78 Options
+@cindex RL78 Options
+
+@table @gcctabopt
+
+@item -msim
+@opindex msim
+Link in additional target libraries to support operation within a
+simulator.
+
+@item -mmul=none
+@itemx -mmul=g13
+@itemx -mmul=rl78
+@opindex mmul
+Selects the type of hardware multiplication support desired.  The
+default is @code{none}, which uses software multiplication functions.
+The @code{g13} option is for the hardware multiply/divide peripheral
+only on the RL78/G13 targets.  The @code{rl78} option is for the
+standard hardware multiplication defined in the RL78 software manual.
+
+@end table
+
 @node RX Options
 @subsection RX Options
 @cindex RX Options
 
 These command line options are defined for RX targets:
 
Index: gcc/doc/contrib.texi
===================================================================
--- gcc/doc/contrib.texi	(revision 180992)
+++ gcc/doc/contrib.texi	(working copy)
@@ -213,13 +213,13 @@ Bud Davis for work on the G77 and GNU Fo
 
 @item
 Mo DeJong for GCJ and libgcj bug fixes.
 
 @item
 DJ Delorie for the DJGPP port, build and libiberty maintenance,
-various bug fixes, and the M32C and MeP ports.
+various bug fixes, and the M32C, MeP, and RL78 ports.
 
 @item
 Arnaud Desitter for helping to debug GNU Fortran.
 
 @item
 Gabriel Dos Reis for contributions to G++, contributions and
Index: gcc/doc/md.texi
===================================================================
--- gcc/doc/md.texi	(revision 180992)
+++ gcc/doc/md.texi	(working copy)
@@ -2905,12 +2905,102 @@ offset) after the opcode.
 
 @item R
 A memory reference that is encoded within the opcode.
 
 @end table
 
+@item RL78---@file{config/rl78/constraints.md}
+@table @code
+
+@item Int3
+An integer constant in the range 1 @dots{} 7.
+@item Int8
+An integer constant in the range 0 @dots{} 255.
+@item J
+An integer constant in the range @minus{}255 @dots{} 0
+@item K
+The integer constant 1.
+@item L
+The integer constant -1.
+@item M
+The integer constant 0.
+@item N
+The integer constant 2.
+@item O
+The integer constant -2.
+@item P
+An integer constant in the range 1 @dots{} 15.
+@item Qbi
+The built-in compare types--eq, ne, gtu, ltu, geu, and leu.
+@item Qsc
+The synthetic compare types--gt, lt, ge, and le.
+@item Wab
+A memory reference with an absolute address.
+@item Wbc
+A memory reference using @code{BC} as a base register, with an optional offset.
+@item Wca
+A memory reference using @code{AX}, @code{BC}, @code{DE}, or @code{HL} for the address, for calls.
+@item Wcv
+A memory reference using any 16-bit register pair for the address, for calls.
+@item Wd2
+A memory reference using @code{DE} as a base register, with an optional offset.
+@item Wde
+A memory reference using @code{DE} as a base register, without any offset.
+@item Wfr
+Any memory reference to an address in the far address space.
+@item Wh1
+A memory reference using @code{HL} as a base register, with an optional one-byte offset.
+@item Whb
+A memory reference using @code{HL} as a base register, with @code{B} or @code{C} as the index register.
+@item Whl
+A memory reference using @code{HL} as a base register, without any offset.
+@item Ws1
+A memory reference using @code{SP} as a base register, with an optional one-byte offset.
+@item Y
+Any memory reference to an address in the near address space.
+@item A
+The @code{AX} register.
+@item B
+The @code{BC} register.
+@item D
+The @code{DE} register.
+@item R
+@code{A} through @code{L} registers.
+@item S
+The @code{SP} register.
+@item T
+The @code{HL} register.
+@item Z08W
+The 16-bit @code{R8} register.
+@item Z10W
+The 16-bit @code{R10} register.
+@item Zint
+The registers reserved for interrupts (@code{R24} to @code{R31}).
+@item a
+The @code{A} register.
+@item b
+The @code{B} register.
+@item c
+The @code{C} register.
+@item d
+The @code{D} register.
+@item e
+The @code{E} register.
+@item h
+The @code{H} register.
+@item l
+The @code{L} register.
+@item v
+The virtual registers.
+@item w
+The @code{PSW} register.
+@item x
+The @code{X} register.
+
+@end table
+
 @item RX---@file{config/rx/constraints.md}
 @table @code
 @item Q
 An address which does not involve register indirect addressing or
 pre/post increment/decrement addressing.
 
Index: gcc/doc/install.texi
===================================================================
--- gcc/doc/install.texi	(revision 180992)
+++ gcc/doc/install.texi	(working copy)
@@ -4126,12 +4126,20 @@ the PSIM simulator.
 @heading @anchor{powerpcle-x-eabi}powerpcle-*-eabi
 Embedded PowerPC system in little endian mode.
 
 @html
 <hr />
 @end html
+@heading @anchor{rl78-x-elf}rl78-*-elf
+The Renesas RL78 processor.  See
+@uref{http://www.renesas.com/pr/mcu/rl78/}
+for more information about this processor.
+
+@html
+<hr />
+@end html
 @heading @anchor{rx-x-elf}rx-*-elf
 The Renesas RX processor.  See
 @uref{http://eu.renesas.com/fmwk.jsp?cnt=rx600_series_landing.jsp&fp=/products/mpumcu/rx_family/rx600_series}
 for more information about this processor.
 
 @html
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 180992)
+++ gcc/config.gcc	(working copy)
@@ -2098,12 +2098,19 @@ rs6000-ibm-aix[6789].* | powerpc-ibm-aix
 	extra_options="${extra_options} rs6000/aix64.opt"
 	use_collect2=yes
 	thread_file='aix'
 	use_gcc_stdint=wrap
 	extra_headers=altivec.h
 	;;
+rl78-*-elf*)
+	tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}"
+	target_has_targetm_common=no
+	c_target_objs="rl78-c.o"
+	cxx_target_objs="rl78-c.o"
+	tmake_file="${tmake_file} rl78/t-rl78"
+	;;
 rx-*-elf*)
 	tm_file="dbxelf.h elfos.h newlib-stdint.h ${tm_file}"
 	tmake_file="${tmake_file} rx/t-rx"
 	;;
 s390-*-linux*)
 	tm_file="s390/s390.h dbxelf.h elfos.h gnu-user.h linux.h glibc-stdint.h s390/linux.h"
Index: gcc/config/rl78/predicates.md
===================================================================
--- gcc/config/rl78/predicates.md	(revision 0)
+++ gcc/config/rl78/predicates.md	(revision 0)
@@ -0,0 +1,60 @@
+;;  Machine Description for Renesas RL78 processors
+;;  Copyright (C) 2011 Free Software Foundation, Inc.
+;;  Contributed by Red Hat.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_predicate "rl78_any_operand"
+  (ior (match_operand 0 "general_operand")
+       (match_code "mem,const_int,const_double,reg"))
+)
+
+(define_predicate "rl78_nonfar_operand"
+  (and (match_operand 0 "general_operand")
+       (not (match_test "rl78_far_p (op)")))
+)
+
+(define_predicate "rl78_nonfar_nonimm_operand"
+  (and (match_operand 0 "nonimmediate_operand")
+       (not (match_test "rl78_far_p (op)")))
+)
+
+(define_predicate "ubyte_operand"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (INTVAL (op), 0, 255)")))
+
+(define_predicate "rl78_24_operand"
+  (and (match_code "const_int")
+       (match_test "INTVAL (op) == 2 || INTVAL (op) == 4")))
+
+(define_predicate "uword_operand"
+  (ior (match_code "const")
+       (and (match_code "const_int")
+	    (match_test "IN_RANGE (INTVAL (op), 0, 65536)"))))
+
+(define_predicate "rl78_cmp_operator_real"
+  (match_code "eq,ne,gtu,ltu,geu,leu"))
+(define_predicate "rl78_cmp_operator"
+  (match_code "eq,ne,gtu,ltu,geu,leu,gt,lt,ge,le"))
+
+(define_predicate "rl78_ax_operand"
+  (and (match_code "reg")
+       (match_test "REGNO (op) == AX_REG || REGNO (op) >= FIRST_PSEUDO_REGISTER")))
+
+(define_predicate "rl78_addw_operand"
+  (and (match_code "reg")
+       (match_test "REGNO (op) == AX_REG || REGNO (op) == SP_REG || REGNO (op) >= FIRST_PSEUDO_REGISTER")))
Index: gcc/config/rl78/rl78.h
===================================================================
--- gcc/config/rl78/rl78.h	(revision 0)
+++ gcc/config/rl78/rl78.h	(revision 0)
@@ -0,0 +1,462 @@
+/* GCC backend definitions for the Renesas RL78 processor.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+
+#define RL78_MUL_NONE	(rl78_mul_type == MUL_NONE)
+#define RL78_MUL_RL78	(rl78_mul_type == MUL_RL78)
+#define RL78_MUL_G13	(rl78_mul_type == MUL_G13)
+
+#define TARGET_CPU_CPP_BUILTINS()               \
+  do                                            \
+    {                                           \
+      builtin_define ("__RL78__"); 		\
+      builtin_assert ("cpu=RL78"); 		\
+      if (RL78_MUL_RL78)			\
+	builtin_define ("__RL78_MUL_RL78__"); 	\
+      if (RL78_MUL_G13)				\
+	builtin_define ("__RL78_MUL_G13__"); 	\
+    }                                           \
+  while (0)
+
+#undef  STARTFILE_SPEC
+#define STARTFILE_SPEC "%{pg:gcrt0.o%s}%{!pg:crt0.o%s} crtbegin.o%s"
+
+#undef  ENDFILE_SPEC
+#define ENDFILE_SPEC "crtend.o%s crtn.o%s"
+
+#undef  LIB_SPEC
+#define LIB_SPEC "					\
+--start-group						\
+-lc							\
+-lsim							\
+%{fprofile-arcs|fprofile-generate|coverage:-lgcov} 	\
+--end-group					   	\
+%{!T*: %{msim:%Trl78-sim.ld}%{!msim:%Trl78.ld}}		\
+"
+
+
+#define BITS_BIG_ENDIAN 		0
+#define BYTES_BIG_ENDIAN 		0
+#define WORDS_BIG_ENDIAN 		0
+
+#ifdef IN_LIBGCC2
+/* This is to get correct SI and DI modes in libgcc2.c (32 and 64 bits).  */
+#define	UNITS_PER_WORD			4
+/* We have a problem with libgcc2.  It only defines two versions of
+   each function, one for "int" and one for "long long".  Ie it assumes
+   that "sizeof (int) == sizeof (long)".  For the RL78 this is not true
+   and we need a third set of functions.  We explicitly define
+   LIBGCC2_UNITS_PER_WORD here so that it is clear that we are expecting
+   to get the SI and DI versions from the libgcc2.c sources, and we
+   provide our own set of HI functions, which is why this
+   definition is surrounded by #ifndef..#endif.  */
+#ifndef LIBGCC2_UNITS_PER_WORD
+#define LIBGCC2_UNITS_PER_WORD 		4
+#endif
+#else
+/* Actual width of a word, in units (bytes).  */
+#define	UNITS_PER_WORD 			1
+#endif
+
+#define SHORT_TYPE_SIZE			16
+#define INT_TYPE_SIZE			16
+#define LONG_TYPE_SIZE			32
+#define LONG_LONG_TYPE_SIZE		64
+
+#define FLOAT_TYPE_SIZE 		32
+#define DOUBLE_TYPE_SIZE 		32 /*64*/
+#define LONG_DOUBLE_TYPE_SIZE		64 /*DOUBLE_TYPE_SIZE*/
+
+#define LIBGCC2_HAS_DF_MODE		1
+#define LIBGCC2_LONG_DOUBLE_TYPE_SIZE   64
+
+#define DEFAULT_SIGNED_CHAR		0
+
+#define STRICT_ALIGNMENT 		1
+#define FUNCTION_BOUNDARY 		8
+#define BIGGEST_ALIGNMENT 		16
+#define STACK_BOUNDARY 			16
+#define PARM_BOUNDARY 			16
+
+#define STACK_GROWS_DOWNWARD		1
+#define FRAME_GROWS_DOWNWARD		1
+#define FIRST_PARM_OFFSET(FNDECL) 	0
+
+#define MAX_REGS_PER_ADDRESS 		1
+
+#define Pmode 				HImode
+#define POINTER_SIZE			16
+#undef  SIZE_TYPE
+#define SIZE_TYPE			"unsigned int"
+#undef  PTRDIFF_TYPE
+#define PTRDIFF_TYPE			"int"
+#undef  WCHAR_TYPE
+#define WCHAR_TYPE			"long int"
+#undef  WCHAR_TYPE_SIZE
+#define WCHAR_TYPE_SIZE			BITS_PER_WORD
+#define POINTERS_EXTEND_UNSIGNED	1
+#define FUNCTION_MODE 			HImode
+#define CASE_VECTOR_MODE		Pmode
+#define WORD_REGISTER_OPERATIONS	0
+#define HAS_LONG_COND_BRANCH		0
+#define HAS_LONG_UNCOND_BRANCH		0
+
+#define MOVE_MAX 			2
+#define STARTING_FRAME_OFFSET		0
+
+#define TRULY_NOOP_TRUNCATION(OUTPREC, INPREC)   1
+
+#define ADDR_SPACE_FAR	1
+
+#define HAVE_PRE_DECCREMENT		0
+#define HAVE_POST_INCREMENT		0
+
+#define MOVE_RATIO(SPEED) 		((SPEED) ? 24 : 16)
+#define SLOW_BYTE_ACCESS		0
+
+#define STORE_FLAG_VALUE		1
+#define LOAD_EXTEND_OP(MODE)		ZERO_EXTEND
+#define SHORT_IMMEDIATES_SIGN_EXTEND	0
+
+
+/* The RL78 has four register banks.  Normal operation uses RB0 as
+   real registers, RB1 and RB2 as "virtual" registers (because we know
+   they'll be there, and not used as variables), and RB3 is reserved
+   for interrupt handlers.  The virtual registers are accessed as
+   SADDRs:
+
+   FFEE0-FFEE7 RB0
+   FFEE8-FFEEF RB1
+   FFEF0-FFEF7 RB2
+   FFEF8-FFEFF RB3
+*/
+#define REGISTER_NAMES						\
+  {								\
+    "x", "a", "c", "b", "e", "d", "l", "h", 			\
+    "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",	\
+    "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",	\
+    "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",	\
+      "sp", "ap", "psw", "es", "cs"				\
+  }
+
+#define ADDITIONAL_REGISTER_NAMES	\
+{					\
+{ "ax", 0 }, \
+{ "bc", 2 }, \
+{ "de", 4 }, \
+{ "hl", 6 }, \
+{ "rp0", 0 }, \
+{ "rp1", 2 }, \
+{ "rp2", 4 }, \
+{ "rp3", 6 }, \
+{ "r0", 0 }, \
+{ "r1", 1 }, \
+{ "r2", 2 }, \
+{ "r3", 3 }, \
+{ "r4", 4 }, \
+{ "r5", 5 }, \
+{ "r6", 6 }, \
+{ "r7", 7 }, \
+}
+
+enum reg_class
+{
+  NO_REGS,			/* No registers in set.  */
+  XREG,
+  AREG,
+  AXREG,
+  CREG,
+  BREG,
+  BCREG,
+  EREG,
+  DREG,
+  DEREG,
+  LREG,
+  HREG,
+  HLREG,
+  IDX_REGS,
+  QI_REGS,
+  SPREG,
+  R8W_REGS,
+  R10W_REGS,
+  INT_REGS,
+  V_REGS,			/* Virtual registers.  */
+  GR_REGS,			/* Integer registers.  */
+  PSWREG,
+  ALL_REGS,			/* All registers.  */
+  LIM_REG_CLASSES		/* Max value + 1.  */
+};
+
+#define REG_CLASS_NAMES					\
+{							\
+  "NO_REGS",						\
+  "XREG",						\
+  "AREG",						\
+  "AXREG",						\
+  "CREG",						\
+  "BREG",						\
+  "BCREG",						\
+  "EREG",						\
+  "DREG",						\
+  "DEREG",						\
+  "LREG",						\
+  "HREG",						\
+  "HLREG",						\
+  "IDX_REGS",						\
+  "QI_REGS",						\
+  "SPREG",						\
+  "R8W_REGS",						\
+  "R10W_REGS",						\
+  "INT_REGS",						\
+  "V_REGS",						\
+  "GR_REGS",						\
+  "PSWREG",						\
+  "ALL_REGS"						\
+}
+
+#define REG_CLASS_CONTENTS				\
+{							\
+  { 0x00000000, 0x00000000 },	/* No registers,  */		\
+  { 0x00000001, 0x00000000 }, \
+  { 0x00000002, 0x00000000 }, \
+  { 0x00000003, 0x00000000 }, \
+  { 0x00000004, 0x00000000 }, \
+  { 0x00000008, 0x00000000 }, \
+  { 0x0000000c, 0x00000000 }, \
+  { 0x00000010, 0x00000000 }, \
+  { 0x00000020, 0x00000000 }, \
+  { 0x00000030, 0x00000000 }, \
+  { 0x00000040, 0x00000000 }, \
+  { 0x00000080, 0x00000000 }, \
+  { 0x000000c0, 0x00000000 }, \
+  { 0x0000000c, 0x00000000 },	/* B and C - index regs.  */	\
+  { 0x000000ff, 0x00000000 },	/* all real registers.  */	\
+  { 0x00000000, 0x00000001 }, 	/* SP */			\
+  { 0x00000300, 0x00000000 }, 	/* R8 - HImode */		\
+  { 0x00000c00, 0x00000000 }, 	/* R10 - HImode */		\
+  { 0xff000000, 0x00000000 }, 	/* INT - HImode */		\
+  { 0x007fff00, 0x00000000 },	/* Virtual registers.  */	\
+  { 0xff7fffff, 0x00000002 },	/* General registers.  */	\
+  { 0x04000000, 0x00000004 },	/* PSW.  */	\
+  { 0xff7fffff, 0x0000001f }	/* All registers.  */		\
+}
+
+#define SMALL_REGISTER_CLASSES 		1
+#define N_REG_CLASSES			(int) LIM_REG_CLASSES
+#define CLASS_MAX_NREGS(CLASS, MODE)    ((GET_MODE_SIZE (MODE) \
+					  + UNITS_PER_WORD - 1) \
+					 / UNITS_PER_WORD)
+
+#define GENERAL_REGS			GR_REGS
+#define BASE_REG_CLASS  		V_REGS
+#define INDEX_REG_CLASS			V_REGS
+
+#define FIRST_PSEUDO_REGISTER 		37
+
+#define REGNO_REG_CLASS(REGNO)          ((REGNO) < FIRST_PSEUDO_REGISTER \
+					 ? GR_REGS : NO_REGS)
+
+#define FRAME_POINTER_REGNUM 		22
+#define STACK_POINTER_REGNUM 	        32
+#define ARG_POINTER_REGNUM 		33
+#define CC_REGNUM                       34
+#define FUNC_RETURN_REGNUM              8
+#define STATIC_CHAIN_REGNUM 		14
+
+/* Trampolines are implemented with a separate data stack.  The memory
+   on stack only holds the function pointer for the chosen stub.
+ */
+
+#define TRAMPOLINE_SIZE			4
+#define TRAMPOLINE_ALIGNMENT		16
+
+#define ELIMINABLE_REGS					\
+{{ ARG_POINTER_REGNUM,   STACK_POINTER_REGNUM },	\
+ { ARG_POINTER_REGNUM,   FRAME_POINTER_REGNUM },	\
+ { FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM }}
+
+#define INITIAL_ELIMINATION_OFFSET(FROM, TO, OFFSET)	\
+  (OFFSET) = rl78_initial_elimination_offset ((FROM), (TO))
+
+
+#define FUNCTION_ARG_REGNO_P(N)	  	0
+#define FUNCTION_VALUE_REGNO_P(N) 	((N) == 8)
+#define DEFAULT_PCC_STRUCT_RETURN	0
+
+#define FIXED_REGISTERS					\
+{							\
+  1,1,1,1, 1,1,1,1,					\
+  0,0,0,0, 0,0,0,0,					\
+  0,0,0,0, 0,0,1,1,					\
+  1,1,1,1, 1,1,1,1,					\
+  0, 1, 0, 1, 1						\
+}
+
+#define CALL_USED_REGISTERS				\
+{							\
+  1,1,1,1, 1,1,1,1,					\
+  1,1,1,1, 1,1,1,1,					\
+  0,0,0,0, 0,0,1,1,					\
+  1,1,1,1, 1,1,1,1,					\
+  0, 1, 1, 1, 1						\
+}
+
+#define LIBCALL_VALUE(MODE)				\
+  gen_rtx_REG ((MODE),					\
+	       FUNC_RETURN_REGNUM)
+
+/* Order of allocation of registers.  */
+
+#define REG_ALLOC_ORDER					\
+  { 8, 9, 10, 11, 12, 13, 14, 15,			\
+    16, 17, 18, 19, 20, 21, 22, 23,			\
+    0, 1, 6, 7, 2, 3, 4, 5,				\
+    24, 25, 26, 27, 28, 29, 30, 31,			\
+    32, 33, 34						\
+}
+
+#define REGNO_IN_RANGE(REGNO, MIN, MAX)			\
+  (IN_RANGE ((REGNO), (MIN), (MAX)) 			\
+   || (reg_renumber != NULL				\
+       && reg_renumber[(REGNO)] >= (MIN)		\
+       && reg_renumber[(REGNO)] <= (MAX)))
+
+#ifdef REG_OK_STRICT
+#define REGNO_OK_FOR_BASE_P(regno)      REGNO_IN_RANGE (regno, 16, 23)
+#else
+#define REGNO_OK_FOR_BASE_P(regno)	1
+#endif
+
+#define REGNO_OK_FOR_INDEX_P(regno)	REGNO_OK_FOR_BASE_P (regno)
+
+#define REGNO_MODE_CODE_OK_FOR_BASE_P(regno, mode, outer_code, index_code) \
+  rl78_regno_mode_code_ok_for_base_p (regno, mode, outer_code, index_code)
+
+#define MODE_CODE_BASE_REG_CLASS(mode, outer_code, index_code) \
+  rl78_mode_code_base_reg_class (mode, outer_code, index_code)
+
+#define RETURN_ADDR_RTX(COUNT, FRAMEADDR)				\
+  ((COUNT) == 0								\
+   ? gen_rtx_MEM (Pmode, gen_rtx_PLUS (HImode, arg_pointer_rtx, GEN_INT (-4))) \
+   : NULL_RTX)
+
+#define INCOMING_RETURN_ADDR_RTX	gen_rtx_MEM (Pmode, stack_pointer_rtx)
+
+#define ACCUMULATE_OUTGOING_ARGS	1
+
+typedef unsigned int CUMULATIVE_ARGS;
+
+#define INIT_CUMULATIVE_ARGS(CUM, FNTYPE, LIBNAME, INDIRECT, N_NAMED_ARGS) \
+  (CUM) = 0
+
+
+/* FIXME */
+#define NO_PROFILE_COUNTERS     1
+#define PROFILE_BEFORE_PROLOGUE 1
+
+#define FUNCTION_PROFILER(FILE, LABELNO)	\
+    fprintf (FILE, "\tbsr\t__mcount\n");
+
+
+#define HARD_REGNO_NREGS(REGNO, MODE)            \
+  rl78_hard_regno_nregs (REGNO, MODE)
+
+#define HARD_REGNO_MODE_OK(REGNO, MODE) 			\
+  rl78_hard_regno_mode_ok (REGNO, MODE)
+
+#define MODES_TIEABLE_P(MODE1, MODE2)				\
+  (   (   GET_MODE_CLASS (MODE1) == MODE_FLOAT			\
+       || GET_MODE_CLASS (MODE1) == MODE_COMPLEX_FLOAT)		\
+   == (   GET_MODE_CLASS (MODE2) == MODE_FLOAT			\
+       || GET_MODE_CLASS (MODE2) == MODE_COMPLEX_FLOAT))
+
+
+#define TEXT_SECTION_ASM_OP ".text"
+#define DATA_SECTION_ASM_OP ".data"
+#define BSS_SECTION_ASM_OP ".bss"
+#define CTORS_SECTION_ASM_OP ".section \".ctors\",\"a\""
+#define DTORS_SECTION_ASM_OP ".section \".dtors\",\"a\""
+
+#define ASM_COMMENT_START	" ;"
+#define ASM_APP_ON		""
+#define ASM_APP_OFF 		""
+#define LOCAL_LABEL_PREFIX	".L"
+#undef  USER_LABEL_PREFIX
+#define USER_LABEL_PREFIX	"_"
+
+#define GLOBAL_ASM_OP 		"\t.global\t"
+
+#define ASM_OUTPUT_ADDR_VEC_ELT(FILE, VALUE) \
+  fprintf (FILE, "\t.long .L%d\n", VALUE)
+
+/* This is how to output an element of a case-vector that is relative.
+   Note: The local label referenced by the "3b" below is emitted by
+   the tablejump insn.  */
+
+#define ASM_OUTPUT_ADDR_DIFF_ELT(FILE, BODY, VALUE, REL) \
+  fprintf (FILE, "\t.long .L%d - 1b\n", VALUE)
+
+
+#define ASM_OUTPUT_ALIGN(STREAM, LOG)		\
+  do						\
+    {						\
+      if ((LOG) == 0)				\
+        break;					\
+      fprintf (STREAM, "\t.balign %d\n", 1 << (LOG));	\
+    }						\
+  while (0)
+
+/* For PIC put jump tables into the text section so that the offsets that
+   they contain are always computed between two same-section symbols.  */
+#define JUMP_TABLES_IN_TEXT_SECTION	(flag_pic)
+
+/* This is a version of REG_P that also returns TRUE for SUBREGs.  */
+#define RL78_REG_P(rtl) (REG_P (rtl) || GET_CODE (rtl) == SUBREG)
+
+/* Like REG_P except that this macro is true for SET expressions.  */
+#define SET_P(rtl)    (GET_CODE (rtl) == SET)
+
+#undef  PREFERRED_DEBUGGING_TYPE
+#define PREFERRED_DEBUGGING_TYPE DWARF2_DEBUG
+
+#undef	DWARF2_ADDR_SIZE
+#define	DWARF2_ADDR_SIZE			4
+
+#define DWARF2_ASM_LINE_DEBUG_INFO		1
+
+#define EXIT_IGNORE_STACK			0
+#define INCOMING_FRAME_SP_OFFSET		4
+
+
+#define BRANCH_COST(SPEED,PREDICT)       1
+#define REGISTER_MOVE_COST(MODE,FROM,TO) 2
+
+#define EH_RETURN_DATA_REGNO(N) (N < 2 ? (8+(N)*2) : INVALID_REGNUM)
+#define EH_RETURN_STACKADJ_RTX gen_rtx_REG (HImode, 20)
+
+#define ASM_PREFERRED_EH_DATA_FORMAT(CODE,GLOBAL) DW_EH_PE_udata4
+
+/* NOTE: defined but zero means dwarf2 debugging, but sjlj EH.  */
+#define DWARF2_UNWIND_INFO 0
+/*#define DONT_USE_BUILTIN_SETJMP 1*/
+#undef DONT_USE_BUILTIN_SETJMP
+#define JMP_BUF_SIZE (8*3+8)
+
+#define REGISTER_TARGET_PRAGMAS() rl78_register_pragmas()
Index: gcc/config/rl78/rl78-opts.h
===================================================================
--- gcc/config/rl78/rl78-opts.h	(revision 0)
+++ gcc/config/rl78/rl78-opts.h	(revision 0)
@@ -0,0 +1,30 @@
+/* GCC option-handling definitions for the Renesas RL78 processor.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify it
+   under the terms of the GNU General Public License as published
+   by the Free Software Foundation; either version 3, or (at your
+   option) any later version.
+
+   GCC is distributed in the hope that it will be useful, but WITHOUT
+   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
+   or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
+   License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#ifndef RL78_OPTS_H
+#define RL78_OPTS_H
+
+enum rl78_mul_types
+{
+  MUL_NONE,
+  MUL_RL78,
+  MUL_G13
+};
+
+#endif
Index: gcc/config/rl78/rl78-protos.h
===================================================================
--- gcc/config/rl78/rl78-protos.h	(revision 0)
+++ gcc/config/rl78/rl78-protos.h	(revision 0)
@@ -0,0 +1,43 @@
+/* Prototypes for Renesas RL78 processors
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+void		rl78_emit_eh_epilogue (rtx);
+void		rl78_expand_compare (rtx *);
+void		rl78_expand_movsi (rtx *);
+int		rl78_force_nonfar_2 (rtx *, rtx (*gen)(rtx,rtx));
+int		rl78_force_nonfar_3 (rtx *, rtx (*gen)(rtx,rtx,rtx));
+void		rl78_expand_eh_epilogue (rtx);
+void		rl78_expand_epilogue (void);
+void		rl78_expand_prologue (void);
+int		rl78_far_p (rtx x);
+int		rl78_hard_regno_mode_ok (int, enum machine_mode);
+int		rl78_hard_regno_nregs (int, enum machine_mode);
+bool		rl78_hl_b_c_addr_p (rtx);
+int		rl78_initial_elimination_offset (int, int);
+bool		rl78_as_legitimate_address (enum machine_mode, rtx,
+					    bool, addr_space_t);
+int		rl78_legitimize_reload_address (rtx *, enum machine_mode, int,int, int);
+enum reg_class	rl78_mode_code_base_reg_class (enum machine_mode, int, int);
+bool		rl78_peep_movhi_p (rtx *);
+bool		rl78_real_insns_ok (void);
+void		rl78_register_pragmas (void);
+bool		rl78_regno_mode_code_ok_for_base_p (int, enum machine_mode, int, int);
+void		rl78_setup_peep_movhi (rtx *);
+bool		rl78_virt_insns_ok (void);
Index: gcc/config/rl78/constraints.md
===================================================================
--- gcc/config/rl78/constraints.md	(revision 0)
+++ gcc/config/rl78/constraints.md	(revision 0)
@@ -0,0 +1,266 @@
+;;  Machine Description for Renesas RL78 processors
+;;  Copyright (C) 2011 Free Software Foundation, Inc.
+;;  Contributed by Red Hat.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+; Constraints in use:
+
+; core:
+; V X g i m n o p r s < >
+; 0..9
+; I..Q - integers
+;   Int8 = 0..255
+;   Int3 = 1..7
+;   J = -255..0
+;   K = 1
+;   L = -1
+;   M = 0
+;   N = 2
+;   O = -2
+;   P = 1..15
+
+; E..H - float constants
+
+; RL78-specific
+; a x b c d e h l w - 8-bit regs
+; A B D T S - 16-bit regs
+; R = all regular registers (A-L)
+; Y - any valid memory
+; Wxx - various memory addressing modes
+; Qxx - conditionals
+; v = virtual registers
+; Zxx = specific virtual registers
+
+(define_constraint "Int8"
+  "Integer constant in the range 0 @dots{} 255."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, 0, 255)")))
+
+(define_constraint "Int3"
+  "Integer constant in the range 1 @dots{} 7."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, 1, 7)")))
+
+(define_constraint "J"
+  "Integer constant in the range -255 @dots{} 0"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, -255, 0)")))
+
+(define_constraint "K"
+  "Integer constant 1."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, 1, 1)")))
+
+(define_constraint "L"
+  "Integer constant -1."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, -1, -1)")))
+
+(define_constraint "M"
+  "Integer constant 0."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, 0, 0)")))
+
+(define_constraint "N"
+  "Integer constant 2."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, 2, 2)")))
+
+(define_constraint "O"
+  "Integer constant -2."
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, -2, -2)")))
+
+(define_constraint "P"
+  "Integer constant 1..15"
+  (and (match_code "const_int")
+       (match_test "IN_RANGE (ival, 1, 15)")))
+
+(define_register_constraint "R" "QI_REGS"
+ "@code{A} through @code{L} registers.")
+
+(define_register_constraint "a" "AREG"
+ "The @code{A} register.")
+
+(define_register_constraint "x" "XREG"
+ "The @code{X} register.")
+
+(define_register_constraint "b" "BREG"
+ "The @code{B} register.")
+
+(define_register_constraint "c" "CREG"
+ "The @code{C} register.")
+
+(define_register_constraint "d" "DREG"
+ "The @code{D} register.")
+
+(define_register_constraint "e" "EREG"
+ "The @code{E} register.")
+
+(define_register_constraint "h" "HREG"
+ "The @code{H} register.")
+
+(define_register_constraint "l" "LREG"
+ "The @code{L} register.")
+
+(define_register_constraint "w" "PSWREG"
+ "The @code{PSW} register.")
+
+(define_register_constraint "A" "AXREG"
+ "The @code{AX} register.")
+
+(define_register_constraint "B" "BCREG"
+ "The @code{BC} register.")
+
+(define_register_constraint "D" "DEREG"
+ "The @code{DE} register.")
+
+; because H + L = T, assuming A=1.
+(define_register_constraint "T" "HLREG"
+ "The @code{HL} register.")
+
+(define_register_constraint "S" "SPREG"
+ "The @code{SP} register.")
+
+(define_register_constraint "v" "V_REGS"
+ "The virtual registers.")
+
+(define_register_constraint "Z08W" "R8W_REGS"
+ "The R8 register, HImode.")
+
+(define_register_constraint "Z10W" "R10W_REGS"
+ "The R10 register, HImode.")
+
+(define_register_constraint "Zint" "INT_REGS"
+ "The interrupt registers.")
+
+; All the memory addressing schemes the RL78 supports
+; of the form W {register} {bytes of offset}
+;          or W {register} {register}
+
+; absolute address
+(define_memory_constraint "Wab"
+  "[addr]"
+  (and (match_code "mem")
+       (ior (match_test "CONSTANT_P (XEXP (op, 0))")
+	    (match_test "GET_CODE (XEXP (op, 0)) == PLUS && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF"))
+	    )
+  )
+
+(define_memory_constraint "Wbc"
+  "word16[BC]"
+  (and (match_code "mem")
+       (ior
+	(and (match_code "reg" "0")
+	     (match_test "REGNO (XEXP (op, 0)) == BC_REG"))
+	(and (match_code "plus" "0")
+	     (and (and (match_code "reg" "00")
+		       (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == BC_REG"))
+		       (match_test "uword_operand (XEXP (XEXP (op, 0), 1), VOIDmode)"))))
+       )
+  )
+
+(define_memory_constraint "Wde"
+  "[DE]"
+  (and (match_code "mem")
+       (and (match_code "reg" "0")
+	    (match_test "REGNO (XEXP (op, 0)) == DE_REG")))
+  )
+
+(define_memory_constraint "Wca"
+  "[AX..HL] for calls"
+  (and (match_code "mem")
+       (and (match_code "reg" "0")
+	    (match_test "REGNO (XEXP (op, 0)) <= HL_REG")))
+  )
+
+(define_memory_constraint "Wcv"
+  "[AX..HL,r8-r23] for calls"
+  (and (match_code "mem")
+       (and (match_code "reg" "0")
+	    (match_test "REGNO (XEXP (op, 0)) < 24")))
+  )
+
+(define_memory_constraint "Wd2"
+  "word16[DE]"
+  (and (match_code "mem")
+       (ior
+	(and (match_code "reg" "0")
+	     (match_test "REGNO (XEXP (op, 0)) == DE_REG"))
+	(and (match_code "plus" "0")
+	     (and (and (match_code "reg" "00")
+		       (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == DE_REG"))
+		       (match_test "uword_operand (XEXP (XEXP (op, 0), 1), VOIDmode)"))))
+       )
+  )
+
+(define_memory_constraint "Whl"
+  "[HL]"
+  (and (match_code "mem")
+       (and (match_code "reg" "0")
+	    (match_test "REGNO (XEXP (op, 0)) == HL_REG")))
+  )
+
+(define_memory_constraint "Wh1"
+  "byte8[HL]"
+  (and (match_code "mem")
+       (and (match_code "plus" "0")
+	    (and (and (match_code "reg" "00")
+		      (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == HL_REG"))
+		      (match_test "ubyte_operand (XEXP (XEXP (op, 0), 1), VOIDmode)"))))
+  )
+
+(define_memory_constraint "Whb"
+  "[HL+B]"
+  (and (match_code "mem")
+       (match_test "rl78_hl_b_c_addr_p (XEXP (op, 0))"))
+  )
+
+(define_memory_constraint "Ws1"
+  "word8[SP]"
+  (and (match_code "mem")
+       (ior
+	(and (match_code "reg" "0")
+	     (match_test "REGNO (XEXP (op, 0)) == SP_REG"))
+	(and (match_code "plus" "0")
+	     (and (and (match_code "reg" "00")
+		       (match_test "REGNO (XEXP (XEXP (op, 0), 0)) == SP_REG"))
+		       (match_test "ubyte_operand (XEXP (XEXP (op, 0), 1), VOIDmode)"))))
+       )
+  )
+
+(define_memory_constraint "Wfr"
+  "ES/CS far pointer"
+  (and (match_code "mem")
+       (match_test "rl78_far_p (op)"))
+  )
+
+(define_memory_constraint "Y"
+  "any near legitimate memory access"
+  (and (match_code "mem")
+       (match_test "!rl78_far_p (op) && rl78_as_legitimate_address (VOIDmode, XEXP (op, 0), true, ADDR_SPACE_GENERIC)"))
+)
+
+
+(define_memory_constraint "Qbi"
+  "built-in compare types"
+  (match_code "eq,ne,gtu,ltu,geu,leu"))
+
+(define_memory_constraint "Qsc"
+  "synthetic compares"
+  (match_code "gt,lt,ge,le"))
Index: gcc/config/rl78/rl78-expand.md
===================================================================
--- gcc/config/rl78/rl78-expand.md	(revision 0)
+++ gcc/config/rl78/rl78-expand.md	(revision 0)
@@ -0,0 +1,256 @@
+;;  Machine Description for Renesas RL78 processors
+;;  Copyright (C) 2011 Free Software Foundation, Inc.
+;;  Contributed by Red Hat.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+;;---------- Moving ------------------------
+
+(define_expand "movqi"
+  [(set (match_operand:QI 0 "nonimmediate_operand")
+	(match_operand:QI 1 "general_operand"))]
+  ""
+  {
+    if (MEM_P (operand0) && MEM_P (operand1))
+      operands[1] = copy_to_mode_reg (QImode, operand1);
+    if (rl78_far_p (operand0) && rl78_far_p (operand1))
+      operands[1] = copy_to_mode_reg (QImode, operand1);
+
+    /* FIXME: Not sure how GCC can generate (SUBREG (SYMBOL_REF)),
+       but it does.  Since this makes no sense, reject it here.  */
+    if (GET_CODE (operand1) == SUBREG
+        && GET_CODE (XEXP (operand1, 0)) == SYMBOL_REF)
+      FAIL;
+
+    if (CONST_INT_P (operand1) && ! IN_RANGE (INTVAL (operand1), (-1 << 8) + 1, (1 << 8) - 1))
+      FAIL;
+  }
+)
+
+(define_expand "movhi"
+  [(set (match_operand:HI 0 "nonimmediate_operand")
+	(match_operand:HI 1 "general_operand"))]
+  ""
+  {
+    if (MEM_P (operand0) && MEM_P (operand1))
+      operands[1] = copy_to_mode_reg (HImode, operand1);
+    if (rl78_far_p (operand0) && rl78_far_p (operand1))
+      operands[1] = copy_to_mode_reg (HImode, operand1);
+
+    /* FIXME: Not sure how GCC can generate (SUBREG (SYMBOL_REF)),
+       but it does.  Since this makes no sense, reject it here.  */
+    if (GET_CODE (operand1) == SUBREG
+        && GET_CODE (XEXP (operand1, 0)) == SYMBOL_REF)
+      FAIL;
+  }
+)
+
+(define_expand "movsi"
+  [(set (match_operand:SI 0 "nonimmediate_operand")
+	(match_operand:SI 1 "general_operand"))]
+  ""
+  {
+    rl78_expand_movsi (operands);
+    DONE;
+  }
+)
+
+;;---------- Conversions ------------------------
+
+(define_expand "zero_extendqihi2"
+  [(set (match_operand:HI                 0 "nonimmediate_operand")
+	(zero_extend:HI (match_operand:QI 1 "general_operand")))]
+  ""
+  "if (rl78_force_nonfar_2 (operands, gen_zero_extendqihi2))
+     DONE;"
+  )
+
+(define_expand "extendqihi2"
+  [(set (match_operand:HI                 0 "nonimmediate_operand")
+	(sign_extend:HI (match_operand:QI 1 "general_operand")))]
+  ""
+  "if (rl78_force_nonfar_2 (operands, gen_extendqihi2))
+     DONE;"
+  )
+
+;;---------- Arithmetic ------------------------
+
+(define_expand "add<mode>3"
+  [(set (match_operand:QHI           0 "nonimmediate_operand")
+	(plus:QHI (match_operand:QHI 1 "general_operand")
+		  (match_operand:QHI 2 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_3 (operands, gen_add<mode>3))
+     DONE;"
+)
+
+(define_expand "sub<mode>3"
+  [(set (match_operand:QHI            0 "nonimmediate_operand")
+	(minus:QHI (match_operand:QHI 1 "general_operand")
+		   (match_operand:QHI 2 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_3 (operands, gen_sub<mode>3))
+     DONE;"
+)
+
+(define_expand "neg<mode>2"
+  [(set (match_operand:QHI            0 "nonimmediate_operand")
+	(minus:QHI (const_int 0)
+		   (match_operand:QHI 1 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_2 (operands, gen_neg<mode>2))
+     DONE;"
+)
+
+(define_expand "umulqihi3"
+  [(set (match_operand:HI 0 "register_operand")
+        (mult:HI (zero_extend:HI (match_operand:QI 1 "register_operand"))
+                 (zero_extend:HI (match_operand:QI 2 "register_operand"))))]
+  "0"
+  ""
+)
+
+(define_expand "andqi3"
+  [(set (match_operand:QI         0 "nonimmediate_operand")
+	(and:QI (match_operand:QI 1 "general_operand")
+		(match_operand:QI 2 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_3 (operands, gen_andqi3))
+     DONE;"
+)
+
+(define_expand "iorqi3"
+  [(set (match_operand:QI         0 "nonimmediate_operand")
+	(ior:QI (match_operand:QI 1 "general_operand")
+		(match_operand:QI 2 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_3 (operands, gen_iorqi3))
+     DONE;"
+)
+
+(define_expand "xorqi3"
+  [(set (match_operand:QI         0 "nonimmediate_operand")
+	(xor:QI (match_operand:QI 1 "general_operand")
+		(match_operand:QI 2 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_3 (operands, gen_xorqi3))
+     DONE;"
+)
+
+(define_expand "one_cmplqi2"
+  [(set (match_operand:QI         0 "nonimmediate_operand")
+	(xor:QI (match_operand:QI 1 "general_operand")
+		(const_int 255)))
+   ]
+  ""
+  "if (rl78_force_nonfar_2 (operands, gen_one_cmplqi2))
+     DONE;"
+)
+
+;;---------- Shifts ------------------------
+
+(define_expand "ashl<mode>3"
+  [(set (match_operand:QHI             0 "nonimmediate_operand")
+	(ashift:QHI (match_operand:QHI 1 "general_operand")
+		    (match_operand:QI  2 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_3 (operands, gen_ashl<mode>3))
+     DONE;"
+)
+
+(define_expand "ashr<mode>3"
+  [(set (match_operand:QHI               0 "nonimmediate_operand")
+	(ashiftrt:QHI (match_operand:QHI 1 "general_operand")
+		      (match_operand:QI  2 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_3 (operands, gen_ashr<mode>3))
+     DONE;"
+)
+
+(define_expand "lshr<mode>3"
+  [(set (match_operand:QHI               0 "nonimmediate_operand")
+	(lshiftrt:QHI (match_operand:QHI 1 "general_operand")
+		      (match_operand:QI  2 "general_operand")))
+   ]
+  ""
+  "if (rl78_force_nonfar_3 (operands, gen_lshr<mode>3))
+     DONE;"
+)
+
+(define_expand "ashrsi3"
+  [(set (match_operand:SI               0 "register_operand")
+	(ashiftrt:SI (match_operand:SI  1 "register_operand")
+		      (match_operand:SI 2 "immediate_operand")))
+   ]
+  ""
+  "if (GET_CODE (operands[2]) != CONST_INT)
+     FAIL;"
+)
+
+;;---------- Branching ------------------------
+
+(define_expand "indirect_jump"
+  [(set (pc)
+	(match_operand:HI 0 "nonimmediate_operand"))]
+  ""
+  ""
+)
+
+(define_expand "call"
+  [(call (match_operand:HI 0 "memory_operand")
+	 (match_operand 1 ""))]
+  ""
+  ""
+)
+
+(define_expand "call_value"
+  [(set (match_operand          0 "register_operand")
+	(call (match_operand:HI 1 "memory_operand")
+	      (match_operand    2 "")))]
+  ""
+  ""
+)
+
+(define_expand "cbranchqi4"
+  [(set (pc) (if_then_else
+	      (match_operator                    0 "rl78_cmp_operator"
+			      [(match_operand:QI 1 "general_operand")
+			       (match_operand:QI 2 "general_operand")])
+              (label_ref (match_operand 3 "" ""))
+	      (pc)))]
+  ""
+  "rl78_expand_compare (operands);"
+)
+
+(define_expand "cbranchhi4"
+  [(set (pc) (if_then_else
+	      (match_operator                    0 "rl78_cmp_operator"
+			      [(match_operand:HI 1 "general_operand")
+			       (match_operand:HI 2 "general_operand")])
+              (label_ref (match_operand 3 "" ""))
+	      (pc)))]
+  ""
+  "rl78_expand_compare (operands);"
+)
Index: gcc/config/rl78/rl78.md
===================================================================
--- gcc/config/rl78/rl78.md	(revision 0)
+++ gcc/config/rl78/rl78.md	(revision 0)
@@ -0,0 +1,320 @@
+;;  Machine Description for Renesas RL78 processors
+;;  Copyright (C) 2011 Free Software Foundation, Inc.
+;;  Contributed by Red Hat.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+(define_constants
+  [
+   (AX_REG 0)
+   (X_REG 0)
+   (A_REG 1)
+   (BC_REG 2)
+   (C_REG 2)
+   (B_REG 3)
+   (DE_REG 4)
+   (E_REG 4)
+   (D_REG 5)
+   (HL_REG 6)
+   (L_REG 6)
+   (H_REG 7)
+
+   (FP_REG 22)
+   (SP_REG 32)
+   (CC_REG 33)
+   (ES_REG 35)
+   (CS_REG 36)
+
+   (UNS_PROLOG	1)
+   (UNS_EPILOG	1)
+   (UNS_RETI	2)
+   (UNS_RETB	3)
+
+   (UNS_SET_RB	10)
+
+   (UNS_TRAMPOLINE_INIT		20)
+   (UNS_TRAMPOLINE_UNINIT	21)
+   (UNS_NONLOCAL_GOTO		22)
+
+   ])
+
+(define_insn "nop"
+  [(const_int 0)]
+  ""
+  "nop"
+  )
+
+(define_mode_iterator QHI [QI HI])
+
+(include "predicates.md")
+(include "constraints.md")
+(include "rl78-expand.md")
+(include "rl78-virt.md")
+(include "rl78-real.md")
+
+
+;; Function Prologue/Epilogue Instructions
+
+(define_expand "prologue"
+  [(const_int 0)]
+  ""
+  "rl78_expand_prologue (); DONE;"
+)
+
+(define_expand "epilogue"
+  [(const_int 0)]
+  ""
+  "rl78_expand_epilogue (); DONE;"
+)
+
+(define_expand "sibcall_epilogue"
+  [(return)]
+  ""
+  "FAIL;"
+)
+
+(define_insn "simple_return"
+  [(return)]
+  ""
+  "ret"
+)
+
+(define_insn "interrupt_return"
+  [(unspec_volatile [(return)] UNS_RETI) ]
+  ""
+  "reti"
+)
+
+(define_insn "brk_interrupt_return"
+  [(unspec_volatile [(return)] UNS_RETB) ]
+  ""
+  "retb"
+)
+
+(define_expand "eh_return"
+  [(match_operand:HI 0 "" "")]
+  ""
+  "rl78_expand_eh_epilogue (operands[0]);
+   emit_barrier ();
+   DONE;"
+)
+
+;; These are used only by prologue/epilogue so it's "safe" to pass
+;; virtual registers.
+(define_insn "push"
+  [(set (reg:HI SP_REG)
+	(plus:HI (reg:HI SP_REG)
+		  (const_int -2)))
+   (set (mem:HI (reg:HI SP_REG))
+	(match_operand:HI 0 "register_operand" "ABDT,vZint"))]
+  ""
+  "@
+   push\t%v0
+   push\t%v0 ; %0"
+)
+
+(define_insn "pop"
+  [(set (match_operand:HI 0 "register_operand" "=ABDT,vZint")
+	(mem:HI (reg:HI SP_REG)))
+   (set (reg:HI SP_REG)
+	(plus:HI (reg:HI SP_REG)
+		    (const_int 2)))]
+  ""
+  "@
+   pop\t%v0
+   pop\t%v0 ; %0"
+)
+
+(define_insn "sel_rb"
+  [(unspec_volatile [(match_operand 0 "immediate_operand" "")] UNS_SET_RB)]
+  ""
+  "sel\trb%u0"
+  )
+
+(define_insn "trampoline_init"
+  [(set (match_operand 0 "register_operand" "=Z08W")
+	(unspec_volatile [(match_operand 1 "register_operand" "Z08W")
+			  (match_operand 2 "register_operand" "Z10W")
+			  ] UNS_TRAMPOLINE_INIT))
+   ]
+  ""
+  "call !!___trampoline_init ; %0 <= %1 %2"
+  )
+
+(define_insn "trampoline_uninit"
+  [(unspec_volatile [(const_int 0)] UNS_TRAMPOLINE_UNINIT)
+   ]
+  ""
+  "call !!___trampoline_uninit"
+  )
+
+;; GCC restores $fp *before* using it to access values on the *old*
+;; frame.  So, we do it ourselves, to ensure this is not the case.
+;; Note that while %1 is usually a label_ref, we allow for a
+;; non-immediate as well.
+(define_expand "nonlocal_goto"
+  [(set (pc)
+	(unspec_volatile [(match_operand 0 "" "") ;; fp (ignore)
+			  (match_operand 1 "" "vi") ;; target
+			  (match_operand 2 "" "vi") ;; sp
+			  (match_operand 3 "" "vi") ;; ?
+			  ] UNS_NONLOCAL_GOTO))
+   ]
+  ""
+  "emit_jump_insn (gen_nonlocal_goto_insn (operands[0], operands[1], operands[2], operands[3]));
+   emit_barrier ();
+   DONE;"
+  )
+
+(define_insn "nonlocal_goto_insn"
+  [(set (pc)
+	(unspec_volatile [(match_operand 0 "" "") ;; fp (ignore)
+			  (match_operand 1 "" "vi") ;; target
+			  (match_operand 2 "" "vi") ;; sp
+			  (match_operand 3 "" "vi") ;; ?
+			  ] UNS_NONLOCAL_GOTO))
+   ]
+  ""
+  "; nonlocal goto
+	movw	ax, %3
+	movw	r22, ax
+	movw	ax, %2
+	movw	sp, ax
+	movw	ax, %1
+	br	ax
+"
+  )
+
+;;======================================================================
+;;
+;; "macro" insns - cases where inline chunks of code are more
+;; efficient than anything else.
+
+(define_expand "addsi3"
+  [(set (match_operand:SI          0 "register_operand" "=&v")
+	(plus:SI (match_operand:SI 1 "nonmemory_operand" "vi")
+		 (match_operand    2 "nonmemory_operand" "vi")))
+   ]
+  ""
+  "if (!nonmemory_operand (operands[1], SImode))
+     operands[1] = force_reg (SImode, operands[1]);
+   if (!nonmemory_operand (operands[1], SImode))
+     operands[2] = force_reg (SImode, operands[2]);"
+)
+
+(define_insn "addsi3_internal"
+  [(set (match_operand:SI          0 "register_operand" "=&v")
+	(plus:SI (match_operand:SI 1 "nonmemory_operand" "vi")
+		 (match_operand:SI 2 "nonmemory_operand" "vi")))
+   ]
+  ""
+  "; addSI macro %0 = %1 + %2
+	movw	ax, %h1
+	addw	ax, %h2
+	movw	%h0, ax
+	movw	ax,%H1
+	sknc
+	incw	ax
+	addw	ax,%H2
+	movw	%H0,ax
+	; end of addSI macro"
+  [(set_attr "valloc" "macax")]
+)
+
+(define_expand "mulsi3"
+  [(set (match_operand:SI          0 "register_operand" "=&v")
+	(mult:SI (match_operand:SI 1 "nonmemory_operand" "vi")
+		 (match_operand:SI 2 "nonmemory_operand" "vi")))
+   ]
+  "! RL78_MUL_NONE"
+  ""
+)
+
+;; 0xFFFF0 is MACR(L).  0xFFFF2 is MACR(H) but we don't care about it
+;; because we're only using the lower 16 bits (which is the upper 16
+;; bits of the result).
+(define_insn "mulsi3_rl78"
+  [(set (match_operand:SI          0 "register_operand" "=&v")
+	(mult:SI (match_operand:SI 1 "nonmemory_operand" "vi")
+		 (match_operand:SI 2 "nonmemory_operand" "vi")))
+   ]
+  "RL78_MUL_RL78"
+  "; mulsi macro %0 = %1 * %2
+	movw	ax, %h1
+	movw	bc, %h2
+	MULHU	; bcax = bc * ax
+	movw	%h0, ax
+	movw	ax, bc
+	movw	0xffff0, ax
+	movw	ax, %H1
+	movw	bc, %h2
+	MACHU	; MACR += bc * ax
+	movw	ax, %h1
+	movw	bc, %H2
+	MACHU	; MACR += bc * ax
+	movw	ax, 0xffff0
+	movw	%H0, ax
+	; end of mulsi macro"
+  [(set_attr "valloc" "macax")]
+  )
+
+;; 0xFFFF0 is MDAL.  0xFFFF2 is MDAH.
+;; 0xFFFF4 is MDBL.  0xFFFF6 is MDBH.
+;; 0xF00E0 is MDCL.  0xF00E2 is MDCH.
+;; 0xF00E8 is MDUC.
+;; Warning: this matches the documentation, not the silicon.
+(define_insn "mulsi3_g13"
+  [(set (match_operand:SI          0 "register_operand" "=&v")
+	(mult:SI (match_operand:SI 1 "nonmemory_operand" "vi")
+		 (match_operand:SI 2 "nonmemory_operand" "vi")))
+   ]
+  "RL78_MUL_G13"
+  "; mulsi macro %0 = %1 * %2
+	mov	a, #0x00
+	mov	!0xf00e8, a	; MDUC
+	movw	ax, %h1
+	movw	0xffff0, ax	; MDAL
+	movw	ax, %h2
+	movw	0xffff2, ax	; MDAH
+	nop	; mdb = mdal * mdah
+	movw	ax, 0xffff4	; MDBL
+	movw	%h0, ax
+
+	mov	a, #0x40
+	mov	!0xf00e8, a	; MDUC
+	movw	ax, 0xffff6	; MDBH
+	movw	!0xf00e0, ax	; MDCL
+	movw	ax, #0
+	movw	!0xf00e2, ax	; MDCL
+	movw	ax, %H1
+	movw	0xffff0, ax	; MDAL
+	movw	ax, %h2
+	movw	0xffff2, ax	; MDAH
+	nop	; mdc += mdal * mdah
+
+	mov	a, #0x40
+	mov	!0xf00e8, a	; MDUC
+	movw	ax, %h1
+	movw	0xffff0, ax	; MDAL
+	movw	ax, %H2
+	movw	0xffff2, ax	; MDAH
+	nop	; mdc += mdal * mdah
+	movw	ax, !0xf00e0	; MDCL
+	movw	%H0, ax
+	; end of mulsi macro"
+  [(set_attr "valloc" "macax")]
+  )
Index: gcc/config/rl78/rl78-real.md
===================================================================
--- gcc/config/rl78/rl78-real.md	(revision 0)
+++ gcc/config/rl78/rl78-real.md	(revision 0)
@@ -0,0 +1,339 @@
+;;  Machine Description for Renesas RL78 processors
+;;  Copyright (C) 2011 Free Software Foundation, Inc.
+;;  Contributed by Red Hat.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; The insns in this file correspond to the actual opcodes the RL78
+;; can issue with real registers.  All insns in here should be
+;; conditional on rl78_real_insns_ok() returning true, and should
+;; allow virtual registers in their predicates - the reorg pass that
+;; allocates physical registers uses the constraints to select
+;; registers, but insns with virtual registers MUST match one of these
+;; patterns - other than the constraints - so that the operand info is
+;; properly set up for the alloc pass.
+
+;;---------- Moving ------------------------
+
+(define_insn "movqi_es"
+  [(set (reg:QI ES_REG)
+	(match_operand:QI 0 "register_operand" "a"))]
+  ""
+  "mov\tes, %0"
+)
+
+(define_insn "movqi_cs"
+  [(set (reg:QI CS_REG)
+	(match_operand:QI 0 "register_operand" "a"))]
+  ""
+  "mov\tcs, %0"
+)
+
+(define_insn "movqi_real"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=g,RaxbcWab,RaxbcWab,a,                          bcx,R, WabWd2WhlWh1WhbWbcWs1v, bcx")
+	(match_operand    1 "general_operand"      "0,K,        M,       RInt8sJvWabWdeWd2WhlWh1WhbWbcWs1,Wab,aInt8J,a,                      R"))]
+  "rl78_real_insns_ok ()"
+  "@
+   ; mov\t%0, %1
+   oneb\t%0
+   clrb\t%0
+   mov\t%0, %1
+   mov\t%0, %1
+   mov\t%0, %1
+   mov\t%0, %1
+   mov\t%0, %S1"
+)
+
+(define_insn "movhi_real"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=g,AB,AB,RSv,A,BDTvSWabWd2WdeWhlWh1WbcWs1, BDT,ABDT,v")
+	(match_operand:HI 1 "general_operand"      " 0,K, M, i,  BDTvSWabWd2WdeWh1WhlWbcWs1,A, BDT,vS,  ABDT"))]
+  "rl78_real_insns_ok ()"
+  "@
+   ; movw\t%0, %1
+   onew\t%0
+   clrw\t%0
+   movw\t%0, %1
+   movw\t%0, %1
+   movw\t%0, %1
+   movw\t%0, %S1
+   movw\t%0, %1
+   movw\t%0, %1"
+)
+
+;;---------- Conversions ------------------------
+
+(define_insn "zero_extendqihi2_real"
+  [(set (match_operand:HI                 0 "nonimmediate_operand" "=rv,A")
+	(zero_extend:HI (match_operand:QI 1 "general_operand" "0,a")))]
+  "rl78_real_insns_ok ()"
+  "@
+   mov\t%Q0, #0
+   mov\tx, a \;mov\ta, #0"
+  )
+
+(define_insn "extendqihi2_real"
+  [(set (match_operand:HI                 0 "nonimmediate_operand" "=A,A")
+	(sign_extend:HI (match_operand:QI 1 "general_operand" "x,a")))]
+  "rl78_real_insns_ok ()"
+  "@
+   shlw\t%0, 8 \;sarw\t%0, 8
+   sarw\t%0, 8"
+  )
+
+;;---------- Arithmetic ------------------------
+
+(define_insn "addqi3_real"
+  [(set (match_operand:QI          0 "nonimmediate_operand"  "=rvWabWhlWh1,rvWabWhlWh1,a,*bcdehl")
+	(plus:QI (match_operand:QI 1 "general_operand"  "%0,0,0,0")
+		 (match_operand:QI 2 "general_operand" "K,L,RWhlWh1i,a")))
+   ]
+  "rl78_real_insns_ok ()"
+  "@
+    inc\t%0
+    dec\t%0
+    add\t%0, %2
+    add\t%0, %2"
+)
+
+(define_insn "addhi3_real"
+  [(set (match_operand:HI          0 "nonimmediate_operand"  "=vABDTWh1Wab,vABDTWh1Wab,v,v,A,S,S,A")
+	(plus:HI (match_operand:HI 1 "general_operand"  "%0,0,0,0,0,0,0,S")
+		 (match_operand:HI 2 "general_operand" "K,L,N,O,RWh1WhlWabiv,Int8,J,Ri")))
+   ]
+  "rl78_real_insns_ok ()"
+  "@
+   incw\t%0
+   decw\t%0
+   incw\t%0 \;incw\t%0
+   decw\t%0 \;decw\t%0
+   addw\t%0, %p2
+   addw\t%0, %2
+   subw\t%0, %m2
+   movw\t%0, %1 \;addw\t%0, %2"
+)
+
+(define_insn "addqihi3a_real"
+  [(set (match_operand:HI          0 "register_operand"  "=r")
+	(plus:HI (zero_extend:HI (match_operand:QI 1 "register_operand"  "%r"))
+		 (match_operand:HI 2 "register_operand" "r")))
+   ]
+  "rl78_real_insns_ok ()"
+  "add\t%q0, %q1 \;addc\t%Q0, #0"
+)
+
+(define_insn "subqi3_real"
+  [(set (match_operand:QI           0 "nonimmediate_operand"  "=a,R,v")
+	(minus:QI (match_operand:QI 1 "general_operand"  "0,0,0")
+		  (match_operand:QI 2 "general_operand" "RiWabWhbWh1Whl,a,i")))
+   ]
+  "rl78_real_insns_ok ()"
+  "sub\t%0, %2"
+)
+
+(define_insn "subhi3_real"
+  [(set (match_operand:HI           0 "nonimmediate_operand"  "=A,S")
+	(minus:HI (match_operand:HI 1 "general_operand"  "0,0")
+		  (match_operand:HI 2 "general_operand" "iBDTWabWh1v,i")))
+   ]
+  "rl78_real_insns_ok ()"
+  "subw\t%0, %2"
+)
+
+(define_insn "umulhi3_shift_real"
+  [(set (match_operand:HI 0 "register_operand" "=A,A")
+        (mult:HI (match_operand:HI 1 "rl78_nonfar_operand" "0,0")
+                 (match_operand:HI 2 "rl78_24_operand" "N,i")))]
+  "rl78_real_insns_ok ()"
+  "@
+   shlw\t%0, 1
+   shlw\t%0, 2"
+)
+
+(define_insn "umulqihi3_real"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=A")
+        (mult:HI (zero_extend:HI (match_operand:QI 1 "general_operand" "%a"))
+                 (zero_extend:HI (match_operand:QI 2 "general_operand" "x"))))]
+  "rl78_real_insns_ok ()"
+  "mulu\t%2"
+)
+
+(define_insn "andqi3_real"
+  [(set (match_operand:QI         0 "nonimmediate_operand"  "=A,R,v")
+	(and:QI (match_operand:QI 1 "general_operand"       "%0,0,0")
+		(match_operand:QI 2 "general_operand"       "iRvWabWhbWh1Whl,A,i")))
+   ]
+  "rl78_real_insns_ok ()"
+  "and\t%0, %2"
+)
+
+(define_insn "iorqi3_real"
+  [(set (match_operand:QI         0 "nonimmediate_operand"  "=A,R,v")
+	(ior:QI (match_operand:QI 1 "general_operand"       "%0,0,0")
+		(match_operand:QI 2 "general_operand"       "iRvWabWhbWh1Whl,A,i")))
+   ]
+  "rl78_real_insns_ok ()"
+  "or\t%0, %2"
+)
+
+(define_insn "xorqi3_real"
+  [(set (match_operand:QI         0 "nonimmediate_operand"  "=A,R,v")
+	(xor:QI (match_operand:QI 1 "general_operand"       "%0,0,0")
+		(match_operand    2 "general_operand"       "iRvWabWhbWh1Whl,A,i")))
+   ]
+  "rl78_real_insns_ok ()"
+  "xor\t%0, %2"
+)
+
+;;---------- Shifts ------------------------
+
+(define_insn "ashlqi3_real"
+  [(set (match_operand:QI            0 "nonimmediate_operand"  "=abc,a,a")
+	(ashift:QI (match_operand:QI 1 "general_operand"  "0,0,0")
+		   (match_operand:QI 2 "general_operand" "Int3,bc,dehl")))
+   ]
+  "rl78_real_insns_ok ()"
+  "@
+   shl\t%0, %u2
+   cmp0 %2\; bz $2f\; 1: shl\t%0, 1 \;dec %2 \;bnz $1b\;2:
+   inc %2\;dec %2\;bz $2f\;1: shl\t%0, 1 \;dec %2 \;bnz $1b\;2:"
+)
+
+(define_insn "ashlhi3_real"
+  [(set (match_operand:HI            0 "nonimmediate_operand"  "=AB,A,A")
+	(ashift:HI (match_operand:HI 1 "general_operand"  "0,0,0")
+		   (match_operand:QI 2 "general_operand" "P,bc,dehl")))
+   ]
+  "rl78_real_insns_ok ()"
+  "@
+   shlw\t%0, %u2
+   cmp0 %2\; bz $2f\; 1: shlw\t%0, 1 \;dec %2 \;bnz $1b\;2:
+   inc %2\;dec %2\;bz $2f\;1: shlw\t%0, 1 \;dec %2 \;bnz $1b\;2:"
+)
+
+;;----------
+
+(define_insn "ashrqi3_real"
+  [(set (match_operand:QI              0 "nonimmediate_operand"  "=abc,a,a")
+	(ashiftrt:QI (match_operand:QI 1 "general_operand"  "0,0,0")
+		     (match_operand:QI 2 "general_operand" "Int3,bc,dehl")))
+   ]
+  "rl78_real_insns_ok ()"
+  "@
+   sar\t%0, %u2
+   cmp0 %2\; bz $2f\; 1: sar\t%0, 1 \;dec %2 \;bnz $1b\;2:
+   inc %2\;dec %2\;bz $2f\;1: sar\t%0, 1\;dec %2 \;bnz $1b\;2:"
+)
+
+(define_insn "ashrhi3_real"
+  [(set (match_operand:HI              0 "nonimmediate_operand"  "=AB,A,A")
+	(ashiftrt:HI (match_operand:HI 1 "general_operand"  "0,0,0")
+		     (match_operand:QI 2 "general_operand" "P,bc,dehl")))
+   ]
+  "rl78_real_insns_ok ()"
+  "@
+   sarw\t%0, %u2
+   cmp0 %2\; bz $2f\; 1: sarw\t%0, 1 \;dec %2 \;bnz $1b\;2:
+   inc %2\;dec %2\;bz $2f\;1: sarw\t%0, 1\;dec %2\;bnz $1b\;2:"
+)
+
+;;----------
+
+(define_insn "lshrqi3_real"
+  [(set (match_operand:QI              0 "nonimmediate_operand"  "=abc,a,a")
+	(lshiftrt:QI (match_operand:QI 1 "general_operand"  "0,0,0")
+		     (match_operand:QI 2 "general_operand" "Int3,bc,dehl")))
+   ]
+  "rl78_real_insns_ok ()"
+  "@
+   shr\t%0, %u2
+   cmp0 %2\; bz $2f\; 1: shr\t%0, 1 \;dec %2 \;bnz $1b\;2:
+   inc %2\;dec %2\;bz $2f\;1: shr\t%0, 1\;dec %2\;bnz $1b\;2:"
+)
+
+(define_insn "lshrhi3_real"
+  [(set (match_operand:HI              0 "nonimmediate_operand"  "=AB,A,A")
+	(lshiftrt:HI (match_operand:HI 1 "general_operand"  "0,0,0")
+		     (match_operand:QI 2 "general_operand" "P,bc,dehl")))
+   ]
+  "rl78_real_insns_ok ()"
+  "@
+   shrw\t%0, %u2
+   cmp0 %2\; bz $2f\; 1: shrw\t%0, 1 \;dec %2 \;bnz $1b\;2:
+   inc %2\;dec %2\;bz $2f\;1: shrw\t%0, 1\;dec %2\;bnz $1b\;2:"
+)
+
+;;---------- Branching ------------------------
+
+(define_insn "indirect_jump_real"
+  [(set (pc)
+	(match_operand:HI 0 "nonimmediate_operand" "A"))]
+  "rl78_real_insns_ok ()"
+  "br\t%0"
+)
+
+(define_insn "jump"
+  [(set (pc)
+	(label_ref (match_operand 0 "" "")))]
+  ""
+  ;; $rel8, $!rel16, !abs16, !!abs20
+  "br\t!!%0"
+)
+
+(define_insn "call_real"
+  [(call (match_operand:HI 0 "memory_operand" "Wab,Wca")
+	 (match_operand 1 "" ""))]
+  "rl78_real_insns_ok ()"
+  "@
+   call\t!!%A0
+   call\t%A0"
+  )
+
+(define_insn "call_value_real"
+  [(set (match_operand 0 "register_operand" "=v,v")
+	(call (match_operand:HI 1 "memory_operand" "Wab,Wca")
+	      (match_operand 2 "" "")))]
+  "rl78_real_insns_ok ()"
+  "@
+   call\t!!%A1
+   call\t%A1"
+  )
+
+(define_insn "cbranchqi4_real"
+  [(set (pc) (if_then_else
+	      (match_operator 0 "rl78_cmp_operator_real"
+			      [(match_operand:QI 1 "general_operand" "Wabvaxbc,a,          v,bcdehl")
+			       (match_operand:QI 2 "general_operand" "M,       irWhlWh1Whb,i,a")])
+              (label_ref (match_operand 3 "" ""))
+	      (pc)))]
+  "rl78_real_insns_ok ()"
+  "@
+   cmp0\t%1 \;sk%c0 \;br\t!!%3
+   cmp\t%1, %2 \;sk%c0 \;br\t!!%3
+   cmp\t%1, %2 \;sk%c0 \;br\t!!%3
+   cmp\t%1, %2 \;sk%c0 \;br\t!!%3"
+  )
+
+(define_insn "cbranchhi4_real"
+  [(set (pc) (if_then_else
+	      (match_operator 0 "rl78_cmp_operator_real"
+			      [(match_operand:HI 1 "general_operand" "A")
+			       (match_operand:HI 2 "general_operand" "iBDTWhlWh1")])
+              (label_ref (match_operand 3 "" ""))
+	      (pc)))]
+  "rl78_real_insns_ok ()"
+  "cmpw\t%1, %2 \;sk%c0 \;br\t!!%3"
+  )
Index: gcc/config/rl78/rl78.opt
===================================================================
--- gcc/config/rl78/rl78.opt	(revision 0)
+++ gcc/config/rl78/rl78.opt	(revision 0)
@@ -0,0 +1,43 @@
+; Command line options for the Renesas RL78 port of GCC.
+; Copyright (C) 2011 Free Software Foundation, Inc.
+; Contributed by Red Hat.
+;
+; This file is part of GCC.
+;
+; GCC is free software; you can redistribute it and/or modify it under
+; the terms of the GNU General Public License as published by the Free
+; Software Foundation; either version 3, or (at your option) any later
+; version.
+;
+; GCC is distributed in the hope that it will be useful, but WITHOUT ANY
+; WARRANTY; without even the implied warranty of MERCHANTABILITY or
+; FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+; for more details.
+;
+; You should have received a copy of the GNU General Public License
+; along with GCC; see the file COPYING3.  If not see
+; <http://www.gnu.org/licenses/>.
+;---------------------------------------------------
+
+HeaderInclude
+config/rl78/rl78-opts.h
+
+msim
+Target
+Use the simulator runtime.
+
+mmul=
+Target RejectNegative Joined Var(rl78_mul_type) Report Tolower Enum(rl78_mul_types) Init(MUL_NONE)
+Select hardware or software multiplication support.
+
+Enum
+Name(rl78_mul_types) Type(enum rl78_mul_types)
+
+EnumValue
+Enum(rl78_mul_types) String(none) Value(MUL_NONE)
+
+EnumValue
+Enum(rl78_mul_types) String(rl78) Value(MUL_RL78)
+
+EnumValue
+Enum(rl78_mul_types) String(g13) Value(MUL_G13)
Index: gcc/config/rl78/rl78-c.c
===================================================================
--- gcc/config/rl78/rl78-c.c	(revision 0)
+++ gcc/config/rl78/rl78-c.c	(revision 0)
@@ -0,0 +1,43 @@
+/* RL78 C-specific support
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Contributed by Red Hat, Inc.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "c-family/c-pragma.h"
+#include "c-family/c-common.h"
+#include "diagnostic-core.h"
+#include "cpplib.h"
+#include "hard-reg-set.h"
+#include "output.h"
+#include "rl78-protos.h"
+#include "function.h"
+#define MAX_RECOG_OPERANDS 10
+#include "reload.h"
+#include "target.h"
+
+/* Implements REGISTER_TARGET_PRAGMAS.  */
+void
+rl78_register_pragmas (void)
+{
+  c_register_addr_space ("__far", ADDR_SPACE_FAR);
+}
Index: gcc/config/rl78/rl78.c
===================================================================
--- gcc/config/rl78/rl78.c	(revision 0)
+++ gcc/config/rl78/rl78.c	(revision 0)
@@ -0,0 +1,2699 @@
+/* Subroutines used for code generation on Renesas RL78 processors.
+   Copyright (C) 2011 Free Software Foundation, Inc.
+   Contributed by Red Hat.
+
+   This file is part of GCC.
+
+   GCC is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3, or (at your option)
+   any later version.
+
+   GCC is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with GCC; see the file COPYING3.  If not see
+   <http://www.gnu.org/licenses/>.  */
+
+#include "config.h"
+#include "system.h"
+#include "coretypes.h"
+#include "tm.h"
+#include "tree.h"
+#include "rtl.h"
+#include "regs.h"
+#include "hard-reg-set.h"
+#include "insn-config.h"
+#include "conditions.h"
+#include "output.h"
+#include "insn-attr.h"
+#include "flags.h"
+#include "function.h"
+#include "expr.h"
+#include "optabs.h"
+#include "libfuncs.h"
+#include "recog.h"
+#include "diagnostic-core.h"
+#include "toplev.h"
+#include "reload.h"
+#include "df.h"
+#include "ggc.h"
+#include "tm_p.h"
+#include "debug.h"
+#include "target.h"
+#include "target-def.h"
+#include "langhooks.h"
+#include "rl78-protos.h"
+#include "tree-pass.h"
+
+static inline bool is_interrupt_func (const_tree decl);
+static inline bool is_brk_interrupt_func (const_tree decl);
+static void rl78_reorg (void);
+
+
+/* Debugging statements are tagged with DEBUG0 only so that they can
+   be easily enabled individually, by replacing the '0' with '1' as
+   needed.  */
+#define DEBUG0 0
+#define DEBUG1 1
+
+/* REGISTER_NAMES has the names for individual 8-bit registers, but
+   these have the names we need to use when referring to 16-bit
+   register pairs.  */
+static const char * const word_regnames[] =
+{
+  "ax", "AX", "bc", "BC", "de", "DE", "hl", "HL",
+  "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15",
+  "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23",
+  "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31",
+  "sp", "ap", "psw", "es", "cs"
+};
+
+struct GTY(()) machine_function
+{
+  /* If set, the rest of the fields have been computed.  */
+  int computed;
+  /* Which register pairs need to be pushed in the prologue.  */
+  int need_to_push [FIRST_PSEUDO_REGISTER / 2];
+
+  /* These fields describe the frame layout...  */
+  /* arg pointer */
+  /* 4 bytes for saved PC */
+  int framesize_regs;
+  /* frame pointer */
+  int framesize_locals;
+  int framesize_outgoing;
+  /* stack pointer */
+  int framesize;
+
+  /* If set, recog is allowed to match against the "real" patterns.  */
+  int real_insns_ok;
+  /* If set, recog is allowed to match against the "virtual" patterns.  */
+  int virt_insns_ok;
+  /* Set if the current function needs to clean up any trampolines.  */
+  int trampolines_used;
+};
+
+/* This is our init_machine_status, as set in
+   rl78_option_override.  */
+static struct machine_function *
+rl78_init_machine_status (void)
+{
+  struct machine_function *m;
+
+  m = ggc_alloc_cleared_machine_function ();
+  m->virt_insns_ok = 1;
+
+  return m;
+}
+
+/* Returns whether to run the devirtualization pass.  */
+static bool
+devirt_gate (void)
+{
+  return true;
+}
+
+/* Runs the devirtualization pass.  */
+static unsigned int
+devirt_pass (void)
+{
+  rl78_reorg ();
+  return 0;
+}
+
+/* This pass converts virtual instructions using virtual registers, to
+   real instructions using real registers.  Rather than run it as
+   reorg, we reschedule it before vartrack to help with debugging.  */
+static struct opt_pass rl78_devirt_pass =
+{
+  RTL_PASS,
+  "devirt",
+  devirt_gate,
+  devirt_pass,
+  NULL,
+  NULL,
+  212,
+  TV_MACH_DEP,
+  0, 0, 0,
+  0,
+  TODO_dump_func
+};
+
+static struct register_pass_info rl78_devirt_info =
+{
+  & rl78_devirt_pass,
+  "vartrack",
+  1,
+  PASS_POS_INSERT_BEFORE
+};
+
+#undef  TARGET_ASM_FILE_START
+#define TARGET_ASM_FILE_START rl78_asm_file_start
+
+static void
+rl78_asm_file_start (void)
+{
+  int i;
+
+  for (i = 0; i < 8; i++)
+    {
+      fprintf (asm_out_file, "r%d\t=\t0x%x\n", 8 + i, 0xffef0 + i);
+      fprintf (asm_out_file, "r%d\t=\t0x%x\n", 16 + i, 0xffee8 + i);
+    }
+
+  register_pass (& rl78_devirt_info);
+}
+
+
+#undef  TARGET_OPTION_OVERRIDE
+#define TARGET_OPTION_OVERRIDE		rl78_option_override
+
+static void
+rl78_option_override (void)
+{
+  flag_omit_frame_pointer = 1;
+  flag_no_function_cse = 1;
+  flag_split_wide_types = 0;
+
+  init_machine_status = rl78_init_machine_status;
+}
+
+/* Most registers are 8 bits.  Some are 16 bits because, for example,
+   gcc doesn't like dealing with $FP as a register pair.  This table
+   maps register numbers to size in bytes.  */
+static const int register_sizes[] =
+{
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  1, 1, 1, 1, 1, 1, 2, 1,
+  1, 1, 1, 1, 1, 1, 1, 1,
+  2, 2, 1, 1, 1
+};
+
+/* Predicates used in the MD patterns.  This one is true when virtual
+   insns may be matched, which typically means before (or during) the
+   devirt pass.  */
+bool
+rl78_virt_insns_ok (void)
+{
+  if (cfun)
+    return cfun->machine->virt_insns_ok;
+  return true;
+}
+
+/* Predicates used in the MD patterns.  This one is true when real
+   insns may be matched, which typically means after (or during) the
+   devirt pass.  */
+bool
+rl78_real_insns_ok (void)
+{
+  if (cfun)
+    return cfun->machine->real_insns_ok;
+  return false;
+}
+
+/* Implements HARD_REGNO_NREGS.  */
+int
+rl78_hard_regno_nregs (int regno, enum machine_mode mode)
+{
+  int rs = register_sizes[regno];
+  if (rs < 1)
+    rs = 1;
+  return ((GET_MODE_SIZE (mode) + rs - 1) / rs);
+}
+
+/* Implements HARD_REGNO_MODE_OK.  */
+int
+rl78_hard_regno_mode_ok (int regno, enum machine_mode mode)
+{
+  int s = GET_MODE_SIZE (mode);
+
+  if (s < 1)
+    return 0;
+  /* These are not to be used by gcc.  */
+  if (regno == 23 || regno == ES_REG || regno == CS_REG)
+    return 0;
+  /* $fp can alway sbe accessed as a 16-bit value.  */
+  if (regno == FP_REG && s == 2)
+    return 1;
+  if (regno < SP_REG)
+    {
+      /* Since a reg-reg move is really a reg-mem move, we must
+	 enforce alignment.  */
+      if (s > 1 && (regno % 2))
+	return 0;
+      return 1;
+    }
+  if (s == CC_REGNUM)
+    return (mode == BImode);
+  /* All other registers must be accessed in their natural sizes.  */
+  if (s == register_sizes [regno])
+    return 1;
+  return 0;
+}
+
+/* Simplify_gen_subreg() doesn't handle memory references the way we
+   need it to below, so we use this function for when we must get a
+   valid subreg in a "natural" state.  */
+static rtx
+rl78_subreg (enum machine_mode mode, rtx r, enum machine_mode omode, int byte)
+{
+  if (GET_CODE (r) == MEM)
+    return adjust_address (r, mode, byte);
+  else
+    return simplify_gen_subreg (mode, r, omode, byte);
+}
+
+/* Used by movsi.  Split SImode moves into two HImode moves, using
+   appropriate patterns for the upper and lower halves of symbols.  */
+void
+rl78_expand_movsi (rtx *operands)
+{
+  rtx op00, op02, op10, op12;
+
+  op00 = rl78_subreg (HImode, operands[0], SImode, 0);
+  op02 = rl78_subreg (HImode, operands[0], SImode, 2);
+  if (GET_CODE (operands[1]) == CONST
+      || GET_CODE (operands[1]) == SYMBOL_REF)
+    {
+      op10 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (0));
+      op10 = gen_rtx_CONST (HImode, op10);
+      op12 = gen_rtx_ZERO_EXTRACT (HImode, operands[1], GEN_INT (16), GEN_INT (16));
+      op12 = gen_rtx_CONST (HImode, op12);
+    }
+  else
+    {
+      op10 = rl78_subreg (HImode, operands[1], SImode, 0);
+      op12 = rl78_subreg (HImode, operands[1], SImode, 2);
+    }
+
+  if (rtx_equal_p (operands[0], operands[1]))
+    ;
+  else if (rtx_equal_p (op00, op12))
+    {
+      emit_move_insn (op02, op12);
+      emit_move_insn (op00, op10);
+    }
+  else
+    {
+      emit_move_insn (op00, op10);
+      emit_move_insn (op02, op12);
+    }
+}
+
+/* Used by various two-operand expanders which cannot accept all
+   operands in the "far" namespace.  Force some such operands into
+   registers so that each pattern has at most one far operand.  */
+int
+rl78_force_nonfar_2 (rtx *operands, rtx (*gen)(rtx,rtx))
+{
+  int did = 0;
+  rtx temp_reg = NULL;
+
+  if (rl78_far_p (operands[0]))
+    {
+      temp_reg = operands[0];
+      operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
+      did = 1;
+    }
+  if (!did)
+    return 0;
+
+  emit_insn (gen (operands[0], operands[1]));
+  if (temp_reg)
+    emit_move_insn (temp_reg, operands[0]);
+  return 1;
+}
+
+/* Likewise, but for three-operand expanders.  */
+int
+rl78_force_nonfar_3 (rtx *operands, rtx (*gen)(rtx,rtx,rtx))
+{
+  int did = 0;
+  rtx temp_reg = NULL;
+
+  if (rl78_far_p (operands[1]))
+    {
+      rtx temp_reg = gen_reg_rtx (GET_MODE (operands[1]));
+      emit_move_insn (temp_reg, operands[1]);
+      operands[1] = temp_reg;
+      did = 1;
+    }
+  if (rl78_far_p (operands[0]))
+    {
+      temp_reg = operands[0];
+      operands[0] = gen_reg_rtx (GET_MODE (operands[0]));
+      did = 1;
+    }
+  if (!did)
+    return 0;
+
+  emit_insn (gen (operands[0], operands[1], operands[2]));
+  if (temp_reg)
+    emit_move_insn (temp_reg, operands[0]);
+  return 1;
+}
+
+#undef  TARGET_CAN_ELIMINATE
+#define TARGET_CAN_ELIMINATE		rl78_can_eliminate
+
+static bool
+rl78_can_eliminate (const int from ATTRIBUTE_UNUSED, const int to ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
+/* Returns nonzero if the given register needs to be saved by the
+   current function.  */
+static int
+need_to_save (int regno)
+{
+  if (is_interrupt_func (cfun->decl))
+    {
+      if (regno < 8)
+	return 1; /* don't know what devirt will need */
+      if (regno > 23)
+	return 0; /* don't need to save interrupt registers */
+      if (current_function_is_leaf)
+	{
+	  return df_regs_ever_live_p (regno);
+	}
+      else
+	return 1;
+    }
+  if (regno == FRAME_POINTER_REGNUM && frame_pointer_needed)
+    return 1;
+  if (fixed_regs[regno])
+    return 0;
+  if (crtl->calls_eh_return)
+    return 1;
+  if (df_regs_ever_live_p (regno)
+      && !call_used_regs[regno])
+    return 1;
+  return 0;
+}
+
+/* We use this to wrap all emitted insns in the prologue.  */
+static rtx
+F (rtx x)
+{
+  RTX_FRAME_RELATED_P (x) = 1;
+  return x;
+}
+
+/* Compute all the frame-related fields in our machine_function
+   structure.  */
+static void
+rl78_compute_frame_info (void)
+{
+  int i;
+
+  cfun->machine->computed = 1;
+  cfun->machine->framesize_regs = 0;
+  cfun->machine->framesize_locals = get_frame_size ();
+  cfun->machine->framesize_outgoing = crtl->outgoing_args_size;
+
+  for (i = 0; i < 16; i ++)
+    if (need_to_save (i * 2) || need_to_save (i * 2 + 1))
+      {
+	cfun->machine->need_to_push [i] = 1;
+	cfun->machine->framesize_regs += 2;
+      }
+    else
+      cfun->machine->need_to_push [i] = 0;
+
+  if ((cfun->machine->framesize_locals + cfun->machine->framesize_outgoing) & 1)
+    cfun->machine->framesize_locals ++;
+
+  cfun->machine->framesize = (cfun->machine->framesize_regs
+			      + cfun->machine->framesize_locals
+			      + cfun->machine->framesize_outgoing);
+}
+
+/* Returns true if the provided function has the specified attribute.  */
+static inline bool
+has_func_attr (const_tree decl, const char * func_attr)
+{
+  if (decl == NULL_TREE)
+    decl = current_function_decl;
+
+  return lookup_attribute (func_attr, DECL_ATTRIBUTES (decl)) != NULL_TREE;
+}
+
+/* Returns true if the provided function has the "interrupt" attribute.  */
+static inline bool
+is_interrupt_func (const_tree decl)
+{
+  return has_func_attr (decl, "interrupt") || has_func_attr (decl, "brk_interrupt");
+}
+
+/* Returns true if the provided function has the "brk_interrupt" attribute.  */
+static inline bool
+is_brk_interrupt_func (const_tree decl)
+{
+  return has_func_attr (decl, "brk_interrupt");
+}
+
+/* Check "interrupt" attributes.  */
+static tree
+rl78_handle_func_attribute (tree * node,
+			  tree   name,
+			  tree   args,
+			  int    flags ATTRIBUTE_UNUSED,
+			  bool * no_add_attrs)
+{
+  gcc_assert (DECL_P (* node));
+  gcc_assert (args == NULL_TREE);
+
+  if (TREE_CODE (* node) != FUNCTION_DECL)
+    {
+      warning (OPT_Wattributes, "%qE attribute only applies to functions",
+	       name);
+      * no_add_attrs = true;
+    }
+
+  /* FIXME: We ought to check that the interrupt and exception
+     handler attributes have been applied to void functions.  */
+  return NULL_TREE;
+}
+
+#undef  TARGET_ATTRIBUTE_TABLE
+#define TARGET_ATTRIBUTE_TABLE		rl78_attribute_table
+
+/* Table of RL78-specific attributes.  */
+const struct attribute_spec rl78_attribute_table[] =
+{
+  /* Name, min_len, max_len, decl_req, type_req, fn_type_req, handler,
+     affects_type_identity.  */
+  { "interrupt",      0, 0, true, false, false, rl78_handle_func_attribute,
+    false },
+  { "brk_interrupt",  0, 0, true, false, false, rl78_handle_func_attribute,
+    false },
+  { NULL,             0, 0, false, false, false, NULL, false }
+};
+
+
+
+/* Break down an address RTX into its component base/index/addend
+   portions and return TRUE if the address is of a valid form, else
+   FALSE.  */
+static bool
+characterize_address (rtx x, rtx *base, rtx *index, rtx *addend)
+{
+  *base = NULL_RTX;
+  *index = NULL_RTX;
+  *addend = NULL_RTX;
+
+  if (GET_CODE (x) == REG)
+    {
+      *base = x;
+      return true;
+    }
+
+  /* We sometimes get these without the CONST wrapper */
+  if (GET_CODE (x) == PLUS
+      && GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+      && GET_CODE (XEXP (x, 1)) == CONST_INT)
+    {
+      *addend = x;
+      return true;
+    }
+
+  if (GET_CODE (x) == PLUS)
+    {
+      *base = XEXP (x, 0);
+      x = XEXP (x, 1);
+
+      if (GET_CODE (*base) != REG
+	  && GET_CODE (x) == REG)
+	{
+	  rtx tmp = *base;
+	  *base = x;
+	  x = tmp;
+	}
+
+      if (GET_CODE (*base) != REG)
+	return false;
+
+      if (GET_CODE (x) == ZERO_EXTEND
+	  && GET_CODE (XEXP (x, 0)) == REG)
+	{
+	  *index = XEXP (x, 0);
+	  return false;
+	}
+    }
+
+  switch (GET_CODE (x))
+    {
+    case PLUS:
+      if (GET_CODE (XEXP (x, 0)) == SYMBOL_REF
+	  && GET_CODE (XEXP (x, 0)) == CONST_INT)
+	{
+	  *addend = x;
+	  return true;
+	}
+      /* fall through */
+    case MEM:
+    case REG:
+      return false;
+
+    case CONST:
+    case SYMBOL_REF:
+    case CONST_INT:
+      *addend = x;
+      return true;
+
+    default:
+      return false;
+    }
+
+  return false;
+}
+
+/* Used by the Whb constraint.  Match addresses that use HL+B or HL+C
+   addressing.  */
+bool
+rl78_hl_b_c_addr_p (rtx op)
+{
+  rtx hl, bc;
+
+  if (GET_CODE (op) != PLUS)
+    return false;
+  hl = XEXP (op, 0);
+  bc = XEXP (op, 1);
+  if (GET_CODE (hl) == ZERO_EXTEND)
+    {
+      rtx tmp = hl;
+      hl = bc;
+      bc = tmp;
+    }
+  if (GET_CODE (hl) != REG)
+    return false;
+  if (GET_CODE (bc) != ZERO_EXTEND)
+    return false;
+  bc = XEXP (bc, 0);
+  if (GET_CODE (bc) != REG)
+    return false;
+  if (REGNO (hl) != HL_REG)
+    return false;
+  if (REGNO (bc) != B_REG && REGNO (bc) != C_REG)
+    return false;
+
+  return true;
+}
+
+#define REG_IS(r, regno) (((r) == (regno)) || ((r) >= FIRST_PSEUDO_REGISTER && !(strict)))
+
+/* Used in various constraints and predicates to match operands in the
+   "far" address space.  */
+int
+rl78_far_p (rtx x)
+{
+  if (GET_CODE (x) != MEM)
+    return 0;
+#if DEBUG0
+  fprintf(stderr, "\033[35mrl78_far_p: "); debug_rtx(x);
+  fprintf(stderr, " = %d\033[0m\n", MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR);
+#endif
+  return MEM_ADDR_SPACE (x) == ADDR_SPACE_FAR;
+}
+
+/* Return the appropriate mode for a named address pointer.  */
+#undef TARGET_ADDR_SPACE_POINTER_MODE
+#define TARGET_ADDR_SPACE_POINTER_MODE rl78_addr_space_pointer_mode
+static enum machine_mode
+rl78_addr_space_pointer_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+      return HImode;
+    case ADDR_SPACE_FAR:
+      return SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+/* Return the appropriate mode for a named address address.  */
+#undef TARGET_ADDR_SPACE_ADDRESS_MODE
+#define TARGET_ADDR_SPACE_ADDRESS_MODE rl78_addr_space_address_mode
+static enum machine_mode
+rl78_addr_space_address_mode (addr_space_t addrspace)
+{
+  switch (addrspace)
+    {
+    case ADDR_SPACE_GENERIC:
+      return HImode;
+    case ADDR_SPACE_FAR:
+      return SImode;
+    default:
+      gcc_unreachable ();
+    }
+}
+
+#undef  TARGET_LEGITIMATE_CONSTANT_P
+#define TARGET_LEGITIMATE_CONSTANT_P		rl78_is_legitimate_constant
+
+static bool
+rl78_is_legitimate_constant (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x ATTRIBUTE_UNUSED)
+{
+  return true;
+}
+
+#undef  TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P
+#define TARGET_ADDR_SPACE_LEGITIMATE_ADDRESS_P	rl78_as_legitimate_address
+
+bool
+rl78_as_legitimate_address (enum machine_mode mode ATTRIBUTE_UNUSED, rtx x,
+			    bool strict ATTRIBUTE_UNUSED, addr_space_t as ATTRIBUTE_UNUSED)
+{
+  rtx base, index, addend;
+
+  if (as == ADDR_SPACE_GENERIC
+      && GET_MODE (x) == SImode)
+    return false;
+
+  if (! characterize_address (x, &base, &index, &addend))
+    return false;
+
+  if (base && index)
+    {
+      int ir = REGNO (index);
+      int br = REGNO (base);
+
+#define OK(test, debug) if (test) { /*fprintf(stderr, "%d: OK %s\n", __LINE__, debug);*/ return true; }
+      OK (REG_IS (br, HL_REG) && REG_IS (ir, B_REG), "[hl+b]");
+      OK (REG_IS (br, HL_REG) && REG_IS (ir, C_REG), "[hl+c]");
+      return false;
+    }
+
+  if (strict && base && GET_CODE (base) == REG && REGNO (base) >= FIRST_PSEUDO_REGISTER)
+    return false;
+
+  return true;
+}
+
+/* Determine if one named address space is a subset of another.  */
+#undef  TARGET_ADDR_SPACE_SUBSET_P
+#define TARGET_ADDR_SPACE_SUBSET_P rl78_addr_space_subset_p
+static bool
+rl78_addr_space_subset_p (addr_space_t subset, addr_space_t superset)
+{
+  gcc_assert (subset == ADDR_SPACE_GENERIC || subset == ADDR_SPACE_FAR);
+  gcc_assert (superset == ADDR_SPACE_GENERIC || superset == ADDR_SPACE_FAR);
+
+  if (subset == superset)
+    return true;
+
+  else
+    return (subset == ADDR_SPACE_GENERIC && superset == ADDR_SPACE_FAR);
+}
+
+#undef  TARGET_ADDR_SPACE_CONVERT
+#define TARGET_ADDR_SPACE_CONVERT rl78_addr_space_convert
+/* Convert from one address space to another.  */
+static rtx
+rl78_addr_space_convert (rtx op, tree from_type, tree to_type)
+{
+  addr_space_t from_as = TYPE_ADDR_SPACE (TREE_TYPE (from_type));
+  addr_space_t to_as = TYPE_ADDR_SPACE (TREE_TYPE (to_type));
+  rtx result;
+
+  gcc_assert (from_as == ADDR_SPACE_GENERIC || from_as == ADDR_SPACE_FAR);
+  gcc_assert (to_as == ADDR_SPACE_GENERIC || to_as == ADDR_SPACE_FAR);
+
+  if (to_as == ADDR_SPACE_GENERIC && from_as == ADDR_SPACE_FAR)
+    {
+      /* This is unpredictable, as we're truncating off usable address
+	 bits.  */
+
+      result = gen_reg_rtx (HImode);
+      emit_move_insn (result, simplify_subreg (HImode, op, SImode, 0));
+      return result;
+    }
+  else if (to_as == ADDR_SPACE_FAR && from_as == ADDR_SPACE_GENERIC)
+    {
+      /* This always works.  */
+      result = gen_reg_rtx (SImode);
+      debug_rtx(result);
+      debug_rtx(op);
+      emit_move_insn (rl78_subreg (HImode, result, SImode, 0), op);
+      emit_move_insn (rl78_subreg (HImode, result, SImode, 2), const0_rtx);
+      return result;
+    }
+  else
+    gcc_unreachable ();
+}
+
+/* Implements REGNO_MODE_CODE_OK_FOR_BASE_P.  */
+bool
+rl78_regno_mode_code_ok_for_base_p (int regno, enum machine_mode mode ATTRIBUTE_UNUSED,
+				    int outer_code ATTRIBUTE_UNUSED, int index_code)
+{
+  if (regno < 24 && regno >= 16)
+    return true;
+  if (index_code == REG)
+    return (regno == HL_REG);
+  if (regno == C_REG || regno == B_REG || regno == E_REG || regno == L_REG)
+    return true;
+  return false;
+}
+
+/* Implements MODE_CODE_BASE_REG_CLASS.  */
+enum reg_class
+rl78_mode_code_base_reg_class (enum machine_mode mode ATTRIBUTE_UNUSED,
+			       int outer_code ATTRIBUTE_UNUSED,
+			       int index_code ATTRIBUTE_UNUSED)
+{
+  return V_REGS;
+}
+
+/* Implements INITIAL_ELIMINATION_OFFSET.  The frame layout is
+   described in the machine_Function struct definition, above.  */
+int
+rl78_initial_elimination_offset (int from, int to)
+{
+  int rv = 0; /* as if arg to arg */
+
+  rl78_compute_frame_info ();
+
+  switch (to)
+    {
+    case STACK_POINTER_REGNUM:
+      rv += cfun->machine->framesize_outgoing;
+      rv += cfun->machine->framesize_locals;
+      /* Fall through.  */
+    case FRAME_POINTER_REGNUM:
+      rv += cfun->machine->framesize_regs;
+      rv += 4;
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  switch (from)
+    {
+    case FRAME_POINTER_REGNUM:
+      rv -= 4;
+      rv -= cfun->machine->framesize_regs;
+    case ARG_POINTER_REGNUM:
+      break;
+    default:
+      gcc_unreachable ();
+    }
+
+  return rv;
+}
+
+/* Expand the function prologue (from the prologue pattern).  */
+void
+rl78_expand_prologue (void)
+{
+  int i, fs;
+  rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
+  int rb = 0;
+
+  if (!cfun->machine->computed)
+    rl78_compute_frame_info ();
+
+  for (i = 0; i < 16; i++)
+    if (cfun->machine->need_to_push [i])
+      {
+	int need_bank = i/4;
+	if (need_bank != rb)
+	  {
+	    emit_insn (gen_sel_rb (GEN_INT (need_bank)));
+	    rb = need_bank;
+	  }
+	F (emit_insn (gen_push (gen_rtx_REG (HImode, i*2))));
+      }
+  if (rb != 0)
+    emit_insn (gen_sel_rb (GEN_INT (0)));
+
+  if (frame_pointer_needed)
+    F (emit_move_insn (gen_rtx_REG (HImode, FRAME_POINTER_REGNUM),
+		       gen_rtx_REG (HImode, STACK_POINTER_REGNUM)));
+
+  fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
+  while (fs > 0)
+    {
+      int fs_byte = (fs > 254) ? 254 : fs;
+      F (emit_insn (gen_subhi3 (sp, sp, GEN_INT (fs_byte))));
+      fs -= fs_byte;
+    }
+}
+
+/* Expand the function epilogue (from the epilogue pattern).  */
+void
+rl78_expand_epilogue (void)
+{
+  int i, fs;
+  rtx sp = gen_rtx_REG (HImode, STACK_POINTER_REGNUM);
+  int rb = 0;
+
+  if (frame_pointer_needed)
+    {
+      emit_move_insn (gen_rtx_REG (HImode, STACK_POINTER_REGNUM),
+		      gen_rtx_REG (HImode, FRAME_POINTER_REGNUM));
+    }
+  else
+    {
+      fs = cfun->machine->framesize_locals + cfun->machine->framesize_outgoing;
+      while (fs > 0)
+	{
+	  int fs_byte = (fs > 254) ? 254 : fs;
+
+	  emit_insn (gen_addhi3 (sp, sp, GEN_INT (fs_byte)));
+	  fs -= fs_byte;
+	}
+    }
+
+  for (i = 15; i >= 0; i--)
+    if (cfun->machine->need_to_push [i])
+      {
+	int need_bank = i / 4;
+
+	if (need_bank != rb)
+	  {
+	    emit_insn (gen_sel_rb (GEN_INT (need_bank)));
+	    rb = need_bank;
+	  }
+	emit_insn (gen_pop (gen_rtx_REG (HImode, i * 2)));
+      }
+
+  if (rb != 0)
+    emit_insn (gen_sel_rb (GEN_INT (0)));
+
+  if (cfun->machine->trampolines_used)
+    emit_insn (gen_trampoline_uninit ());
+
+  if (is_brk_interrupt_func (cfun->decl))
+    emit_jump_insn (gen_brk_interrupt_return ());
+  else if (is_interrupt_func (cfun->decl))
+    emit_jump_insn (gen_interrupt_return ());
+  else
+    emit_jump_insn (gen_simple_return ());
+}
+
+/* Likewise, for exception handlers.  */
+void
+rl78_expand_eh_epilogue (rtx x ATTRIBUTE_UNUSED)
+{
+  /* FIXME - replace this with an indirect jump with stack adjust.  */
+  emit_jump_insn (gen_simple_return ());
+}
+
+#undef  TARGET_ASM_FUNCTION_PROLOGUE
+#define TARGET_ASM_FUNCTION_PROLOGUE	rl78_start_function
+
+/* We don't use this to actually emit the function prologue.  We use
+   this to insert a comment in the asm file describing the
+   function.  */
+static void
+rl78_start_function (FILE *file, HOST_WIDE_INT hwi_local ATTRIBUTE_UNUSED)
+{
+  int i;
+
+  if (cfun->machine->framesize == 0)
+    return;
+  fprintf (file, "\t; start of function\n");
+
+  if (cfun->machine->framesize_regs)
+    {
+      fprintf (file, "\t; push %d:", cfun->machine->framesize_regs);
+      for (i = 0; i < 16; i ++)
+	if (cfun->machine->need_to_push[i])
+	  fprintf (file, " %s", word_regnames[i*2]);
+      fprintf(file, "\n");
+    }
+
+  if (frame_pointer_needed)
+    fprintf (file, "\t; $fp points here (r22)\n");
+
+  if (cfun->machine->framesize_locals)
+    fprintf (file, "\t; locals: %d byte%s\n", cfun->machine->framesize_locals,
+	     cfun->machine->framesize_locals == 1 ? "" : "s");
+
+  if (cfun->machine->framesize_outgoing)
+    fprintf (file, "\t; outgoing: %d byte%s\n", cfun->machine->framesize_outgoing,
+	     cfun->machine->framesize_outgoing == 1 ? "" : "s");
+}
+
+/* Return an RTL describing where a function return value of type RET_TYPE
+   is held.  */
+
+#undef  TARGET_FUNCTION_VALUE
+#define TARGET_FUNCTION_VALUE		rl78_function_value
+
+static rtx
+rl78_function_value (const_tree ret_type,
+		     const_tree fn_decl_or_type ATTRIBUTE_UNUSED,
+		     bool       outgoing ATTRIBUTE_UNUSED)
+{
+  enum machine_mode mode = TYPE_MODE (ret_type);
+
+  return gen_rtx_REG (mode, 8);
+}
+
+#undef  TARGET_PROMOTE_FUNCTION_MODE
+#define TARGET_PROMOTE_FUNCTION_MODE rl78_promote_function_mode
+
+static enum machine_mode
+rl78_promote_function_mode (const_tree type ATTRIBUTE_UNUSED,
+			    enum machine_mode mode,
+			    int *punsignedp ATTRIBUTE_UNUSED,
+			    const_tree funtype ATTRIBUTE_UNUSED, int for_return ATTRIBUTE_UNUSED)
+{
+  return mode;
+}
+
+/* Return an RTL expression describing the register holding a function
+   parameter of mode MODE and type TYPE or NULL_RTX if the parameter should
+   be passed on the stack.  CUM describes the previous parameters to the
+   function and NAMED is false if the parameter is part of a variable
+   parameter list, or the last named parameter before the start of a
+   variable parameter list.  */
+
+#undef  TARGET_FUNCTION_ARG
+#define TARGET_FUNCTION_ARG     	rl78_function_arg
+
+static rtx
+rl78_function_arg (cumulative_args_t cum_v ATTRIBUTE_UNUSED,
+		   enum machine_mode mode ATTRIBUTE_UNUSED,
+		   const_tree type ATTRIBUTE_UNUSED,
+		   bool named ATTRIBUTE_UNUSED)
+{
+  return NULL_RTX;
+}
+
+#undef  TARGET_FUNCTION_ARG_ADVANCE
+#define TARGET_FUNCTION_ARG_ADVANCE     rl78_function_arg_advance
+
+static void
+rl78_function_arg_advance (cumulative_args_t cum_v, enum machine_mode mode, const_tree type,
+			   bool named ATTRIBUTE_UNUSED)
+{
+  int rounded_size;
+  CUMULATIVE_ARGS * cum = get_cumulative_args (cum_v);
+
+  rounded_size = ((mode == BLKmode)
+		  ? int_size_in_bytes (type) : GET_MODE_SIZE (mode));
+  if (rounded_size & 1)
+    rounded_size ++;
+  (*cum) += rounded_size;
+}
+
+#undef  TARGET_FUNCTION_ARG_BOUNDARY
+#define	TARGET_FUNCTION_ARG_BOUNDARY rl78_function_arg_boundary
+
+static unsigned int
+rl78_function_arg_boundary (enum machine_mode mode ATTRIBUTE_UNUSED,
+			    const_tree type ATTRIBUTE_UNUSED)
+{
+  return 16;
+}
+
+/* Supported modifier letters:
+
+   A - address of a MEM
+   S - SADDR form of a real register
+   v - real register corresponding to a virtual register
+   m - minus - negative of CONST_INT value.
+   c - inverse of a conditional (NE vs EQ for example)
+
+   h - bottom HI of an SI
+   H - top HI of an SI
+   q - bottom QI of an HI
+   Q - top QI of an HI
+   e - third QI of an SI (i.e. where the ES register gets values from)
+
+*/
+
+/* Implements the bulk of rl78_print_operand, below.  We do it this
+   way because we need to test for a constant at the top level and
+   insert the '#', but not test for it anywhere else as we recurse
+   down into the operand.  */
+static void
+rl78_print_operand_1 (FILE * file, rtx op, int letter)
+{
+  int need_paren;
+
+  switch (GET_CODE (op))
+    {
+    case MEM:
+      if (letter == 'A')
+	rl78_print_operand_1 (file, XEXP (op, 0), letter);
+      else
+	{
+	  if (rl78_far_p (op))
+	    fprintf(file, "es:");
+	  if (letter == 'H')
+	    {
+	      op = adjust_address (op, HImode, 2);
+	      letter = 0;
+	    }
+	  if (letter == 'h')
+	    {
+	      op = adjust_address (op, HImode, 0);
+	      letter = 0;
+	    }
+	  if (letter == 'Q')
+	    {
+	      op = adjust_address (op, QImode, 1);
+	      letter = 0;
+	    }
+	  if (letter == 'q')
+	    {
+	      op = adjust_address (op, QImode, 0);
+	      letter = 0;
+	    }
+	  if (letter == 'e')
+	    {
+	      op = adjust_address (op, QImode, 2);
+	      letter = 0;
+	    }
+	  if (CONSTANT_P (XEXP (op, 0)))
+	    {
+	      fprintf(file, "!");
+	      rl78_print_operand_1 (file, XEXP (op, 0), letter);
+	    }
+	  else if (GET_CODE (XEXP (op, 0)) == PLUS
+		   && GET_CODE (XEXP (XEXP (op, 0), 0)) == SYMBOL_REF)
+	    {
+	      fprintf(file, "!");
+	      rl78_print_operand_1 (file, XEXP (op, 0), letter);
+	    }
+	  else if (GET_CODE (XEXP (op, 0)) == PLUS
+		   && GET_CODE (XEXP (XEXP (op, 0), 0)) == REG
+		   && REGNO (XEXP (XEXP (op, 0), 0)) == 2)
+	    {
+	      rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 1), 'u');
+	      fprintf(file, "[");
+	      rl78_print_operand_1 (file, XEXP (XEXP (op, 0), 0), 0);
+	      fprintf(file, "]");
+	    }
+	  else
+	    {
+	      fprintf(file, "[");
+	      rl78_print_operand_1 (file, XEXP (op, 0), letter);
+	      fprintf(file, "]");
+	    }
+	}
+      break;
+
+    case REG:
+      if (letter == 'Q')
+	fprintf (file, "%s", reg_names [REGNO (op) | 1]);
+      else if (letter == 'H')
+	fprintf (file, "%s", reg_names [REGNO (op) + 2]);
+      else if (letter == 'q')
+	fprintf (file, "%s", reg_names [REGNO (op) & ~1]);
+      else if (letter == 'e')
+	fprintf (file, "%s", reg_names [REGNO (op) + 2]);
+      else if (letter == 'S')
+	fprintf (file, "0x%x", 0xffef8 + REGNO (op));
+      else if (GET_MODE (op) == HImode
+	       && ! (REGNO (op) & ~0xfe))
+	{
+	  if (letter == 'v')
+	    fprintf (file, "%s", word_regnames [REGNO (op) % 8]);
+	  else
+	    fprintf (file, "%s", word_regnames [REGNO (op)]);
+	}
+      else
+	fprintf (file, "%s", reg_names [REGNO (op)]);
+      break;
+
+    case CONST_INT:
+      if (letter == 'Q')
+	fprintf (file, "%ld", INTVAL (op) >> 8);
+      else if (letter == 'H')
+	fprintf (file, "%ld", INTVAL (op) >> 16);
+      else if (letter == 'q')
+	fprintf (file, "%ld", INTVAL (op) & 0xff);
+      else if (letter == 'h')
+	fprintf (file, "%ld", INTVAL (op) & 0xffff);
+      else if (letter == 'e')
+	fprintf (file, "%ld", (INTVAL (op) >> 16) & 0xff);
+      else if (letter == 'm')
+	fprintf (file, "%ld", - INTVAL (op));
+      else
+	fprintf(file, "%ld", INTVAL (op));
+      break;
+
+    case CONST:
+      rl78_print_operand_1 (file, XEXP (op, 0), letter);
+      break;
+
+    case ZERO_EXTRACT:
+      {
+	int bits = INTVAL (XEXP (op, 1));
+	int ofs = INTVAL (XEXP (op, 2));
+	if (bits == 16 && ofs == 0)
+	  fprintf (file, "%%lo16(");
+	else if (bits == 16 && ofs == 16)
+	  fprintf (file, "%%hi16(");
+	else if (bits == 8 && ofs == 16)
+	  fprintf (file, "%%hi8(");
+	else
+	  gcc_unreachable ();
+	rl78_print_operand_1 (file, XEXP (op, 0), 0);
+	fprintf (file, ")");
+      }
+      break;
+
+    case ZERO_EXTEND:
+      if (GET_CODE (XEXP (op, 0)) == REG)
+	fprintf (file, "%s", reg_names [REGNO (XEXP (op, 0))]);
+      else
+	print_rtl (file, op);
+      break;
+
+    case PLUS:
+      need_paren = 0;
+      if (letter == 'H')
+	{
+	  fprintf (file, "%%hi16(");
+	  need_paren = 1;
+	  letter = 0;
+	}
+      if (letter == 'h')
+	{
+	  fprintf (file, "%%lo16(");
+	  need_paren = 1;
+	  letter = 0;
+	}
+      if (letter == 'e')
+	{
+	  fprintf (file, "%%hi8(");
+	  need_paren = 1;
+	  letter = 0;
+	}
+      if (letter == 'q' || letter == 'Q')
+	output_operand_lossage ("q/Q modifiers invalid for symbol references");
+
+      if (GET_CODE (XEXP (op, 0)) == ZERO_EXTEND)
+	{
+	  rl78_print_operand_1 (file, XEXP (op, 1), letter);
+	  fprintf (file, "+");
+	  rl78_print_operand_1 (file, XEXP (op, 0), letter);
+	}
+      else
+	{
+	  rl78_print_operand_1 (file, XEXP (op, 0), letter);
+	  fprintf (file, "+");
+	  rl78_print_operand_1 (file, XEXP (op, 1), letter);
+	}
+      if (need_paren)
+	fprintf (file, ")");
+      break;
+
+    case SYMBOL_REF:
+      need_paren = 0;
+      if (letter == 'H')
+	{
+	  fprintf (file, "%%hi16(");
+	  need_paren = 1;
+	  letter = 0;
+	}
+      if (letter == 'h')
+	{
+	  fprintf (file, "%%lo16(");
+	  need_paren = 1;
+	  letter = 0;
+	}
+      if (letter == 'e')
+	{
+	  fprintf (file, "%%hi8(");
+	  need_paren = 1;
+	  letter = 0;
+	}
+      if (letter == 'q' || letter == 'Q')
+	output_operand_lossage ("q/Q modifiers invalid for symbol references");
+
+      output_addr_const (file, op);
+      if (need_paren)
+	fprintf (file, ")");
+      break;
+
+    case CODE_LABEL:
+    case LABEL_REF:
+      output_asm_label (op);
+      break;
+
+    case LTU:
+      fprintf (file, letter == 'c' ? "nc" : "c");
+      break;
+    case LEU:
+      fprintf (file, letter == 'c' ? "h" : "nh");
+      break;
+    case GEU:
+      fprintf (file, letter == 'c' ? "c" : "nc");
+      break;
+    case GTU:
+      fprintf (file, letter == 'c' ? "nh" : "h");
+      break;
+    case EQ:
+      fprintf (file, letter == 'c' ? "nz" : "z");
+      break;
+    case NE:
+      fprintf (file, letter == 'c' ? "z" : "nz");
+      break;
+
+    default:
+      fprintf (file, "(%s)", GET_RTX_NAME (GET_CODE (op)));
+      break;
+    }
+}
+
+#undef  TARGET_PRINT_OPERAND
+#define TARGET_PRINT_OPERAND		rl78_print_operand
+
+static void
+rl78_print_operand (FILE * file, rtx op, int letter)
+{
+  if (CONSTANT_P (op) && letter != 'u')
+    fprintf (file, "#");
+  rl78_print_operand_1 (file, op, letter);
+}
+
+#undef  TARGET_TRAMPOLINE_INIT
+#define TARGET_TRAMPOLINE_INIT rl78_trampoline_init
+
+/* Note that the RL78's addressing makes it very difficult to do
+   trampolines on the stack.  So, libgcc has a small pool of
+   trampolines from which one is allocated to this task.  */
+static void
+rl78_trampoline_init (rtx m_tramp, tree fndecl, rtx static_chain)
+{
+  rtx mov_addr, thunk_addr;
+  rtx function = XEXP (DECL_RTL (fndecl), 0);
+
+  mov_addr = adjust_address (m_tramp, HImode, 0);
+  thunk_addr = gen_reg_rtx (HImode);
+
+  function = force_reg (HImode, function);
+  static_chain = force_reg (HImode, static_chain);
+
+  emit_insn (gen_trampoline_init (thunk_addr, function, static_chain));
+  emit_move_insn (mov_addr, thunk_addr);
+
+  cfun->machine->trampolines_used = 1;
+}
+
+#undef  TARGET_TRAMPOLINE_ADJUST_ADDRESS
+#define TARGET_TRAMPOLINE_ADJUST_ADDRESS rl78_trampoline_adjust_address
+
+static rtx
+rl78_trampoline_adjust_address (rtx m_tramp)
+{
+  rtx x = gen_rtx_MEM (HImode, m_tramp);
+  return x;
+}
+
+/* Expander for cbranchqi4 and cbranchhi4.  RL78 is missing some of
+   the "normal" compares, specifically, it only has unsigned compares,
+   so we must synthesize the missing ones.  */
+void
+rl78_expand_compare (rtx *operands)
+{
+  /* RL78 does not have signed comparisons.  We must modify the
+     operands to be in the unsigned range, and emit an unsigned
+     comparison.  */
+
+  enum machine_mode mode;
+  rtx high_bit;
+  int i;
+  RTX_CODE new_cond;
+
+  switch (GET_CODE (operands[0]))
+    {
+    case GE:
+      new_cond = GEU;
+      break;
+    case LE:
+      new_cond = LEU;
+      break;
+    case GT:
+      new_cond = GTU;
+      break;
+    case LT:
+      new_cond = LTU;
+      break;
+    default:
+      return;
+    }
+
+#if DEBUG0
+  fprintf (stderr, "\033[38;5;129mrl78_expand_compare\n");
+  debug_rtx (operands[0]);
+  fprintf (stderr, "\033[0m");
+#endif
+
+  mode = GET_MODE (operands[1]);
+  if (mode == VOIDmode)
+    mode = GET_MODE (operands[2]);
+  high_bit = GEN_INT (~0 << (GET_MODE_BITSIZE (mode) - 1));
+
+  /* 0: conditional 1,2: operands */
+  for (i = 1; i <= 2; i ++)
+    {
+      rtx r = operands[i];
+
+      if (GET_CODE (r) == CONST_INT)
+	r = GEN_INT (INTVAL (r) ^ INTVAL (high_bit));
+      else
+	{
+	  r = gen_rtx_PLUS (mode, operands[i], high_bit);
+	  r = copy_to_mode_reg (mode, r);
+	}
+      operands[i] = r;
+    }
+
+  operands[0] = gen_rtx_fmt_ee (new_cond, GET_MODE (operands[0]), operands[1], operands[2]);
+
+#if DEBUG0
+  fprintf (stderr, "\033[38;5;142mrl78_expand_compare\n");
+  debug_rtx (operands[0]);
+  fprintf (stderr, "\033[0m");
+#endif
+}
+
+
+
+/* Define this to 1 if you are debugging the peephole optimizers.  */
+#define DEBUG_PEEP 0
+
+/* Predicate used to enable the peephole2 patterns in rl78-virt.md.
+   The default "word" size is a byte so we can effectively use all the
+   registers, but we want to do 16-bit moves whenever possible.  This
+   function determines when such a move is an option.  */
+bool
+rl78_peep_movhi_p (rtx *operands)
+{
+  int i;
+  rtx m, a;
+
+  /* (set (op0) (op1))
+     (set (op2) (op3)) */
+
+#if DEBUG_PEEP
+  fprintf (stderr, "\033[33m");
+  debug_rtx(operands[0]);
+  debug_rtx(operands[1]);
+  debug_rtx(operands[2]);
+  debug_rtx(operands[3]);
+  fprintf (stderr, "\033[0m");
+#endif
+
+  if (rtx_equal_p (operands[0], operands[3]))
+    {
+#if DEBUG_PEEP
+      fprintf (stderr, "no peep: overlapping\n");
+#endif
+      return false;
+    }
+
+  for (i = 0; i < 2; i ++)
+    {
+      if (GET_CODE (operands[i]) != GET_CODE (operands[i+2]))
+	{
+#if DEBUG_PEEP
+	  fprintf (stderr, "no peep: different codes\n");
+#endif
+	  return false;
+	}
+      if (GET_MODE (operands[i]) != GET_MODE (operands[i+2]))
+	{
+#if DEBUG_PEEP
+	  fprintf (stderr, "no peep: different modes\n");
+#endif
+	  return false;
+	}
+
+      switch (GET_CODE (operands[i]))
+	{
+	case REG:
+	  /*   LSB                      MSB  */
+	  if (REGNO (operands[i]) + 1 != REGNO (operands[i+2])
+	      || GET_MODE (operands[i]) != QImode)
+	    {
+#if DEBUG_PEEP
+	      fprintf (stderr, "no peep: wrong regnos %d %d %d\n",
+		       REGNO (operands[i]), REGNO (operands[i+2]),
+		       i);
+#endif
+	      return false;
+	    }
+	  if (! rl78_hard_regno_mode_ok (REGNO (operands[i]), HImode))
+	    {
+#if DEBUG_PEEP
+	      fprintf (stderr, "no peep: reg %d not HI\n", REGNO (operands[i]));
+#endif
+	      return false;
+	    }
+	  break;
+
+	case CONST_INT:
+	  break;
+
+	case MEM:
+	  if (GET_MODE (operands[i]) != QImode)
+	    return false;
+	  if (MEM_ALIGN (operands[i]) < 16)
+	    return false;
+	  a = XEXP (operands[i], 0);
+	  if (GET_CODE (a) == CONST)
+	    a = XEXP (a, 0);
+	  if (GET_CODE (a) == PLUS)
+	    a = XEXP (a, 1);
+	  if (GET_CODE (a) == CONST_INT
+	      && INTVAL (a) & 1)
+	    {
+#if DEBUG_PEEP
+	      fprintf (stderr, "no peep: misaligned mem %d\n", i);
+	      debug_rtx (operands[i]);
+#endif
+	      return false;
+	    }
+	  m = adjust_address (operands[i], QImode, 1);
+	  if (! rtx_equal_p (m, operands[i+2]))
+	    {
+#if DEBUG_PEEP
+	      fprintf (stderr, "no peep: wrong mem %d\n", i);
+	      debug_rtx(m);
+	      debug_rtx (operands[i+2]);
+#endif
+	      return false;
+	    }
+	  break;
+
+	default:
+#if DEBUG_PEEP
+	  fprintf (stderr, "no peep: wrong rtx %d\n", i);
+#endif
+	  return false;
+	}
+    }
+#if DEBUG_PEEP
+  fprintf (stderr, "\033[32mpeep!\033[0m\n");
+#endif
+  return true;
+}
+
+/* Likewise, when a peephole is activated, this function helps compute
+   the new operands.  */
+void
+rl78_setup_peep_movhi (rtx *operands)
+{
+  int i;
+
+  for (i = 0; i < 2; i ++)
+    {
+      switch (GET_CODE (operands[i]))
+	{
+	case REG:
+	  operands[i+4] = gen_rtx_REG (HImode, REGNO (operands[i]));
+	  break;
+
+	case CONST_INT:
+	  operands[i+4] = GEN_INT ((INTVAL (operands[i]) & 0xff) + ((char)INTVAL (operands[i+2])) * 256);
+	  break;
+
+	case MEM:
+	  operands[i+4] = adjust_address (operands[i], HImode, 0);
+	  break;
+
+	default:
+	  break;
+	}
+    }
+}
+
+/*
+	How Devirtualization works in the RL78 GCC port
+
+Background
+
+The RL78 is an 8-bit port with some 16-bit operations.  It has 32
+bytes of register space, in four banks, memory-mapped.  One bank is
+the "selected" bank and holds the registers used for primary
+operations.  Since the registers are memory mapped, often you can
+still refer to the unselected banks via memory accesses.
+
+Virtual Registers
+
+The GCC port uses bank 0 as the "selected" registers (A, X, BC, etc)
+and refers to the other banks via their memory addresses, although
+they're treated as regular registers internally.  These "virtual"
+registers are R8 through R23 (bank3 is reserved for asm-based
+interrupt handlers).
+
+There are four machine description files:
+
+rl78.md        - common register-independent patterns and definitions
+rl78-expand.md - expanders
+rl78-virt.md   - patterns that match BEFORE devirtualization
+rl78-real.md   - patterns that match AFTER devirtualization
+
+At least through register allocation and reload, gcc is told that it
+can do pretty much anything - but may only use the virtual registers.
+GCC cannot properly create the varying addressing modes that the RL78
+supports in an efficient way.
+
+Sometime after reload, the RL78 backend "devirtualizes" the RTL.  It
+uses the "valloc" attribute in rl78-virt.md for determining the rules
+by which it will replace virtual registers with real registers (or
+not) and how to make up addressing modes.  For example, insns tagged
+with "ro1" have a single read-only parameter, which may need to be
+moved from memory/constant/vreg to a suitable real register.  As part
+of devirtualization, a flag is toggled, disabling the rl78-virt.md
+patterns and enabling the rl78-real.md patterns.  The new patterns'
+constraints are used to determine the real registers used.  NOTE:
+patterns in rl78-virt.md essentially ignore the constrains and rely on
+predicates, where the rl78-real.md ones essentially ignore the
+predicates and rely on the constraints.
+
+The devirtualization pass is scheduled via the pass manager (despite
+being called "rl78_reorg") so it can be scheduled prior to var-track
+(the idea is to let gdb know about the new registers).  Ideally, it
+would be scheduled right after pro/epilogue generation, so the
+post-reload optimizers could operate on the real registers, but when I
+tried that there were some issues building the target libraries.
+
+During devirtualization, a simple register move optimizer is run.  It
+would be better to run a full CSE/propogation pass on it through, or
+re-run regmove, but that has not yet been attempted.
+
+ */
+#define DEBUG_ALLOC 0
+
+/* Rescans an insn to see if it's recognized again.  This is done
+   carefully to ensure that all the constraint information is accurate
+   for the newly matched insn.  */
+static bool
+insn_ok_now (rtx insn)
+{
+  INSN_CODE (insn) = -1;
+  if (recog (PATTERN (insn), insn, 0) > -1)
+    {
+      extract_insn (insn);
+      if (constrain_operands (1))
+	{
+#if DEBUG_ALLOC
+	  fprintf (stderr, "\033[32m");
+	  debug_rtx (insn);
+	  fprintf (stderr, "\033[0m");
+#endif
+	  return true;
+	}
+    }
+  else
+    {
+      fprintf (stderr, "\033[41;30m Unrecognized insn \033[0m\n");
+      debug_rtx (insn);
+      gcc_unreachable ();
+    }
+#if DEBUG_ALLOC
+  fprintf (stderr, "\033[31m");
+  debug_rtx (insn);
+  fprintf (stderr, "\033[0m");
+#endif
+  return false;
+}
+
+#if DEBUG_ALLOC
+#define WORKED fprintf (stderr, "\033[48;5;22m Worked at line %d \033[0m\n", __LINE__)
+#define FAILEDSOFAR fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__)
+#define FAILED fprintf (stderr, "\033[48;5;52m FAILED at line %d \033[0m\n", __LINE__), gcc_unreachable()
+#define MAYBE_OK(insn) if (insn_ok_now (insn)) { WORKED; return; } else { FAILEDSOFAR; }
+#else
+#define WORKED
+#define FAILEDSOFAR
+#define FAILED
+#define MAYBE_OK(insn) if (insn_ok_now (insn)) return;
+#endif
+
+/* Registers into which we move the contents of virtual registers.  */
+#define X gen_rtx_REG (QImode, 0)
+#define A gen_rtx_REG (QImode, 1)
+#define C gen_rtx_REG (QImode, 2)
+#define B gen_rtx_REG (QImode, 3)
+#define E gen_rtx_REG (QImode, 4)
+#define D gen_rtx_REG (QImode, 5)
+#define L gen_rtx_REG (QImode, 6)
+#define H gen_rtx_REG (QImode, 7)
+
+#define AX gen_rtx_REG (HImode, 0)
+#define BC gen_rtx_REG (HImode, 2)
+#define DE gen_rtx_REG (HImode, 4)
+#define HL gen_rtx_REG (HImode, 6)
+
+#define OP(x) (*recog_data.operand_loc[x])
+
+/* Returns TRUE if R is a virtual register.  */
+static bool
+is_virtual_register (rtx r)
+{
+  return (GET_CODE (r) == REG
+	  && REGNO (r) >= 8
+	  && REGNO (r) < 24);
+}
+
+/* In all these alloc routines, we expect the following: the insn
+   pattern is unshared, the insn was previously recognized and failed
+   due to predicates or constraints, and the operand data is in
+   recog_data.  */
+
+static int virt_insn_was_frame;
+
+/* Hook for all insns we emit.  Re-mark them as FRAME_RELATED if
+   needed.  */
+static rtx
+EM2 (int line ATTRIBUTE_UNUSED, rtx r)
+{
+#if DEBUG_ALLOC
+  fprintf (stderr, "\033[36m%d: ", line);
+  debug_rtx(r);
+  fprintf (stderr, "\033[0m");
+#endif
+  /*SCHED_GROUP_P (r) = 1;*/
+  if (virt_insn_was_frame)
+    RTX_FRAME_RELATED_P (r) = 1;
+  return r;
+}
+
+#define EM(x) EM2 (__LINE__, x)
+
+/* Return a suitable RTX for the low half of a __far address.  */
+static rtx
+rl78_lo16 (rtx addr)
+{
+  if (GET_CODE (addr) == SYMBOL_REF
+      || GET_CODE (addr) == CONST)
+    {
+      rtx r = gen_rtx_ZERO_EXTRACT (HImode, addr, GEN_INT (16), GEN_INT (0));
+      r = gen_rtx_CONST (HImode, r);
+      return r;
+    }
+  return rl78_subreg (HImode, addr, SImode, 0);
+}
+
+/* Return a suitable RTX for the high half's lower byte of a __far address.  */
+static rtx
+rl78_hi8 (rtx addr)
+{
+  if (GET_CODE (addr) == SYMBOL_REF
+      || GET_CODE (addr) == CONST)
+    {
+      rtx r = gen_rtx_ZERO_EXTRACT (QImode, addr, GEN_INT (8), GEN_INT (16));
+      r = gen_rtx_CONST (QImode, r);
+      return r;
+    }
+  return rl78_subreg (QImode, addr, SImode, 2);
+}
+
+/* Copy any register values into real registers and return an RTX for
+   the same memory, now addressed by real registers.  Any needed insns
+   are emitted before BEFORE.  */
+static rtx
+transcode_memory_rtx (rtx m, rtx newbase, rtx before)
+{
+  rtx base, index, addendr;
+  int addend = 0;
+
+  if (GET_CODE (m) != MEM)
+    return m;
+
+  if (GET_MODE (XEXP (m, 0)) == SImode)
+    {
+      rtx seg = rl78_hi8 (XEXP (m, 0));
+#if DEBUG_ALLOC
+      fprintf (stderr, "setting ES:\n");
+      debug_rtx(seg);
+#endif
+      emit_insn_before (EM(gen_movqi (A, seg)), before);
+      emit_insn_before (EM(gen_movqi_es (A)), before);
+      m = change_address (m, GET_MODE (m), rl78_lo16 (XEXP (m, 0)));
+    }
+
+  characterize_address (XEXP (m, 0), &base, &index, &addendr);
+  gcc_assert (index == NULL_RTX);
+
+#if DEBUG_ALLOC
+  fprintf (stderr, "\033[33m"); debug_rtx(m); fprintf (stderr, "\033[0m");
+  debug_rtx (base);
+#endif
+  if (base == NULL_RTX)
+    return m;
+
+  if (addendr && GET_CODE (addendr) == CONST_INT)
+    addend = INTVAL (addendr);
+
+  if (REGNO (base) == SP_REG)
+    {
+      if (addend >= 0 && addend  <= 255)
+	return m;
+    }
+
+  /* BASE should be a virtual register.  We copy it to NEWBASE.  If
+     the addend is out of range for DE/HL, we use AX to compute the full
+     address.  */
+
+  if (addend < 0
+      || (addend > 255 && REGNO (newbase) != 2)
+      || (addendr && GET_CODE (addendr) != CONST_INT))
+    {
+      /* mov ax, vreg
+	 add ax, #imm
+	 mov hl, ax	*/
+      EM (emit_insn_before (gen_movhi (AX, base), before));
+      EM (emit_insn_before (gen_addhi3 (AX, AX, addendr), before));
+      EM (emit_insn_before (gen_movhi (newbase, AX), before));
+      base = newbase;
+      addend = 0;
+    }
+  else
+    {
+      EM (emit_insn_before (gen_movhi (newbase, base), before));
+      base = newbase;
+    }
+
+  if (addend)
+    base = gen_rtx_PLUS (HImode, base, GEN_INT (addend));
+
+#if DEBUG_ALLOC
+  fprintf (stderr, "\033[33m");
+  debug_rtx (m);
+#endif
+  m = change_address (m, GET_MODE (m), base);
+#if DEBUG_ALLOC
+  debug_rtx (m);
+  fprintf (stderr, "\033[0m");
+#endif
+  return m;
+}
+
+/* Copy SRC to accumulator (A or AX), placing any generated insns
+   before BEFORE.  Returns accumulator RTX.  */
+
+static rtx
+move_to_acc (int opno, rtx before)
+{
+  rtx src = OP(opno);
+  enum machine_mode mode = GET_MODE (src);
+
+  if (GET_CODE (src) == REG
+      && REGNO (src) < 2)
+    return src;
+
+  if (mode == VOIDmode)
+    mode = recog_data.operand_mode[opno];
+
+  if (mode == QImode)
+    {
+      EM (emit_insn_before (gen_movqi (A, src), before));
+      return A;
+    }
+  else
+    {
+      EM (emit_insn_before (gen_movhi (AX, src), before));
+      return AX;
+    }
+}
+
+/* Copy accumulator (A or AX) to DEST, placing any generated insns
+   after AFTER.  Returns accumulator RTX.  */
+
+static rtx
+move_from_acc (rtx dest, rtx after)
+{
+  enum machine_mode mode = GET_MODE (dest);
+
+  if (REG_P (dest) && REGNO (dest) < 2)
+    return dest;
+
+  if (mode == QImode)
+    {
+      EM (emit_insn_after (gen_movqi (dest, A), after));
+      return A;
+    }
+  else
+    {
+      EM (emit_insn_after (gen_movhi (dest, AX), after));
+      return AX;
+    }
+}
+
+/* Copy accumulator (A or AX) to REGNO, placing any generated insns
+   before BEFORE.  Returns reg RTX.  */
+
+static rtx
+move_acc_to_reg (rtx acc, int regno, rtx before)
+{
+  enum machine_mode mode = GET_MODE (acc);
+  rtx reg;
+
+  reg = gen_rtx_REG (mode, regno);
+
+  if (mode == QImode)
+    {
+      EM (emit_insn_before (gen_movqi (reg, A), before));
+      return reg;
+    }
+  else
+    {
+      EM (emit_insn_before (gen_movhi (reg, AX), before));
+      return reg;
+    }
+}
+
+/* Copy SRC to X, placing any generated insns before BEFORE.
+   Returns X RTX.  */
+
+static rtx
+move_to_x (int opno, rtx before)
+{
+  rtx src = OP(opno);
+  enum machine_mode mode = GET_MODE (src);
+  rtx reg;
+
+  if (mode == VOIDmode)
+    mode = recog_data.operand_mode[opno];
+  reg = (mode == QImode) ? X : AX;
+
+  if (mode == QImode || ! is_virtual_register (OP (opno)))
+    {
+      OP(opno) = move_to_acc (opno, before);
+      OP(opno) = move_acc_to_reg (OP(opno), X_REG, before);
+      return reg;
+    }
+
+  if (mode == QImode)
+    EM (emit_insn_before (gen_movqi (reg, src), before));
+  else
+    EM (emit_insn_before (gen_movhi (reg, src), before));
+
+  return reg;
+}
+
+/* Copy OP(opno) to H or HL, placing any generated insns before BEFORE.
+   Returns H/HL RTX.  */
+
+static rtx
+move_to_hl (int opno, rtx before)
+{
+  rtx src = OP (opno);
+  enum machine_mode mode = GET_MODE (src);
+  rtx reg;
+
+  if (mode == VOIDmode)
+    mode = recog_data.operand_mode[opno];
+  reg = (mode == QImode) ? L : HL;
+
+  if (mode == QImode || ! is_virtual_register (OP (opno)))
+    {
+      OP (opno) = move_to_acc (opno, before);
+      OP (opno) = move_acc_to_reg (OP (opno), L_REG, before);
+      return reg;
+    }
+
+  if (mode == QImode)
+    EM (emit_insn_before (gen_movqi (reg, src), before));
+  else
+    EM (emit_insn_before (gen_movhi (reg, src), before));
+
+  return reg;
+}
+
+/* Copy OP(opno) to E or DE, placing any generated insns before BEFORE.
+   Returns E/DE RTX.  */
+
+static rtx
+move_to_de (int opno, rtx before)
+{
+  rtx src = OP (opno);
+  enum machine_mode mode = GET_MODE (src);
+  rtx reg;
+
+  if (mode == VOIDmode)
+    mode = recog_data.operand_mode[opno];
+
+  reg = (mode == QImode) ? E : DE;
+
+  if (mode == QImode || ! is_virtual_register (OP (opno)))
+    {
+      OP (opno) = move_to_acc (opno, before);
+      OP (opno) = move_acc_to_reg (OP (opno), E_REG, before);
+    }
+  else
+    {
+      rtx move = mode == QImode ? gen_movqi (reg, src) : gen_movhi (reg, src);
+
+      EM (emit_insn_before (move, before));
+    }
+
+  return reg;
+}
+
+/* Devirtualize an insn of the form (SET (op) (unop (op))).  */
+static void
+rl78_alloc_physical_registers_op1 (rtx insn)
+{
+  /* op[0] = func op[1] */
+
+  /* We first try using A as the destination, then copying it
+     back.  */
+  if (rtx_equal_p (OP(0), OP(1)))
+    {
+      OP(0) =
+      OP(1) = transcode_memory_rtx (OP(1), DE, insn);
+    }
+  else
+    {
+      OP(0) = transcode_memory_rtx (OP(0), BC, insn);
+      OP(1) = transcode_memory_rtx (OP(1), HL, insn);
+    }
+
+  MAYBE_OK (insn);
+
+  OP(0) = move_from_acc (OP(0), insn);
+
+  MAYBE_OK (insn);
+
+  /* Try copying the src to acc first, then.  This is for, for
+     example, ZERO_EXTEND or NOT.  */
+  OP(1) = move_to_acc (1, insn);
+
+  MAYBE_OK (insn);
+
+  FAILED;
+}
+
+/* Devirtualize an insn of the form (SET (op) (unop (op) (op))).  */
+static void
+rl78_alloc_physical_registers_op2 (rtx insn)
+{
+  /* op[0] = op[1] func op[2] */
+  rtx prev = prev_nonnote_nondebug_insn (insn);
+  rtx first;
+  bool hl_used;
+
+  if (rtx_equal_p (OP(0), OP(1)))
+    {
+      OP(0) =
+      OP(1) = transcode_memory_rtx (OP(1), DE, insn);
+      prev = next_nonnote_nondebug_insn (prev);
+      OP(2) = transcode_memory_rtx (OP(2), HL, insn);
+      prev = prev_nonnote_nondebug_insn (prev);
+    }
+  else if (rtx_equal_p (OP(0), OP(2)))
+    {
+      OP(1) = transcode_memory_rtx (OP(1), DE, insn);
+      prev = next_nonnote_nondebug_insn (prev);
+      OP(0) =
+      OP(2) = transcode_memory_rtx (OP(2), HL, insn);
+      prev = prev_nonnote_nondebug_insn (prev);
+    }
+  else
+    {
+      OP(0) = transcode_memory_rtx (OP(0), BC, insn);
+      OP(1) = transcode_memory_rtx (OP(1), DE, insn);
+      prev = next_nonnote_nondebug_insn (prev);
+      OP(2) = transcode_memory_rtx (OP(2), HL, insn);
+    }
+
+  MAYBE_OK (insn);
+
+  prev = prev_nonnote_nondebug_insn (insn);
+  if (recog_data.constraints[1][0] == '%'
+      && is_virtual_register (OP (1))
+      && ! is_virtual_register (OP (2))
+      && ! CONSTANT_P (OP (2)))
+    {
+      rtx tmp = OP (1);
+      OP (1) = OP (2);
+      OP (2) = tmp;
+    }
+
+  /* Make a note of wether (H)L is being used.  It matters
+     because if OP(2) alsoneeds reloading, then we must take
+     care not to corrupt HL.  */
+  hl_used = reg_mentioned_p (L, OP (0)) || reg_mentioned_p (L, OP (1));
+
+  OP(0) = move_from_acc (OP (0), insn);
+  OP(1) = move_to_acc (1, insn);
+
+  MAYBE_OK (insn);
+
+  /* We have to copy op2 to HL, but that involves AX, which
+     already has a live value.  Emit it before those insns.  */
+
+  if (prev)
+    first = next_nonnote_nondebug_insn (prev);
+  else
+    for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
+      ;
+
+  OP (2) = hl_used ? move_to_de (2, first) : move_to_hl (2, first);
+  
+  MAYBE_OK (insn);
+  
+  FAILED;
+}
+
+/* Devirtualize an insn of the form (SET () (unop (op))).  */
+
+static void
+rl78_alloc_physical_registers_ro1 (rtx insn)
+{
+  /* (void) op[0] */
+  OP(0) = transcode_memory_rtx (OP(0), BC, insn);
+
+  MAYBE_OK (insn);
+
+  OP(0) = move_to_acc (0, insn);
+
+  MAYBE_OK (insn);
+
+  FAILED;
+}
+
+/* Devirtualize a compare insn.  */
+static void
+rl78_alloc_physical_registers_cmp (rtx insn)
+{
+  /* op[1] cmp_op[0] op[2] */
+  rtx prev = prev_nonnote_nondebug_insn (insn);
+  rtx first;
+
+  OP(1) = transcode_memory_rtx (OP(1), DE, insn);
+  OP(2) = transcode_memory_rtx (OP(2), HL, insn);
+
+  MAYBE_OK (insn);
+
+  OP(1) = move_to_acc (1, insn);
+
+  MAYBE_OK (insn);
+
+  /* We have to copy op2 to HL, but that involves the acc, which
+     already has a live value.  Emit it before those insns.  */
+
+  if (prev)
+    first = next_nonnote_nondebug_insn (prev);
+  else
+    for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
+      ;
+  OP(2) = move_to_hl (2, first);
+
+  MAYBE_OK (insn);
+
+  FAILED;
+}
+
+/* Like op2, but AX = A op X.  */
+static void
+rl78_alloc_physical_registers_umul (rtx insn)
+{
+  /* op[0] = op[1] func op[2] */
+  rtx prev = prev_nonnote_nondebug_insn (insn);
+  rtx first;
+
+  OP(0) = transcode_memory_rtx (OP(0), BC, insn);
+  OP(1) = transcode_memory_rtx (OP(1), DE, insn);
+  OP(2) = transcode_memory_rtx (OP(2), HL, insn);
+
+  MAYBE_OK (insn);
+
+  if (recog_data.constraints[1][0] == '%'
+      && is_virtual_register (OP(1))
+      && !is_virtual_register (OP(2))
+      && !CONSTANT_P (OP(2)))
+    {
+      rtx tmp = OP(1);
+      OP(1) = OP(2);
+      OP(2) = tmp;
+    }
+
+  OP(0) = move_from_acc (OP(0), insn);
+  OP(1) = move_to_acc (1, insn);
+
+  MAYBE_OK (insn);
+
+  /* We have to copy op2 to X, but that involves the acc, which
+     already has a live value.  Emit it before those insns.  */
+
+  if (prev)
+    first = next_nonnote_nondebug_insn (prev);
+  else
+    for (first = insn; prev_nonnote_nondebug_insn (first); first = prev_nonnote_nondebug_insn (first))
+      ;
+  OP(2) = move_to_x (2, first);
+
+  MAYBE_OK (insn);
+
+  FAILED;
+}
+
+/* Scan all insns and devirtualize them.  */
+static void
+rl78_alloc_physical_registers (void)
+{
+  /* During most of the compile, gcc is dealing with virtual
+     registers.  At this point, we need to assign physical registers
+     to the vitual ones, and copy in/out as needed.  */
+
+  rtx insn, curr;
+  enum attr_valloc valloc_method;
+
+  for (insn = get_insns (); insn; insn = curr)
+    {
+      int i;
+
+      curr = next_nonnote_nondebug_insn (insn);
+
+      if (INSN_P (insn)
+	  && (GET_CODE (PATTERN (insn)) == SET
+	      || GET_CODE (PATTERN (insn)) == CALL)
+	  && INSN_CODE (insn) == -1)
+	{
+	  if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS)
+	    continue;
+	  i = recog (PATTERN (insn), insn, 0);
+	  if (i == -1)
+	    {
+	      debug_rtx (insn);
+	      gcc_unreachable ();
+	    }
+	  INSN_CODE (insn) = i;
+	}
+    }
+
+  cfun->machine->virt_insns_ok = 0;
+  cfun->machine->real_insns_ok = 1;
+
+  for (insn = get_insns (); insn; insn = curr)
+    {
+      curr = insn ? next_nonnote_nondebug_insn (insn) : NULL;
+
+      if (!INSN_P (insn))
+	continue;
+      if (GET_CODE (PATTERN (insn)) != SET
+	  && GET_CODE (PATTERN (insn)) != CALL)
+	  continue;
+
+      if (GET_CODE (SET_SRC (PATTERN (insn))) == ASM_OPERANDS)
+	continue;
+
+      valloc_method = get_attr_valloc (insn);
+
+      PATTERN (insn)= copy_rtx_if_shared (PATTERN (insn));
+
+      if (insn_ok_now (insn))
+	continue;
+
+      INSN_CODE (insn) = -1;
+
+      if (RTX_FRAME_RELATED_P (insn))
+	virt_insn_was_frame = 1;
+      else
+	virt_insn_was_frame = 0;
+
+      switch (valloc_method)
+	{
+	case VALLOC_OP1:
+	  rl78_alloc_physical_registers_op1 (insn);
+	  break;
+	case VALLOC_OP2:
+	  rl78_alloc_physical_registers_op2 (insn);
+	  break;
+	case VALLOC_RO1:
+	  rl78_alloc_physical_registers_ro1 (insn);
+	  break;
+	case VALLOC_CMP:
+	  rl78_alloc_physical_registers_cmp (insn);
+	  break;
+	case VALLOC_UMUL:
+	  rl78_alloc_physical_registers_umul (insn);
+	  break;
+	case VALLOC_MACAX:
+	  /* Macro that clobbers AX */
+	  break;
+	}
+    }
+#if DEBUG_ALLOC
+  fprintf (stderr, "\033[0m");
+#endif
+}
+
+/* Add REG_DEAD notes using DEAD[reg] for rtx S which is part of INSN.
+   This function scans for uses of registers; the last use (i.e. first
+   encounter when scanning backwards) triggers a REG_DEAD note if the
+   reg was previously in DEAD[].  */
+static void
+rl78_note_reg_uses (char *dead, rtx s, rtx insn)
+{
+  const char *fmt;
+  int i, r;
+  enum rtx_code code;
+
+  if (!s)
+    return;
+
+  code = GET_CODE (s);
+
+  switch (code)
+    {
+      /* Compare registers by number.  */
+    case REG:
+      r = REGNO (s);
+      if (dump_file)
+	{
+	  fprintf (dump_file, "note use reg %d size %d on insn %d\n",
+		   r, GET_MODE_SIZE (GET_MODE (s)), INSN_UID (insn));
+	  print_rtl_single (dump_file, s);
+	}
+      if (dead [r])
+	add_reg_note (insn, REG_DEAD, gen_rtx_REG (GET_MODE (s), r));
+      for (i = 0; i < GET_MODE_SIZE (GET_MODE (s)); i ++)
+	dead [r + i] = 0;
+      return;
+
+      /* These codes have no constituent expressions
+	 and are unique.  */
+    case SCRATCH:
+    case CC0:
+    case PC:
+      return;
+
+    case CONST_INT:
+    case CONST_VECTOR:
+    case CONST_DOUBLE:
+    case CONST_FIXED:
+      /* These are kept unique for a given value.  */
+      return;
+
+    default:
+      break;
+    }
+
+  fmt = GET_RTX_FORMAT (code);
+
+  for (i = GET_RTX_LENGTH (code) - 1; i >= 0; i--)
+    {
+      if (fmt[i] == 'E')
+	{
+	  int j;
+	  for (j = XVECLEN (s, i) - 1; j >= 0; j--)
+	    rl78_note_reg_uses (dead, XVECEXP (s, i, j), insn);
+	}
+      else if (fmt[i] == 'e')
+	rl78_note_reg_uses (dead, XEXP (s, i), insn);
+    }
+}
+
+/* Like the previous function, but scan for SETs instead.  */
+static void
+rl78_note_reg_set (char *dead, rtx d, rtx insn)
+{
+  int r, i;
+
+  if (GET_CODE (d) != REG)
+    return;
+
+  r = REGNO (d);
+  if (dead [r])
+    add_reg_note (insn, REG_UNUSED, gen_rtx_REG (GET_MODE (d), r));
+  if (dump_file)
+    fprintf (dump_file, "note set reg %d size %d\n", r, GET_MODE_SIZE (GET_MODE (d)));
+  for (i = 0; i < GET_MODE_SIZE (GET_MODE (d)); i ++)
+    dead [r + i] = 1;
+}
+
+/* This is a rather crude register death pass.  Death status is reset
+   at every jump or call insn.  */
+static void
+rl78_calculate_death_notes (void)
+{
+  char dead[FIRST_PSEUDO_REGISTER];
+  rtx insn, p, s, d;
+  int i;
+
+  memset (dead, 0, sizeof (dead));
+
+  for (insn = get_last_insn ();
+       insn;
+       insn = prev_nonnote_nondebug_insn (insn))
+    {
+      if (dump_file)
+	{
+	  fprintf (dump_file, "\n--------------------------------------------------");
+	  fprintf (dump_file, "\nDead:");
+	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
+	    if (dead[i])
+	      fprintf(dump_file, " %s", reg_names[i]);
+	  fprintf (dump_file, "\n");
+	  print_rtl_single (dump_file, insn);
+	}
+
+      switch (GET_CODE (insn))
+	{
+	case INSN:
+	  p = PATTERN (insn);
+	  switch (GET_CODE (p))
+	    {
+	    case SET:
+	      s = SET_SRC (p);
+	      d = SET_DEST (p);
+	      rl78_note_reg_set (dead, d, insn);
+	      rl78_note_reg_uses (dead, s, insn);
+	      break;
+
+	    case USE:
+	      rl78_note_reg_uses (dead, p, insn);
+	      break;
+
+	    default:
+	      break;
+	    }
+	  break;
+
+	case JUMP_INSN:
+	  if (INSN_CODE (insn) == CODE_FOR_simple_return)
+	    {
+	      memset (dead, 1, sizeof (dead));
+	      /* We expect a USE just prior to this, which will mark
+		 the actual return registers.  The USE will have a
+		 death note, but we aren't going to be modifying it
+		 after this pass.  */
+	      break;
+	    }
+	case CALL_INSN:
+	  memset (dead, 0, sizeof (dead));
+	  break;
+
+	default:
+	  break;
+	}
+      if (dump_file)
+	print_rtl_single (dump_file, insn);
+    }
+}
+
+/* Helper function to reset the origins in RP and the age in AGE for
+   all registers.  */
+static void
+reset_origins (int *rp, int *age)
+{
+  int i;
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      rp[i] = i;
+      age[i] = 0;
+    }
+}
+
+/* The idea behind this optimization is to look for cases where we
+   move data from A to B to C, and instead move from A to B, and A to
+   C.  If B is a virtual register or memory, this is a big win on its
+   own.  If B turns out to be unneeded after this, it's a bigger win.
+   For each register, we try to determine where it's value originally
+   came from, if it's propogated purely through moves (and not
+   computes).  The ORIGINS[] array has the regno for the "origin" of
+   the value in the [regno] it's indexed by.  */
+static void
+rl78_propogate_register_origins (void)
+{
+  int origins[FIRST_PSEUDO_REGISTER];
+  int age[FIRST_PSEUDO_REGISTER];
+  int i;
+  rtx insn, ninsn = NULL_RTX;
+  rtx pat;
+
+  reset_origins (origins, age);
+
+  for (insn = get_insns (); insn; insn = ninsn)
+    {
+      ninsn = next_nonnote_nondebug_insn (insn);
+
+      if (dump_file)
+	{
+	  fprintf (dump_file, "\n");
+	  fprintf (dump_file, "Origins:");
+	  for (i = 0; i < FIRST_PSEUDO_REGISTER; i ++)
+	    if (origins[i] != i)
+	      fprintf (dump_file, " r%d=r%d", i, origins[i]);
+	  fprintf (dump_file, "\n");
+	  print_rtl_single (dump_file, insn);
+	}
+
+      switch (GET_CODE (insn))
+	{
+	case CODE_LABEL:
+	case BARRIER:
+	case CALL_INSN:
+	case JUMP_INSN:
+	  reset_origins (origins, age);
+	  break;
+
+	default:
+	  break;
+
+	case INSN:
+	  pat = PATTERN (insn);
+
+	  if (GET_CODE (pat) == PARALLEL)
+	    {
+	      rtx clobber = XVECEXP (pat, 0, 1);
+	      pat = XVECEXP (pat, 0, 0);
+	      if (GET_CODE (clobber) == CLOBBER)
+		{
+		  int cr = REGNO (XEXP (clobber, 0));
+		  int mb = GET_MODE_SIZE (GET_MODE (XEXP (clobber, 0)));
+		  if (dump_file)
+		    fprintf (dump_file, "reset origins of %d regs at %d\n", mb, cr);
+		  for (i = 0; i < mb; i++)
+		    {
+		      origins[cr + i] = cr + i;
+		      age[cr + i] = 0;
+		    }
+		}
+	      else
+		break;
+	    }
+
+	  if (GET_CODE (pat) == SET)
+	    {
+	      rtx src = SET_SRC (pat);
+	      rtx dest = SET_DEST (pat);
+	      int mb = GET_MODE_SIZE (GET_MODE (dest));
+
+	      if (GET_CODE (dest) == REG)
+		{
+		  int dr = REGNO (dest);
+
+		  if (GET_CODE (src) == REG)
+		    {
+		      int sr = REGNO (src);
+		      int same = 1;
+		      int best_age, best_reg;
+
+		      /* See if the copy is not needed.  */
+		      for (i = 0; i < mb; i ++)
+			if (origins[dr + i] != origins[sr + i])
+			  same = 0;
+		      if (same)
+			{
+			  if (dump_file)
+			    fprintf (dump_file, "deleting because dest already has correct value\n");
+			  delete_insn (insn);
+			  break;
+			}
+
+		      if (dr < 8 || sr >= 8)
+			{
+			  int ar;
+
+			  best_age = -1;
+			  best_reg = -1;
+			  /* See if the copy can be made from another
+			     bank 0 register instead, instead of the
+			     virtual src register.  */
+			  for (ar = 0; ar < 8; ar += mb)
+			    {
+			      same = 1;
+			      for (i = 0; i < mb; i ++)
+				if (origins[ar + i] != origins[sr + i])
+				  same = 0;
+
+			      /* The chip has some reg-reg move limitations.  */
+			      if (mb == 1 && dr > 3)
+				same = 0;
+
+			      if (same)
+				{
+				  if (best_age == -1 || best_age > age[sr + i])
+				    {
+				      best_age = age[sr + i];
+				      best_reg = sr;
+				    }
+				}
+			    }
+
+			  if (best_reg != -1)
+			    {
+			      /* FIXME: copy debug info too.  */
+			      SET_SRC (pat) = gen_rtx_REG (GET_MODE (src), best_reg);
+			      sr = best_reg;
+			    }
+			}
+
+		      for (i = 0; i < mb; i++)
+			{
+			  origins[dr + i] = origins[sr + i];
+			  age[dr + i] = age[sr + i] + 1;
+			}
+		    }
+		  else
+		    {
+		      /* The destination is computed, its origin is itself.  */
+		      if (dump_file)
+			fprintf (dump_file, "resetting origin of r%d for %d byte%s\n",
+				 dr, mb, mb == 1 ? "" : "s");
+		      for (i = 0; i < mb; i ++)
+			{
+			  origins[dr + i] = dr + i;
+			  age[dr + i] = 0;
+			}
+		    }
+
+		  /* Any registers marked with that reg as an origin are reset.  */
+		  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+		    if (origins[i] >= dr && origins[i] < dr + mb)
+		      {
+			origins[i] = i;
+			age[i] = 0;
+		      }
+		}
+
+	      /* Special case - our ADDSI3 macro uses AX */
+	      if (get_attr_valloc (insn) == VALLOC_MACAX)
+		{
+		  if (dump_file)
+		    fprintf (dump_file, "Resetting origin of AX for macro.\n");
+		  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+		    if (i <= 1 || origins[i] <= 1)
+		      {
+			origins[i] = i;
+			age[i] = 0;
+		      }
+		}
+
+	      if (GET_CODE (src) == ASHIFT
+		  || GET_CODE (src) == ASHIFTRT
+		  || GET_CODE (src) == LSHIFTRT)
+		{
+		  rtx count = XEXP (src, 1);
+		  if (GET_CODE (count) == REG)
+		    {
+		      /* Special case - our pattern clobbers the count register.  */
+		      int r = REGNO (count);
+		      if (dump_file)
+			fprintf (dump_file, "Resetting origin of r%d for shift.\n", r);
+		      for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+			if (i == r || origins[i] == r)
+			  {
+			    origins[i] = i;
+			    age[i] = 0;
+			  }
+		    }
+		}
+	    }
+	}
+    }
+}
+
+/* Remove any SETs where the destination is unneeded.  */
+static void
+rl78_remove_unused_sets (void)
+{
+  rtx insn, ninsn = NULL_RTX;
+  rtx dest;
+
+  for (insn = get_insns (); insn; insn = ninsn)
+    {
+      ninsn = next_nonnote_nondebug_insn (insn);
+
+      if ((insn = single_set (insn)) == NULL_RTX)
+	continue;
+
+      dest = SET_DEST (insn);
+
+      if (REGNO (dest) > 23)
+	continue;
+
+      if (find_regno_note (insn, REG_UNUSED, REGNO (dest)))
+	delete_insn (insn);
+    }
+}
+
+#undef  xTARGET_MACHINE_DEPENDENT_REORG
+#define xTARGET_MACHINE_DEPENDENT_REORG  rl78_reorg
+
+/* This is the top of the devritualization pass.  */
+static void
+rl78_reorg (void)
+{
+  rl78_alloc_physical_registers ();
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "\n================DEVIRT:=AFTER=ALLOC=PHYSICAL=REGISTERS================\n");
+      print_rtl_with_bb (dump_file, get_insns ());
+    }
+
+  rl78_propogate_register_origins ();
+  rl78_calculate_death_notes ();
+
+  if (dump_file)
+    {
+      fprintf (dump_file, "\n================DEVIRT:=AFTER=PROPOGATION=============================\n");
+      print_rtl_with_bb (dump_file, get_insns ());
+      fprintf (dump_file, "\n======================================================================\n");
+    }
+
+  rl78_remove_unused_sets ();
+
+  /* The code after devirtualizing has changed so much that at this point
+     we might as well just rescan everything.  Note that
+     df_rescan_all_insns is not going to help here because it does not
+     touch the artificial uses and defs.  */
+  df_finish_pass (true);
+  if (optimize > 1)
+    df_live_add_problem ();
+  df_scan_alloc (NULL);
+  df_scan_blocks ();
+
+  if (optimize)
+    df_analyze ();
+}
+
+#undef TARGET_RETURN_IN_MEMORY
+#define TARGET_RETURN_IN_MEMORY rl78_return_in_memory
+
+static bool
+rl78_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED)
+{
+  const HOST_WIDE_INT size = int_size_in_bytes (type);
+  return (size == -1 || size > 8);
+}
+
+
+struct gcc_target targetm = TARGET_INITIALIZER;
+
+#include "gt-rl78.h"
Index: gcc/config/rl78/rl78-virt.md
===================================================================
--- gcc/config/rl78/rl78-virt.md	(revision 0)
+++ gcc/config/rl78/rl78-virt.md	(revision 0)
@@ -0,0 +1,259 @@
+;;  Machine Description for Renesas RL78 processors
+;;  Copyright (C) 2011 Free Software Foundation, Inc.
+;;  Contributed by Red Hat.
+
+;; This file is part of GCC.
+
+;; GCC is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 3, or (at your option)
+;; any later version.
+
+;; GCC is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
+
+;; In this MD file, we define those insn patterns that involve
+;; registers, where such registers are virtual until allocated to a
+;; physical register.  All of these insns need to be conditional on
+;; rl78_virt_insns_ok () being true.
+
+;; This tells the physical register allocator what method to use to
+;; allocate registers.  Basically, this defines the template of the
+;; instruction - op1 is of the form "a = op(b)", op2 is "a = b op c"
+;; etc.
+
+(define_attr "valloc" "op1,op2,ro1,cmp,umul,macax"
+  (const_string "op2"))
+
+;;---------- Moving ------------------------
+
+(define_insn "movqi_virt"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=vY,v,Wfr")
+	(match_operand    1 "general_operand" "vInt8JY,Wfr,vInt8J"))]
+  "rl78_virt_insns_ok ()"
+  "v.mov %0, %1"
+  [(set_attr "valloc" "op1")]
+)
+
+(define_insn "movhi_virt"
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=vYS,v,Wfr")
+	(match_operand:HI 1 "general_operand" "viYS,Wfr,v"))]
+  "rl78_virt_insns_ok ()"
+  "v.movw %0, %1"
+  [(set_attr "valloc" "op1")]
+)
+
+;;---------- Conversions ------------------------
+
+(define_insn "zero_extendqihi2_virt"
+  [(set (match_operand:HI                 0 "rl78_nonfar_nonimm_operand" "=vm")
+	(zero_extend:HI (match_operand:QI 1 "general_operand" "vim")))]
+  "rl78_virt_insns_ok ()"
+  "v.zero_extend\t%0, %1"
+  [(set_attr "valloc" "op1")]
+  )
+
+(define_insn "extendqihi2_virt"
+  [(set (match_operand:HI                 0 "rl78_nonfar_nonimm_operand" "=vm")
+	(sign_extend:HI (match_operand:QI 1 "general_operand" "vim")))]
+  "rl78_virt_insns_ok ()"
+  "v.sign_extend\t%0, %1"
+  [(set_attr "valloc" "op1")]
+  )
+
+;;---------- Arithmetic ------------------------
+
+(define_insn "add<mode>3_virt"
+  [(set (match_operand:QHI           0 "rl78_nonfar_nonimm_operand" "=vY,S")
+	(plus:QHI (match_operand:QHI 1 "rl78_nonfar_operand" "viY,0")
+		  (match_operand:QHI 2 "general_operand" "vim,i")))
+   ]
+  "rl78_virt_insns_ok ()"
+  "v.add\t%0, %1, %2"
+)
+
+(define_insn "sub<mode>3_virt"
+  [(set (match_operand:QHI            0 "rl78_nonfar_nonimm_operand" "=vm,S")
+	(minus:QHI (match_operand:QHI 1 "rl78_nonfar_operand" "vim,0")
+		   (match_operand:QHI 2 "general_operand" "vim,i")))
+   ]
+  "rl78_virt_insns_ok ()"
+  "v.sub\t%0, %1, %2"
+)
+
+(define_insn "umulhi3_shift_virt"
+  [(set (match_operand:HI 0 "register_operand" "=vm")
+        (mult:HI (match_operand:HI 1 "rl78_nonfar_operand" "%vim")
+                 (match_operand:HI 2 "rl78_24_operand" "Ni")))]
+  "rl78_virt_insns_ok ()"
+  "v.mulu\t%0, %1, %2"
+  [(set_attr "valloc" "umul")]
+)
+
+(define_insn "umulqihi3_virt"
+  [(set (match_operand:HI 0 "register_operand" "=vm")
+        (mult:HI (zero_extend:HI (match_operand:QI 1 "rl78_nonfar_operand" "%vim"))
+                 (zero_extend:HI (match_operand:QI 2 "general_operand" "vim"))))]
+  "rl78_virt_insns_ok ()"
+  "v.mulu\t%0, %2"
+  [(set_attr "valloc" "umul")]
+)
+
+(define_insn "andqi3_virt"
+  [(set (match_operand:QI         0 "rl78_nonfar_nonimm_operand" "=vm")
+	(and:QI (match_operand:QI 1 "rl78_nonfar_operand" "vim")
+		(match_operand:QI 2 "general_operand" "vim")))
+   ]
+  "rl78_virt_insns_ok ()"
+  "v.and\t%0, %1, %2"
+)
+
+(define_insn "iorqi3_virt"
+  [(set (match_operand:QI         0 "rl78_nonfar_nonimm_operand" "=vm")
+	(ior:QI (match_operand:QI 1 "rl78_nonfar_operand" "vim")
+		(match_operand:QI 2 "general_operand" "vim")))
+   ]
+  "rl78_virt_insns_ok ()"
+  "v.or\t%0, %1, %2"
+)
+
+(define_insn "xor3_virt"
+  [(set (match_operand:QI         0 "rl78_nonfar_nonimm_operand" "=v,vm,m")
+	(xor:QI (match_operand:QI 1 "rl78_nonfar_operand" "%0,vm,vm")
+		(match_operand    2 "general_operand" "i,vm,vim")))
+   ]
+  "rl78_virt_insns_ok ()"
+  "v.xor\t%0, %1, %2"
+)
+
+;;---------- Shifts ------------------------
+
+(define_insn "ashl<mode>3_virt"
+  [(set (match_operand:QHI             0 "rl78_nonfar_nonimm_operand" "=vm")
+	(ashift:QHI (match_operand:QHI 1 "rl78_nonfar_operand" "vim")
+		    (match_operand:QI  2 "general_operand" "vim")))
+   ]
+  "rl78_virt_insns_ok ()"
+  "v.shl\t%0, %1, %2"
+)
+
+(define_insn "ashr<mode>3_virt"
+  [(set (match_operand:QHI               0 "rl78_nonfar_nonimm_operand" "=vm")
+	(ashiftrt:QHI (match_operand:QHI 1 "rl78_nonfar_operand" "vim")
+		      (match_operand:QI  2 "general_operand" "vim")))
+   ]
+  "rl78_virt_insns_ok ()"
+  "v.sar\t%0, %1, %2"
+)
+
+(define_insn "lshr<mode>3_virt"
+  [(set (match_operand:QHI               0 "rl78_nonfar_nonimm_operand" "=vm")
+	(lshiftrt:QHI (match_operand:QHI 1 "rl78_nonfar_operand" "vim")
+		      (match_operand:QI  2 "general_operand" "vim")))
+   ]
+  "rl78_virt_insns_ok ()"
+  "v.shr\t%0, %1, %2"
+)
+
+;; really a macro
+(define_insn "ashrsi3_virt"
+  [(set (match_operand:SI               0 "register_operand" "=v,v,v")
+	(ashiftrt:SI (match_operand:SI  1 "register_operand" "0,v,0")
+		      (match_operand:SI 2 "immediate_operand" "M,K,i")))
+   ]
+  ""
+  "@
+   ; ashrsi %0, 0
+   movw\tax,%H1\;sarw\tax,1\;movw\t%H0,ax\;mov\ta,%Q1\;rorc\ta,1\;mov\t%Q0,a\;mov\ta,%q1\;rorc\ta,1\;mov\t%q0,a
+   mov\tb,%2\;1:\;movw\tax,%H1\;sarw\tax,1\;movw\t%H0,ax\;mov\ta,%Q1\;rorc\ta,1\;mov\t%Q0,a\;mov\ta,%q1\;rorc\ta,1\;mov\t%q0,a\;dec\tb\;bnz $1b"
+  [(set_attr "valloc" "macax")]
+)
+
+;;---------- Branching ------------------------
+
+(define_insn "indirect_jump_virt"
+  [(set (pc)
+	(match_operand:HI 0 "nonimmediate_operand" "vm"))]
+  "rl78_virt_insns_ok ()"
+  "v.br\t%0"
+  [(set_attr "valloc" "ro1")]
+)
+
+(define_insn "call_virt"
+  [(call (match_operand:HI 0 "memory_operand" "Wab,Wcv")
+	 (match_operand 1 "" ""))]
+  "rl78_virt_insns_ok ()"
+  "v.call\t%0"
+  [(set_attr "valloc" "ro1")]
+  )
+
+(define_insn "call_value_virt"
+  [(set (match_operand 0 "register_operand" "=v,v")
+	(call (match_operand:HI 1 "memory_operand" "Wab,Wcv")
+	      (match_operand 2 "" "")))]
+  "rl78_virt_insns_ok ()"
+  "v.call\t%1"
+  [(set_attr "valloc" "op1")]
+  )
+
+(define_insn "cbranchqi4_virt"
+  [(set (pc) (if_then_else
+	      (match_operator 0 "rl78_cmp_operator_real"
+			      [(match_operand:QI 1 "general_operand" "vim")
+			       (match_operand:QI 2 "general_operand" "vim")])
+              (label_ref (match_operand 3 "" ""))
+	      (pc)))]
+  "rl78_virt_insns_ok ()"
+  "v.cmp\t%1, %2\\n\tv.b%c0\t%3"
+  [(set_attr "valloc" "cmp")]
+  )
+
+(define_insn "cbranchhi4_virt"
+  [(set (pc) (if_then_else
+	      (match_operator 0 "rl78_cmp_operator_real"
+			      [(match_operand:HI 1 "general_operand" "vim")
+			       (match_operand:HI 2 "general_operand" "vim")])
+              (label_ref (match_operand 3 "" ""))
+	      (pc)))]
+  "rl78_virt_insns_ok ()"
+  "v.cmpw\t%1, %2\\n\tv.b%c0\t%3"
+  [(set_attr "valloc" "cmp")]
+  )
+
+;;---------- Peepholes ------------------------
+
+(define_peephole2
+  [(set (match_operand:QI 0 "" "")
+	(match_operand:QI 1 "" ""))
+   (set (match_operand:QI 2 "" "")
+	(match_operand:QI 3 "" ""))]
+  "rl78_peep_movhi_p (operands)"
+  [(set (match_dup 4)
+	(match_dup 5))]
+  "rl78_setup_peep_movhi (operands);"
+  )
+
+(define_peephole2
+  [(set (reg:QI A_REG)
+	(match_operand:QI 1 "" ""))
+   (set (match_operand:QI 0 "" "")
+	(reg:QI A_REG))
+   (set (reg:QI A_REG)
+	(match_operand:QI 3 "" ""))
+   (set (match_operand:QI 2 "" "")
+	(reg:QI A_REG))
+   ]
+  "rl78_peep_movhi_p (operands)"
+  [(set (reg:HI AX_REG)
+	(match_dup 5))
+   (set (match_dup 4)
+	(reg:HI AX_REG))
+   ]
+  "rl78_setup_peep_movhi (operands);"
+  )
Index: gcc/config/rl78/t-rl78
===================================================================
--- gcc/config/rl78/t-rl78	(revision 0)
+++ gcc/config/rl78/t-rl78	(revision 0)
@@ -0,0 +1,22 @@
+# Makefile fragment for building GCC for the Renesas RL78 target.
+# Copyright (C) 2011 Free Software Foundation, Inc.
+# Contributed by Red Hat.
+#
+# This file is part of GCC.
+#
+# GCC is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License as published
+# by the Free Software Foundation; either version 3, or (at your
+# option) any later version.
+#
+# GCC is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.   See
+# the GNU General Public License for more details.
+#
+# You should have received a copy of the  GNU General Public
+# License along with GCC; see the file COPYING3.  If not see
+# <http://www.gnu.org/licenses/>.
+
+rl78-c.o: $(srcdir)/config/rl78/rl78-c.c $(RTL_H) $(TREE_H) $(CONFIG_H) $(TM_H)
+	$(COMPILER) -c $(ALL_COMPILERFLAGS) $(ALL_CPPFLAGS) $(INCLUDES) $<


Index: backends.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/backends.html,v
retrieving revision 1.41
diff -p -U5 -r1.41  backends.html
--- backends.html	15 Jul 2011 09:48:14 -0000	1.41
+++ backends.html	4 Nov 2011 23:52:42 -0000
@@ -90,10 +90,11 @@ mips     |     Q   CB   qr p   bda  s
 mmix     | HM  Q   C    q  p   b a e 
 mn10300  | ??             c  g      s
 ms1      |   S   F  B      p g bd
 pa       |   ? Q   CBD  qr    m da e 
 pdp11    |    L   IC    qrcp       e 
+rl78     |    L  F     l   p gmb    s
 rs6000   |     Q   C    qr      da   
 s390     |   ? Q        qr p g bda e 
 sh       |     Q   CB   qr      da   
 sparc    |     Q   CB   qr p    da   
 spu      |   ? Q  *C       p g bd    
Index: index.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/index.html,v
retrieving revision 1.819
diff -p -U5 -r1.819  index.html
--- index.html	28 Oct 2011 21:47:30 -0000	1.819
+++ index.html	4 Nov 2011 23:52:42 -0000
@@ -51,10 +51,15 @@ mission statement</a>.</p>
 
 <h2 style="margin-top:0pt;" id="news">News</h2>
 
 <dl class="news">
 
+<dt><span>TI C6X processor support</span>
+    <span class="date">[2011-11-04]</span></dt>
+<dd>A port for the Renesas RL78 family of processors has been contributed by
+Red Hat.</dd>
+
 <dt><span><a href="gcc-4.6/">GCC 4.6.2</a> released</span>
     <span class="date">[2011-10-26]</span></dt>
 <dd></dd>
 
 <dt><span>OpenMP v3.1</span>
Index: readings.html
===================================================================
RCS file: /cvs/gcc/wwwdocs/htdocs/readings.html,v
retrieving revision 1.215
diff -p -U5 -r1.215  readings.html
--- readings.html	15 Jul 2011 09:48:15 -0000	1.215
+++ readings.html	4 Nov 2011 23:52:42 -0000
@@ -237,10 +237,15 @@ Intel&reg;64 and IA-32 Architectures Sof
   <br /><a href="http://publib16.boulder.ibm.com/pseries/en_US/infocenter/base/43_docs/aixassem/alangref/toc.htm";>AIX V4.3 Assembler Language Ref.</a>
   <br /><a href="http://publibn.boulder.ibm.com/doc_link/en_US/a_doc_lib/aixassem/alangref/alangreftfrm.htm";>AIX 5L Assembler Language Ref.</a>
   <br /><a href="http://www.power.org/resources/downloads/";>Documentation and tools at power.org</a>
  </li>
  
+ <li>rl78
+  <br />Manufacturer: Renesas
+  <br /><a href="http://www.renesas.com/pr/mcu/rl78/";>Renesas RL78 Processors</a>
+ </li>
+ 
  <li>rx
   <br />Manufacturer: Renesas
   <br /><a href="http://documentation.renesas.com/eng/products/mpumcu/rej09b0460_rx610hm.pdf";>RX610 Hardware Manual</a>
  </li>
  


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