OSDN Git Service

* config/v850/lib1funcs.asm, config/v850/rtems.h,
[pf3gnuchains/gcc-fork.git] / gcc / config / v850 / v850.md
index 4308e07..811f87a 100644 (file)
@@ -1,21 +1,21 @@
 ;; GCC machine description for NEC V850
-;; Copyright (C) 1996, 1997, 1998, 1999 Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2002 Free Software Foundation, Inc.
 ;; Contributed by Jeff Law (law@cygnus.com).
 
-;; This file is part of GNU CC.
+;; This file is part of GCC.
 
-;; GNU CC is free software; you can redistribute it and/or modify
+;; GCC is free software; you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
 ;; the Free Software Foundation; either version 2, or (at your option)
 ;; any later version.
 
-;; GNU CC is distributed in the hope that it will be useful,
+;; 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 GNU CC; see the file COPYING.  If not, write to
+;; along with GCC; see the file COPYING.  If not, write to
 ;; the Free Software Foundation, 59 Temple Place - Suite 330,
 ;; Boston, MA 02111-1307, USA.
 
@@ -33,7 +33,7 @@
 ;; The size of instructions in bytes.
 
 (define_attr "length" ""
-  (const_int 200))
+  (const_int 4))
 
 (define_attr "long_calls" "yes,no"
   (const (if_then_else (symbol_ref "TARGET_LONG_CALLS")
      must be done with HIGH & LO_SUM patterns.  */
   if (CONSTANT_P (operands[1])
       && GET_CODE (operands[1]) != HIGH
+      && ! TARGET_V850E
       && !special_symbolref_operand (operands[1], VOIDmode)
       && !(GET_CODE (operands[1]) == CONST_INT
           && (CONST_OK_FOR_J (INTVAL (operands[1]))
     }
 }")
 
+;; This is the same as the following pattern, except that it includes
+;; support for arbitrary 32 bit immediates.
+
+;; ??? This always loads addresses using hilo.  If the only use of this address
+;; was in a load/store, then we would get smaller code if we only loaded the
+;; upper part with hi, and then put the lower part in the load/store insn.
+
+(define_insn "*movsi_internal_v850e"
+  [(set (match_operand:SI 0 "general_operand" "=r,r,r,r,Q,r,r,m,m,r")
+       (match_operand:SI 1 "general_operand" "Jr,K,L,Q,Ir,m,R,r,I,i"))]
+  "TARGET_V850E
+   && (register_operand (operands[0], SImode)
+       || reg_or_0_operand (operands[1], SImode))"
+  "* return output_move_single (operands);"
+  [(set_attr "length" "2,4,4,2,2,4,4,4,4,6")
+   (set_attr "cc" "none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")
+   (set_attr "type" "other,other,other,load,other,load,other,other,other,other")])
+
 (define_insn "*movsi_internal"
   [(set (match_operand:SI 0 "general_operand" "=r,r,r,r,Q,r,r,m,m")
        (match_operand:SI 1 "movsi_source_operand" "Jr,K,L,Q,Ir,m,R,r,I"))]
    (set_attr "cc" "none_0hit,none_0hit")
    (set_attr "type" "mult")])
 
+;; ??? The scheduling info is probably wrong.
+
+;; ??? This instruction can also generate the 32 bit highpart, but using it
+;; may increase code size counter to the desired result.
+
+;; ??? This instructions can also give a DImode result.
+
+;; ??? There is unsigned version, but it matters only for the DImode/highpart
+;; results.
+
+(define_insn "mulsi3"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI (match_operand:SI 1 "register_operand" "%0")
+                (match_operand:SI 2 "reg_or_int9_operand" "rO")))]
+  "TARGET_V850E"
+  "mul %2,%1,%."
+  [(set_attr "length" "4")
+   (set_attr "cc" "none_0hit")
+   (set_attr "type" "mult")])
+
+;; ----------------------------------------------------------------------
+;; DIVIDE INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+;; ??? These insns do set the Z/N condition codes, except that they are based
+;; on only one of the two results, so it doesn't seem to make sense to use
+;; them.
+
+;; ??? The scheduling info is probably wrong.
+
+(define_insn "divmodsi4"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (div:SI (match_operand:SI 1 "register_operand" "0")
+               (match_operand:SI 2 "register_operand" "r")))
+   (set (match_operand:SI 3 "register_operand" "=r")
+       (mod:SI (match_dup 1)
+               (match_dup 2)))]
+  "TARGET_V850E"
+  "div %2,%0,%3"
+  [(set_attr "length" "4")
+   (set_attr "cc" "clobber")
+   (set_attr "type" "other")])
+       
+(define_insn "udivmodsi4"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (udiv:SI (match_operand:SI 1 "register_operand" "0")
+                (match_operand:SI 2 "register_operand" "r")))
+   (set (match_operand:SI 3 "register_operand" "=r")
+       (umod:SI (match_dup 1)
+                (match_dup 2)))]
+  "TARGET_V850E"
+  "divu %2,%0,%3"
+  [(set_attr "length" "4")
+   (set_attr "cc" "clobber")
+   (set_attr "type" "other")])
+       
+;; ??? There is a 2 byte instruction for generating only the quotient.
+;; However, it isn't clear how to compute the length field correctly.
+
+(define_insn "divmodhi4"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (div:HI (match_operand:HI 1 "register_operand" "0")
+               (match_operand:HI 2 "register_operand" "r")))
+   (set (match_operand:HI 3 "register_operand" "=r")
+       (mod:HI (match_dup 1)
+               (match_dup 2)))]
+  "TARGET_V850E"
+  "divh %2,%0,%3"
+  [(set_attr "length" "4")
+   (set_attr "cc" "clobber")
+   (set_attr "type" "other")])
+
+;; Half-words are sign-extended by default, so we must zero extend to a word
+;; here before doing the divide.
+
+(define_insn "udivmodhi4"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (udiv:HI (match_operand:HI 1 "register_operand" "0")
+                (match_operand:HI 2 "register_operand" "r")))
+   (set (match_operand:HI 3 "register_operand" "=r")
+       (umod:HI (match_dup 1)
+                (match_dup 2)))]
+  "TARGET_V850E"
+  "zxh %0 ; divhu %2,%0,%3"
+  [(set_attr "length" "4")
+   (set_attr "cc" "clobber")
+   (set_attr "type" "other")])
 \f
 ;; ----------------------------------------------------------------------
 ;; AND INSTRUCTIONS
   [(set_attr "length" "4")
    (set_attr "cc" "none_0hit")])
 
