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: Renesas RL78


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're included in the patch below with separate ChangeLog entries,
since you'll need the port to trigger the bug.

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.

. (already in src)

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

libgcc

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

gcc

	* caller-save.c (setup_save_areas): Increase call_saved_regs[]
	size to avoid writing beyond the end of the array.  There are two
	loops that iterate over hard regs and potentially add to this
	array, so it must hold a max of 2x the hard regs.

	* expr.c (expand_expr_real_2): Don't try to emit a MUL-based
	expression if the target doesn't have a multiply pattern.  Fall
	back to shifts instead of using libgcc calls.

	* except.c (init_eh): Fix setjmp buffer size calculations for
	targets where pointers are not word-sized.

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


Index: libstdc++-v3/include/tr1/beta_function.tcc
===================================================================
--- libstdc++-v3/include/tr1/beta_function.tcc	(revision 180758)
+++ 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 = 65536U;
       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 180758)
+++ 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 180758)
+++ 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 180758)
+++ configure.ac	(working copy)
@@ -498,12 +498,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: configure
===================================================================
--- configure	(revision 180758)
+++ 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 180758)
+++ libgcc/config.host	(working copy)
@@ -683,12 +683,16 @@ rs6000-ibm-aix5.1.* | powerpc-ibm-aix5.1
 	tmake_file="t-fdpbit rs6000/t-ppc64-fp rs6000/t-ibm-ldouble"
 	;;
 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"
 	;;
+rl78-*-elf)
+	extra_parts="crtbegin.o crtend.o"
+	tmake_file="rl78/t-rl78"
+	;;
 rx-*-elf)
 	extra_parts="crtbegin.o crtend.o"
 	tmake_file="rx/t-rx t-fdpbit"
 	;;
 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,116 @@
+/* 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(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,103 @@
+/* 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.
+
+   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/>.  */
+
+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 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,133 @@
+/* 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:
+	movw	ax, !trampoline_chain_\n
+	movw	r14, ax
+	movw	ax, !trampoline_addr_\n
+	br	ax
+
+	.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
+___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
+
+	.global	___trampoline_uninit
+___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
\ No newline at end of file
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,44 @@
+/* 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;
+  UINT_TYPE mask = 1;
+
+  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,37 @@
+# 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
+
+FPBIT = fp-bit.c
+$(gcc_objdir)/fp-bit.c: $(gcc_srcdir)/config/fp-bit.c
+	echo '#define FLOAT'		     > $@
+	cat $(gcc_srcdir)/config/fp-bit.c   >> $@
+
+DPBIT = dp-bit.c
+$(gcc_objdir)/dp-bit.c: $(gcc_srcdir)/config/fp-bit.c
+	cat $(gcc_srcdir)/config/fp-bit.c   >> $@
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 180758)
+++ 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 180758)
+++ 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
@@ -10248,12 +10251,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::
@@ -16711,12 +16715,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/caller-save.c
===================================================================
--- gcc/caller-save.c	(revision 180758)
+++ gcc/caller-save.c	(working copy)
@@ -494,13 +494,13 @@ setup_save_areas (void)
     {
       rtx slot;
       char *saved_reg_conflicts;
       int next_k;
       struct saved_hard_reg *saved_reg2, *saved_reg3;
       int call_saved_regs_num;
-      struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER];
+      struct saved_hard_reg *call_saved_regs[FIRST_PSEUDO_REGISTER*2];
       int best_slot_num;
       int prev_save_slots_num;
       rtx prev_save_slots[FIRST_PSEUDO_REGISTER];
 
       /* Find saved hard register conflicts.  */
       saved_reg_conflicts = (char *) xmalloc (saved_regs_num * saved_regs_num);