+;; ----------------------------------------------------------------------
+;; CONDITIONAL MOVE INSTRUCTIONS
+;; ----------------------------------------------------------------------
+
+;; Instructions using cc0 aren't allowed to have input reloads, so we must
+;; hide the fact that this instruction uses cc0.  We do so by including the
+;; compare instruction inside it.
+
+;; ??? This is very ugly.  The right way to do this is to modify cmpsi so
+;; that it doesn't emit RTL, and then modify the bcc/scc patterns so that
+;; they emit RTL for the compare instruction.  Unfortunately, this requires
+;; lots of changes that will be hard to sanitize.  So for now, cmpsi still
+;; emits RTL, and I get the compare operands here from the previous insn.
+
+(define_expand "movsicc"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (match_operator 1 "comparison_operator"
+                        [(match_dup 4) (match_dup 5)])
+        (match_operand:SI 2 "reg_or_const_operand" "rJ")
+        (match_operand:SI 3 "reg_or_const_operand" "rI")))]
+  "TARGET_V850E"
+  "
+{
+  rtx insn = get_last_insn_anywhere ();
+
+  if (   (GET_CODE (operands[2]) == CONST_INT
+       && GET_CODE (operands[3]) == CONST_INT))
+    {
+      int o2 = INTVAL (operands[2]);
+      int o3 = INTVAL (operands[3]);
+
+      if (o2 == 1 && o3 == 0)
+       FAIL;   /* setf */
+      if (o3 == 1 && o2 == 0)
+       FAIL;   /* setf */
+      if (o2 == 0 && (o3 < -16 || o3 > 15) && exact_log2 (o3) >= 0)
+       FAIL;   /* setf + shift */
+      if (o3 == 0 && (o2 < -16 || o2 > 15) && exact_log2 (o2) >=0)
+       FAIL;   /* setf + shift */
+      if (o2 != 0)
+       operands[2] = copy_to_mode_reg (SImode, operands[2]);
+      if (o3 !=0 )
+       operands[3] = copy_to_mode_reg (SImode, operands[3]);
+    }
+  else
+    {
+      if (GET_CODE (operands[2]) != REG)
+       operands[2] = copy_to_mode_reg (SImode,operands[2]);
+      if (GET_CODE (operands[3]) != REG)
+       operands[3] = copy_to_mode_reg (SImode, operands[3]);
+    }
+  if (GET_CODE (insn) == INSN
+      && GET_CODE (PATTERN (insn)) == SET
+      && SET_DEST (PATTERN (insn)) == cc0_rtx)
+    {
+      rtx src = SET_SRC (PATTERN (insn));
+
+      if (GET_CODE (src) == COMPARE)
+       {
+         operands[4] = XEXP (src, 0);
+         operands[5] = XEXP (src, 1);
+       }
+      else if (GET_CODE (src) == REG
+               || GET_CODE (src) == SUBREG)
+       {
+         operands[4] = src;
+         operands[5] = const0_rtx;
+       }
+      else
+       abort ();
+    }
+  else
+    abort ();
+}")
+
+;; ??? Clobbering the condition codes is overkill.
+
+;; ??? We sometimes emit an unnecessary compare instruction because the
+;; condition codes may have already been set by an earlier instruction,
+;; but we have no code here to avoid the compare if it is unnecessary.
+
+(define_insn "*movsicc_normal"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (match_operator 1 "comparison_operator"
+                        [(match_operand:SI 4 "register_operand" "r")
+                         (match_operand:SI 5 "reg_or_int5_operand" "rJ")])
+        (match_operand:SI 2 "reg_or_int5_operand" "rJ")
+        (match_operand:SI 3 "reg_or_0_operand" "rI")))]
+  "TARGET_V850E"
+  "cmp %5,%4 ; cmov %c1,%2,%z3,%0"
+  [(set_attr "length" "6")
+   (set_attr "cc" "clobber")])
+
+(define_insn "*movsicc_reversed"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (match_operator 1 "comparison_operator"
+                        [(match_operand:SI 4 "register_operand" "r")
+                         (match_operand:SI 5 "reg_or_int5_operand" "rJ")])
+        (match_operand:SI 2 "reg_or_0_operand" "rI")
+        (match_operand:SI 3 "reg_or_int5_operand" "rJ")))]
+  "TARGET_V850E"
+  "cmp %5,%4 ; cmov %C1,%3,%z2,%0"
+  [(set_attr "length" "6")
+   (set_attr "cc" "clobber")])
+
+(define_insn "*movsicc_tst1"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (match_operator 1 "comparison_operator"
+                        [(zero_extract:SI
+                          (match_operand:QI 2 "memory_operand" "m")
+                          (const_int 1)
+                          (match_operand 3 "const_int_operand" "n"))
+                         (const_int 0)])
+        (match_operand:SI 4 "reg_or_int5_operand" "rJ")
+        (match_operand:SI 5 "reg_or_0_operand" "rI")))]
+  "TARGET_V850E"
+  "tst1 %3,%2 ; cmov %c1,%4,%z5,%0"
+  [(set_attr "length" "8")
+   (set_attr "cc" "clobber")])
+
+(define_insn "*movsicc_tst1_reversed"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (if_then_else:SI
+        (match_operator 1 "comparison_operator"
+                        [(zero_extract:SI
+                          (match_operand:QI 2 "memory_operand" "m")
+                          (const_int 1)
+                          (match_operand 3 "const_int_operand" "n"))
+                         (const_int 0)])
+        (match_operand:SI 4 "reg_or_0_operand" "rI")
+        (match_operand:SI 5 "reg_or_int5_operand" "rJ")))]
+  "TARGET_V850E"
+  "tst1 %3,%2 ; cmov %C1,%5,%z4,%0"
+  [(set_attr "length" "8")
+   (set_attr "cc" "clobber")])
+
+;; Matching for sasf requires combining 4 instructions, so we provide a
+;; dummy pattern to match the first 3, which will always be turned into the
+;; second pattern by subsequent combining.  As above, we must include the
+;; comparison to avoid input reloads in an insn using cc0.
+
+(define_insn "*sasf_1"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (ior:SI (match_operator 1 "comparison_operator" [(cc0) (const_int 0)])
+               (ashift:SI (match_operand:SI 2 "register_operand" "")
+                          (const_int 1))))]
+  "TARGET_V850E"
+  "* abort ();")
+
+(define_insn "*sasf_2"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ior:SI
+        (match_operator 1 "comparison_operator"
+                        [(match_operand:SI 3 "register_operand" "r")
+                         (match_operand:SI 4 "reg_or_int5_operand" "rJ")])
+        (ashift:SI (match_operand:SI 2 "register_operand" "0")
+                   (const_int 1))))]
+  "TARGET_V850E"
+  "cmp %4,%3 ; sasf %c1,%0"
+  [(set_attr "length" "6")
+   (set_attr "cc" "clobber")])
+
+(define_split
+  [(set (match_operand:SI 0 "register_operand" "")
+       (if_then_else:SI
+        (match_operator 1 "comparison_operator"
+                        [(match_operand:SI 4 "register_operand" "")
+                         (match_operand:SI 5 "reg_or_int5_operand" "")])
+        (match_operand:SI 2 "const_int_operand" "")
+        (match_operand:SI 3 "const_int_operand" "")))]
+  "TARGET_V850E
+   && ((INTVAL (operands[2]) ^ INTVAL (operands[3])) == 1)
+   && ((INTVAL (operands[2]) + INTVAL (operands[3])) != 1)
+   && (GET_CODE (operands[5]) == CONST_INT
+      || REGNO (operands[0]) != REGNO (operands[5]))
+   && REGNO (operands[0]) != REGNO (operands[4])"
+  [(set (match_dup 0) (match_dup 6))
+   (set (match_dup 0)
+       (ior:SI (match_op_dup 7 [(match_dup 4) (match_dup 5)])
+               (ashift:SI (match_dup 0) (const_int 1))))]
+  "
+{
+  operands[6] = GEN_INT (INTVAL (operands[2]) >> 1);
+  if (INTVAL (operands[2]) & 0x1)
+    operands[7] = operands[1];
+  else
+    operands[7] = gen_rtx (reverse_condition (GET_CODE (operands[1])),
+                          GET_MODE (operands[1]), XEXP (operands[1], 0),
+                          XEXP (operands[1], 1));
+}")
+;; ---------------------------------------------------------------------
+;; BYTE SWAP INSTRUCTIONS
+;; ---------------------------------------------------------------------
+
+(define_expand "rotlhi3"
+  [(set (match_operand:HI 0 "register_operand" "")
+       (rotate:HI (match_operand:HI 1 "register_operand" "")
+                  (match_operand:HI 2 "const_int_operand" "")))]
+  "TARGET_V850E"
+  "
+{
+  if (INTVAL (operands[2]) != 8)
+    FAIL;
+}")
+
+(define_insn "*rotlhi3_8"
+  [(set (match_operand:HI 0 "register_operand" "=r")
+       (rotate:HI (match_operand:HI 1 "register_operand" "r")
+                  (const_int 8)))]
+  "TARGET_V850E"
+  "bsh %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "cc" "clobber")])
+
+(define_expand "rotlsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (rotate:SI (match_operand:SI 1 "register_operand" "")
+                  (match_operand:SI 2 "const_int_operand" "")))]
+  "TARGET_V850E"
+  "
+{
+  if (INTVAL (operands[2]) != 16)
+    FAIL;
+}")
+
+(define_insn "*rotlsi3_16"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (rotate:SI (match_operand:SI 1 "register_operand" "r")
+                  (const_int 16)))]
+  "TARGET_V850E"
+  "hsw %1,%0"
+  [(set_attr "length" "4")
+   (set_attr "cc" "clobber")])
 \f
 ;; ----------------------------------------------------------------------
 ;; JUMP INSTRUCTIONS
   [(set_attr "length" "2")
    (set_attr "cc" "none")])
 
+(define_insn "switch"
+  [(set (pc)
+       (plus:SI
+        (sign_extend:SI
+         (mem:HI
+          (plus:SI (ashift:SI (match_operand:SI 0 "register_operand" "r")
+                              (const_int 1))
+                   (label_ref (match_operand 1 "" "")))))
+        (label_ref (match_dup 1))))]
+  "TARGET_V850E"
+  "switch %0"
+  [(set_attr "length" "2")
+   (set_attr "cc" "none")])
+
 (define_expand "casesi"
   [(match_operand:SI 0 "register_operand" "")
    (match_operand:SI 1 "register_operand" "")
   /* Branch to the default label if out of range of the table.  */
   emit_jump_insn (gen_bgtu (operands[4]));
 
+  if (! TARGET_BIG_SWITCH && TARGET_V850E)
+    {
+      emit_jump_insn (gen_switch (reg, operands[3]));
+      DONE;
+    }
+
   /* Shift index for the table array access.  */
   emit_insn (gen_ashlsi3 (reg, reg, GEN_INT (TARGET_BIG_SWITCH ? 2 : 1)));
   /* Load the table address into a pseudo.  */
   emit_insn (gen_movsi (tableaddress,
-                       gen_rtx_LABEL_REF (VOIDmode, operands[3])));
+                       gen_rtx_LABEL_REF (Pmode, operands[3])));
   /* Add the table address to the index.  */
   emit_insn (gen_addsi3 (reg, reg, tableaddress));
   /* Load the table entry.  */
 ;; EXTEND INSTRUCTIONS
 ;; ----------------------------------------------------------------------
 
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (zero_extend:SI
+        (match_operand:HI 1 "nonimmediate_operand" "0,r,T,m")))]
+  "TARGET_V850E"
+  "@
+   zxh %0
+   andi 65535,%1,%0
+   sld.hu %1,%0
+   ld.hu %1,%0"
+  [(set_attr "length" "2,4,2,4")
+   (set_attr "cc" "none_0hit,set_znv,none_0hit,none_0hit")])
 
 (define_insn "zero_extendhisi2"
   [(set (match_operand:SI 0 "register_operand" "=r")
   [(set_attr "length" "4")
    (set_attr "cc" "set_znv")])
 
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r,r")
+       (zero_extend:SI
+        (match_operand:QI 1 "nonimmediate_operand" "0,r,T,m")))]
+  "TARGET_V850E"
+  "@
+   zxb %0
+   andi 255,%1,%0
+   sld.bu %1,%0
+   ld.bu %1,%0"
+  [(set_attr "length" "2,4,2,4")
+   (set_attr "cc" "none_0hit,set_znv,none_0hit,none_0hit")])
 
 (define_insn "zero_extendqisi2"
   [(set (match_operand:SI 0 "register_operand" "=r")
 
 ;;- sign extension instructions
 
+;; ??? The extendhisi2 pattern should not emit shifts for v850e?
+
+(define_insn "*extendhisi_insn"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (sign_extend:SI (match_operand:HI 1 "nonimmediate_operand" "0,Q,m")))]
+  "TARGET_V850E"
+  "@
+   sxh %0
+   sld.h %1,%0
+   ld.h %1,%0"
+  [(set_attr "length" "2,2,4")
+   (set_attr "cc" "none_0hit,none_0hit,none_0hit")])
 
 ;; ??? This is missing a sign extend from memory pattern to match the ld.h
 ;; instruction.
   operands[2] = gen_reg_rtx (SImode);
 }")
 