Index: gcc/expr.c
===================================================================
--- gcc/expr.c	(revision 180758)
+++ gcc/expr.c	(working copy)
@@ -8289,12 +8289,13 @@ expand_expr_real_2 (sepops ops, rtx targ
 	}
 
       /* Attempt to return something suitable for generating an
 	 indexed address, for machines that support that.  */
 
       if (modifier == EXPAND_SUM && mode == ptr_mode
+	  && optab_handler (smul_optab, mode) != CODE_FOR_nothing
 	  && host_integerp (treeop1, 0))
 	{
 	  tree exp1 = treeop1;
 
 	  op0 = expand_expr (treeop0, subtarget, VOIDmode,
 			     EXPAND_SUM);
Index: gcc/except.c
===================================================================
--- gcc/except.c	(revision 180758)
+++ gcc/except.c	(working copy)
@@ -253,13 +253,13 @@ init_eh (void)
 	 also tend to be larger than necessary for most systems, a more
 	 optimal port will define JMP_BUF_SIZE.  */
       tmp = size_int (FIRST_PSEUDO_REGISTER + 2 - 1);
 #endif
 #else
       /* builtin_setjmp takes a pointer to 5 words.  */
-      tmp = size_int (5 * BITS_PER_WORD / POINTER_SIZE - 1);
+      tmp = size_int (5 * POINTER_SIZE / BITS_PER_WORD - 1);
 #endif
       tmp = build_index_type (tmp);
       tmp = build_array_type (ptr_type_node, tmp);
       f_jbuf = build_decl (BUILTINS_LOCATION,
 			   FIELD_DECL, get_identifier ("__jbuf"), tmp);
 #ifdef DONT_USE_BUILTIN_SETJMP
Index: gcc/config.gcc
===================================================================
--- gcc/config.gcc	(revision 180758)
+++ gcc/config.gcc	(working copy)
@@ -2243,12 +2243,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}"
 	libgcc_tm_file="${libgcc_tm_file} rx/rx-abi.h rx/rx-lib.h"
 	tmake_file="${tmake_file} rx/t-rx"
 	;;
 s390-*-linux*)
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,42 @@
+/* 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 *);
+int            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_epilog (void);
+void           rl78_expand_prolog (void);
+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);
+bool           rl78_is_legitimate_address (enum machine_mode, rtx, bool);
+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);
+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 Prolog/Epilog Instructions
+
+(define_expand "prologue"
+  [(const_int 0)]
+  ""
+  "rl78_expand_prolog (); DONE;"
+)
+
+(define_expand "epilogue"
+  [(const_int 0)]
+  ""
+  "rl78_expand_epilog (); 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,2565 @@
+/* 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/>.  */
+
+/* To Do:
+
+ * Re-enable memory-to-memory copies and fix up reload.  */
+
+#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);
+
+
+/* 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
+
+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
+{
+  int computed;
+  int need_to_push [FIRST_PSEUDO_REGISTER / 2];
+  /* arg pointer */
+  /* 4 bytes for saved PC */
+  int framesize_regs;
+  /* frame pointer */
+  int framesize_locals;
+  int framesize_outgoing;
+  /* stack pointer */
+  int framesize;
+
+  int real_insns_ok;
+  int virt_insns_ok;
+  int trampolines_used;
+};
+
+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;
+}
+
+static bool
+devirt_gate (void)
+{
+  return true;
+}
+
+static void rl78_reorg (void);
+
+static unsigned int
+devirt_pass (void)
+{
+  rl78_reorg ();
+  return 0;
+}
+
+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;
+}
+
+static 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
+};
+
+bool
+rl78_virt_insns_ok (void)
+{
+  if (cfun)
+    return cfun->machine->virt_insns_ok;
+  return true;
+}
+
+bool
+rl78_real_insns_ok (void)
+{
+  if (cfun)
+    return cfun->machine->real_insns_ok;
+  return false;
+}
+
+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);
+}
+
+int
+rl78_hard_regno_mode_ok (int regno, enum machine_mode mode)
+{
+  int s = GET_MODE_SIZE (mode);
+
+  if (s < 1)
+    return 0;
+  if (regno == 23 || regno == ES_REG || regno == CS_REG)
+    return 0;
+  if (regno == FP_REG && s == 2)
+    return 1;
+  if (regno < SP_REG)
+    {
+      if (s > 1 && (regno % 2))
+	return 0;
+      return 1;
+    }
+  if (s == CC_REGNUM)
+    return (mode == BImode);
+  if (s == register_sizes [regno])
+    return 1;
+  return 0;
+}
+
+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);
+}
+
+int
+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);
+    }
+}
+
+int
+rl78_force_nonfar_2 (rtx *operands, rtx (*gen)(rtx,rtx))
+{
+  int i, 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;
+}
+
+int
+rl78_force_nonfar_3 (rtx *operands, rtx (*gen)(rtx,rtx,rtx))
+{
+  int i, 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;
+}
+
+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;
+}
+
+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");
+}
+
+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 }
+};
+
+
+
+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:
+      /*debug_rtx(x);*/
+      return false;
+    }
+
+  return false;
+}
+
+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)))
+
+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;
+
+  /*debug_rtx(x);*/
+  return true;
+}
+
+bool
+rl78_is_legitimate_address (enum machine_mode mode, rtx x,
+			    bool strict)
+{
+  return rl78_as_legitimate_address (mode, x, strict, ADDR_SPACE_GENERIC);
+}
+
+/* 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 ();
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+void
+rl78_expand_prolog (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;
+    }
+}
+
+void
+rl78_expand_epilog (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 ());
+}
+
+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
+
+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");
+
+#if 1
+  fprintf (file, "\t; ap->fp = %d\n", rl78_initial_elimination_offset (ARG_POINTER_REGNUM, FRAME_POINTER_REGNUM));
+  fprintf (file, "\t; fp->sp = %d\n", rl78_initial_elimination_offset (FRAME_POINTER_REGNUM, STACK_POINTER_REGNUM));
+#endif
+}
+
+/* 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
+   H - top HIword of an SIword
+   h - top QIbyte of an HIword
+   b - bottom QIbyte of an HIword
+   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)
+
+   Proposed:
+
+   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)
+
+*/
+
+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')
+	error ("q/Q modifiers invalid for symbol referencs");
+
+      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')
+	error ("q/Q modifiers invalid for symbol referencs");
+
+      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)));
+      /*print_simple_rtl (file, 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
+
+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;
+}
+
+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 DEBUG_PEEP 0
+
+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;
+}
+
+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);
+	  /*debug_rtx (operands[i+4]);*/
+	  break;
+
+	case MEM:
+	  operands[i+4] = adjust_address (operands[i], HImode, 0);
+	  break;
+
+	default:
+	  break;
+	}
+    }
+}
+
+#define DEBUG_ALLOC 0
+
+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
+
+#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])
+
+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;
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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;
+}
+
+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
+}
+
+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);
+    }
+}
+
+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);
+    }
+}
+
+static void
+reset_origins (int *rp, int *age)
+{
+  int i;
+  for (i = 0; i < FIRST_PSEUDO_REGISTER; i++)
+    {
+      rp[i] = i;
+      age[i] = 0;
+    }
+}
+
+extern int flag_simple;
+
+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");
+	  /* flag_simple = 1; */
+	  print_rtl_single (dump_file, insn);
+	  /* flag_simple = 0; */
+	}
+
+      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;
+			  }
+		    }
+		}
+	    }
+	}
+    }
+}
+
+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
+
+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 Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]