+;; ??? The extendqisi2 pattern should not emit shifts for v850e?
+
+(define_insn "*extendqisi_insn"
+  [(set (match_operand:SI 0 "register_operand" "=r,r,r")
+       (sign_extend:SI (match_operand:QI 1 "nonimmediate_operand" "0,Q,m")))]
+  "TARGET_V850E"
+  "@
+   sxb %0
+   sld.b %1,%0
+   ld.b %1,%0"
+  [(set_attr "length" "2,2,4")
+   (set_attr "cc" "none_0hit,none_0hit,none_0hit")])
 
 ;; ??? This is missing a sign extend from memory pattern to match the ld.b
 ;; instruction.
 ;; RTXs.  These RTXs will then be turned into a suitable call to a worker
 ;; function.
 
+;;
+;; Actually, convert the RTXs into a PREPARE instruction.
+;;
+(define_insn ""
+ [(match_parallel 0 "pattern_is_ok_for_prepare"
+   [(set (reg:SI 3)
+        (plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
+    (set (mem:SI (plus:SI (reg:SI 3)
+                         (match_operand:SI 2 "immediate_operand" "i")))
+        (match_operand:SI 3 "register_is_ok_for_epilogue" "r"))])]
+ "TARGET_PROLOG_FUNCTION && TARGET_V850E"
+ "* return construct_prepare_instruction (operands[0]);
+ "
+ [(set_attr "length" "4")
+  (set_attr "cc"     "none")])
 
 (define_insn ""
  [(match_parallel 0 "pattern_is_ok_for_prologue"
                                     (const_string "4")))
   (set_attr "cc"     "clobber")])
 
+;;
+;; Actually, turn the RTXs into a DISPOSE instruction.
+;;
+(define_insn ""
+ [(match_parallel 0 "pattern_is_ok_for_dispose"
+   [(return)
+    (set (reg:SI 3)
+        (plus:SI (reg:SI 3) (match_operand:SI 1 "immediate_operand" "i")))
+    (set (match_operand:SI 2 "register_is_ok_for_epilogue" "=r")
+        (mem:SI (plus:SI (reg:SI 3)
+                         (match_operand:SI 3 "immediate_operand" "i"))))])]
+ "TARGET_PROLOG_FUNCTION && TARGET_V850E"
+ "* return construct_dispose_instruction (operands[0]);
+ "
+ [(set_attr "length" "4")
+  (set_attr "cc"     "none")])
+
 ;; This pattern will match a return RTX followed by any number of pop RTXs
 ;; and possible a stack adjustment as well.  These RTXs will be turned into
 ;; a suitable call to a worker function.
   (set_attr "cc"     "clobber")])
 
 ;; Initialize an interrupt function.  Do not depend on TARGET_PROLOG_FUNCTION.
+(define_insn "callt_save_interrupt"
+  [(unspec_volatile [(const_int 0)] 2)]
+    "TARGET_V850E && !TARGET_DISABLE_CALLT"
+    ;; The CALLT instruction stores the next address of CALLT to CTPC register
+    ;; without saving its previous value.  So if the interrupt handler
+    ;; or its caller could possibily execute the CALLT insn, save_interrupt 
+    ;; MUST NOT be called via CALLT.
+    "*
+{
+  output_asm_insn (\"addi -24,   sp, sp\", operands);
+  output_asm_insn (\"st.w r10,   12[sp]\", operands);
+  output_asm_insn (\"stsr ctpc,  r10\",    operands);
+  output_asm_insn (\"st.w r10,   16[sp]\", operands);
+  output_asm_insn (\"stsr ctpsw, r10\",    operands);
+  output_asm_insn (\"st.w r10,   20[sp]\", operands);
+  output_asm_insn (\"callt ctoff(__callt_save_interrupt)\", operands);
+  return \"\";
+}"
+   [(set_attr "length" "26")
+    (set_attr "cc" "none")])
+
+(define_insn "callt_return_interrupt"
+  [(unspec_volatile [(const_int 0)] 3)]
+  "TARGET_V850E && !TARGET_DISABLE_CALLT"
+  "callt ctoff(__callt_return_interrupt)"
+  [(set_attr "length" "2")
+   (set_attr "cc" "clobber")])
+
 (define_insn "save_interrupt"
   [(set (reg:SI 3) (plus:SI (reg:SI 3) (const_int -16)))
-   (set (mem:SI (reg:SI 3)) (reg:SI 30))
-   (set (mem:SI (plus:SI (reg:SI 3) (const_int -4))) (reg:SI 10))
-   (set (mem:SI (plus:SI (reg:SI 3) (const_int -8))) (reg:SI 4))
-   (set (mem:SI (plus:SI (reg:SI 3) (const_int -12))) (reg:SI 1))]
-  "TARGET_V850 && ! TARGET_LONG_CALLS"
-  "add -16, sp ; st.w r10, 12[sp] ; jarl __save_interrupt, r10"
-  [(set_attr "length" "12")
+   (set (mem:SI (plus:SI (reg:SI 3) (const_int -16))) (reg:SI 30))
+   (set (mem:SI (plus:SI (reg:SI 3) (const_int -12))) (reg:SI 4))
+   (set (mem:SI (plus:SI (reg:SI 3) (const_int  -8))) (reg:SI 1))
+   (set (mem:SI (plus:SI (reg:SI 3) (const_int  -4))) (reg:SI 10))]
+  ""
+  "*
+{
+  if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
+    return \"add -16,sp\;st.w r10,12[sp]\;jarl __save_interrupt,r10\";
+  else
+    {
+      output_asm_insn (\"add   -16, sp\", operands);
+      output_asm_insn (\"st.w  r10, 12[sp]\", operands);
+      output_asm_insn (\"st.w  ep, 0[sp]\", operands);
+      output_asm_insn (\"st.w  gp, 4[sp]\", operands);
+      output_asm_insn (\"st.w  r1, 8[sp]\", operands);
+      output_asm_insn (\"movhi hi(__ep), r0, ep\", operands);
+      output_asm_insn (\"movea lo(__ep), ep, ep\", operands);
+      output_asm_insn (\"movhi hi(__gp), r0, gp\", operands);
+      output_asm_insn (\"movea lo(__gp), gp, gp\", operands);
+      return \"\";
+    }
+}"
+  [(set (attr "length")
+        (if_then_else (ne (symbol_ref "TARGET_LONG_CALLS") (const_int 0))
+                       (const_int 10)
+                       (const_int 34)))
    (set_attr "cc" "clobber")])
-
+  
 ;; Restore r1, r4, r10, and return from the interrupt
-(define_insn "restore_interrupt"
+(define_insn "return_interrupt"
   [(return)
-   (set (reg:SI 3) (plus:SI (reg:SI 3) (const_int 16)))
-   (set (reg:SI 30) (mem:SI (plus:SI (reg:SI 3) (const_int 12))))
-   (set (reg:SI 10) (mem:SI (plus:SI (reg:SI 3) (const_int 8))))
-   (set (reg:SI 4)  (mem:SI (plus:SI (reg:SI 3) (const_int 4))))
-   (set (reg:SI 1)  (mem:SI (reg:SI 3)))]
+   (set (reg:SI 3)  (plus:SI (reg:SI 3) (const_int 16)))
+   (set (reg:SI 10) (mem:SI (plus:SI (reg:SI 3) (const_int 12))))
+   (set (reg:SI 1)  (mem:SI (plus:SI (reg:SI 3) (const_int  8))))
+   (set (reg:SI 4)  (mem:SI (plus:SI (reg:SI 3) (const_int  4))))
+   (set (reg:SI 30) (mem:SI (reg:SI 3)))]
   ""
-  "jr __return_interrupt"
-  [(set_attr "length" "4")
+  "*
+{
+  if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
+    return \"jr __return_interrupt\";
+  else 
+    {
+      output_asm_insn (\"ld.w 0[sp],  ep\",   operands);
+      output_asm_insn (\"ld.w 4[sp],  gp\",   operands);
+      output_asm_insn (\"ld.w 8[sp],  r1\",   operands);
+      output_asm_insn (\"ld.w 12[sp], r10\", operands);
+      output_asm_insn (\"addi 16, sp, sp\",   operands);
+      output_asm_insn (\"reti\",            operands);
+      return \"\";
+    }
+}"
+  [(set (attr "length")
+        (if_then_else (ne (symbol_ref "TARGET_LONG_CALLS") (const_int 0))
+                       (const_int 4)
+                       (const_int 24)))
    (set_attr "cc" "clobber")])
 
-
 ;; Save all registers except for the registers saved in save_interrupt when
 ;; an interrupt function makes a call.
 ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
 ;; This is needed because the rest of the compiler is not ready to handle
 ;; insns this complicated.
 
+(define_insn "callt_save_all_interrupt"
+  [(unspec_volatile [(const_int 0)] 0)]
+  "TARGET_V850E && !TARGET_DISABLE_CALLT"
+  "callt ctoff(__callt_save_all_interrupt)"
+  [(set_attr "length" "2")
+   (set_attr "cc" "none")])
+
 (define_insn "save_all_interrupt"
   [(unspec_volatile [(const_int 0)] 0)]
+  ""
+  "*
+{
+  if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
+    return \"jarl __save_all_interrupt,r10\";
+
+  output_asm_insn (\"addi -120, sp, sp\", operands);
+  output_asm_insn (\"mov ep, r1\", operands);
+  output_asm_insn (\"mov sp, ep\", operands);
+  output_asm_insn (\"sst.w r31, 116[ep]\", operands);
+  output_asm_insn (\"sst.w r2,  112[ep]\", operands);
+  output_asm_insn (\"sst.w gp,  108[ep]\", operands);
+  output_asm_insn (\"sst.w r6,  104[ep]\", operands);
+  output_asm_insn (\"sst.w r7,  100[ep]\", operands);
+  output_asm_insn (\"sst.w r8,   96[ep]\", operands);
+  output_asm_insn (\"sst.w r9,   92[ep]\", operands);
+  output_asm_insn (\"sst.w r11,  88[ep]\", operands);
+  output_asm_insn (\"sst.w r12,  84[ep]\", operands);
+  output_asm_insn (\"sst.w r13,  80[ep]\", operands);
+  output_asm_insn (\"sst.w r14,  76[ep]\", operands);
+  output_asm_insn (\"sst.w r15,  72[ep]\", operands);
+  output_asm_insn (\"sst.w r16,  68[ep]\", operands);
+  output_asm_insn (\"sst.w r17,  64[ep]\", operands);
+  output_asm_insn (\"sst.w r18,  60[ep]\", operands);
+  output_asm_insn (\"sst.w r19,  56[ep]\", operands);
+  output_asm_insn (\"sst.w r20,  52[ep]\", operands);
+  output_asm_insn (\"sst.w r21,  48[ep]\", operands);
+  output_asm_insn (\"sst.w r22,  44[ep]\", operands);
+  output_asm_insn (\"sst.w r23,  40[ep]\", operands);
+  output_asm_insn (\"sst.w r24,  36[ep]\", operands);
+  output_asm_insn (\"sst.w r25,  32[ep]\", operands);
+  output_asm_insn (\"sst.w r26,  28[ep]\", operands);
+  output_asm_insn (\"sst.w r27,  24[ep]\", operands);
+  output_asm_insn (\"sst.w r28,  20[ep]\", operands);
+  output_asm_insn (\"sst.w r29,  16[ep]\", operands);
+  output_asm_insn (\"mov   r1,   ep\", operands);
+  return \"\";
+}"
+  [(set (attr "length")
+        (if_then_else (ne (symbol_ref "TARGET_LONG_CALLS") (const_int 0))
+                       (const_int 4)
+                       (const_int 62)
+       ))
+   (set_attr "cc" "clobber")])
+
+(define_insn "_save_all_interrupt"
+  [(unspec_volatile [(const_int 0)] 0)]
   "TARGET_V850 && ! TARGET_LONG_CALLS"
   "jarl __save_all_interrupt,r10"
   [(set_attr "length" "4")
    (set_attr "cc" "clobber")])
 
-
 ;; Restore all registers saved when an interrupt function makes a call.
 ;; UNSPEC_VOLATILE is considered to use and clobber all hard registers and
 ;; all of memory.  This blocks insns from being moved across this point.
 ;; This is needed because the rest of the compiler is not ready to handle
 ;; insns this complicated.
 
+(define_insn "callt_restore_all_interrupt"
+  [(unspec_volatile [(const_int 0)] 1)]
+  "TARGET_V850E && !TARGET_DISABLE_CALLT"
+  "callt ctoff(__callt_restore_all_interrupt)"
+  [(set_attr "length" "2")
+   (set_attr "cc" "none")])
+
 (define_insn "restore_all_interrupt"
   [(unspec_volatile [(const_int 0)] 1)]
+  ""
+  "*
+{
+  if (TARGET_PROLOG_FUNCTION && !TARGET_LONG_CALLS)
+    return \"jarl __restore_all_interrupt,r10\";
+  else
+    {
+      output_asm_insn (\"mov   ep,      r1\", operands);
+      output_asm_insn (\"mov   sp,      ep\", operands);
+      output_asm_insn (\"sld.w 116[ep], r31\", operands);
+      output_asm_insn (\"sld.w 112[ep], r2\", operands);
+      output_asm_insn (\"sld.w 108[ep], gp\", operands);
+      output_asm_insn (\"sld.w 104[ep], r6\", operands);
+      output_asm_insn (\"sld.w 100[ep], r7\", operands);
+      output_asm_insn (\"sld.w 96[ep],  r8\", operands);
+      output_asm_insn (\"sld.w 92[ep],  r9\", operands);
+      output_asm_insn (\"sld.w 88[ep],  r11\", operands);
+      output_asm_insn (\"sld.w 84[ep],  r12\", operands);
+      output_asm_insn (\"sld.w 80[ep],  r13\", operands);
+      output_asm_insn (\"sld.w 76[ep],  r14\", operands);
+      output_asm_insn (\"sld.w 72[ep],  r15\", operands);
+      output_asm_insn (\"sld.w 68[ep],  r16\", operands);
+      output_asm_insn (\"sld.w 64[ep],  r17\", operands);
+      output_asm_insn (\"sld.w 60[ep],  r18\", operands);
+      output_asm_insn (\"sld.w 56[ep],  r19\", operands);
+      output_asm_insn (\"sld.w 52[ep],  r20\", operands);
+      output_asm_insn (\"sld.w 48[ep],  r21\", operands);
+      output_asm_insn (\"sld.w 44[ep],  r22\", operands);
+      output_asm_insn (\"sld.w 40[ep],  r23\", operands);
+      output_asm_insn (\"sld.w 36[ep],  r24\", operands);
+      output_asm_insn (\"sld.w 32[ep],  r25\", operands);
+      output_asm_insn (\"sld.w 28[ep],  r26\", operands);
+      output_asm_insn (\"sld.w 24[ep],  r27\", operands);
+      output_asm_insn (\"sld.w 20[ep],  r28\", operands);
+      output_asm_insn (\"sld.w 16[ep],  r29\", operands);
+      output_asm_insn (\"mov   r1,      ep\", operands);
+      output_asm_insn (\"addi  120, sp, sp\", operands);
+      return \"\";
+    }
+}"
+  [(set (attr "length")
+        (if_then_else (ne (symbol_ref "TARGET_LONG_CALLS") (const_int 0))
+                       (const_int 4)
+                       (const_int 62)
+       ))
+   (set_attr "cc" "clobber")])
+
+(define_insn "_restore_all_interrupt"
+  [(unspec_volatile [(const_int 0)] 1)]
   "TARGET_V850 && ! TARGET_LONG_CALLS"
   "jarl __restore_all_interrupt,r10"
   [(set_attr "length" "4")
    (set_attr "cc" "clobber")])
 
 ;; Save r6-r9 for a variable argument function
+(define_insn "save_r6_r9_v850e"
+  [(set (mem:SI (reg:SI 3)) (reg:SI 6))
+   (set (mem:SI (plus:SI (reg:SI 3) (const_int 4))) (reg:SI 7))
+   (set (mem:SI (plus:SI (reg:SI 3) (const_int 8))) (reg:SI 8))
+   (set (mem:SI (plus:SI (reg:SI 3) (const_int 12))) (reg:SI 9))
+  ]
+  "TARGET_PROLOG_FUNCTION && TARGET_V850E && !TARGET_DISABLE_CALLT"
+  "callt ctoff(__callt_save_r6_r9)"
+  [(set_attr "length" "2")
+   (set_attr "cc" "none")])
+
 (define_insn "save_r6_r9"
   [(set (mem:SI (reg:SI 3)) (reg:SI 6))
    (set (mem:SI (plus:SI (reg:SI 3) (const_int 4))) (reg:SI 7))