]> oss.titaniummirror.com Git - msp430-gcc.git/blobdiff - gcc/config/mn10300/mn10300.md
Imported gcc-4.4.3
[msp430-gcc.git] / gcc / config / mn10300 / mn10300.md
index 31239559192bf5dda05012faa4740b12affd0ef4..35b0e589cb55c69e48d236290482f75404b10e01 100644 (file)
@@ -1,24 +1,23 @@
 ;; GCC machine description for Matsushita MN10300
-;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001
-;; Free Software Foundation, Inc.
+;; Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005,
+;; 2007, 2008 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)
+;; the Free Software Foundation; either version 3, 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
-;; the Free Software Foundation, 59 Temple Place - Suite 330,
-;; Boston, MA 02111-1307, USA.
+;; along with GCC; see the file COPYING3.  If not see
+;; <http://www.gnu.org/licenses/>.
 
 ;; The original PO technology requires these to be ordered by speed,
 ;; so that assigner will pick the fastest.
 ;; set_znv - insn sets z,n,v to usable values; c is unusable.
 ;; set_zn  - insn sets z,n to usable values; v,c are unusable.
 ;; compare - compare instruction
-;; invert -- like compare, but flags are inverted.
 ;; clobber - value of cc is unknown
-(define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber,invert"
+(define_attr "cc" "none,none_0hit,set_znv,set_zn,compare,clobber"
   (const_string "clobber"))
+
+(define_constants [
+  (PIC_REG     6)
+  (SP_REG      9)
+
+  (UNSPEC_INT_LABEL    0)
+  (UNSPEC_PIC          1)
+  (UNSPEC_GOT          2)
+  (UNSPEC_GOTOFF       3)
+  (UNSPEC_PLT          4)
+  (UNSPEC_GOTSYM_OFF   5)
+])
+
+(include "predicates.md")
+(include "constraints.md")
 \f
 ;; ----------------------------------------------------------------------
 ;; MOVE INSTRUCTIONS
@@ -57,8 +70,8 @@
 }")
 
 (define_insn ""
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=d*x*a,d*x,d*x*a,d*x*a,m")
-       (match_operand:QI 1 "general_operand" "0,I,d*xai,m,d*xa"))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=d*x*a*f,d*x,d*x*a,d*x*a,m,*f,d*x*a")
+       (match_operand:QI 1 "general_operand" "0,I,d*xai,m,d*xa,d*xa*f,*f"))]
   "TARGET_AM33
    && (register_operand (operands[0], QImode)
        || register_operand (operands[1], QImode))"
     case 3:
     case 4:
       return \"movbu %1,%0\";
+    case 5:
+    case 6:
+      return \"fmov %1,%0\";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
-  [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit")])
+  [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 (define_insn ""
-  [(set (match_operand:QI 0 "nonimmediate_operand" "=d*a,d,d*a,d,m")
-       (match_operand:QI 1 "general_operand" "0,I,dai,m,d"))]
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
+       (match_operand:QI 1 "general_operand" "0,I,i,i,da,m,d"))]
   "register_operand (operands[0], QImode)
    || register_operand (operands[1], QImode)"
   "*
     case 1:
       return \"clr %0\";
     case 2:
+    case 3:
+    case 4:
       if (GET_CODE (operands[1]) == CONST_DOUBLE)
        {
          rtx xoperands[2];
        }
 
       return \"mov %1,%0\";
-    case 3:
-    case 4:
+    case 5:
+    case 6:
       return \"movbu %1,%0\";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
-  [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit")])
+  [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 ;; movhi
 
 }")
 
 (define_insn ""
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=d*x*a,d*x,d*x*a,d*x*a,m")
-       (match_operand:HI 1 "general_operand" "0,I,d*x*ai,m,d*x*a"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=d*x*a*f,d*x,d*x*a,d*x*a,m,*f,d*x*a")
+       (match_operand:HI 1 "general_operand" "0,I,d*x*ai,m,d*x*a,d*x*a*f,*f"))]
   "TARGET_AM33
    && (register_operand (operands[0], HImode)
        || register_operand (operands[1], HImode))"
     case 3:
     case 4:
       return \"movhu %1,%0\";
+    case 5:
+    case 6:
+      return \"fmov %1,%0\";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
-  [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit")])
+  [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 (define_insn ""
-  [(set (match_operand:HI 0 "nonimmediate_operand" "=d*a,d,d*a,d,m")
-       (match_operand:HI 1 "general_operand" "0,I,dai,m,d"))]
+  [(set (match_operand:HI 0 "nonimmediate_operand" "=d*a,d,d,!*a,d*a,d,m")
+       (match_operand:HI 1 "general_operand" "0,I,i,i,da,m,d"))]
   "register_operand (operands[0], HImode)
    || register_operand (operands[1], HImode)"
   "*
     case 1:
       return \"clr %0\";
     case 2:
+    case 3:
+    case 4:
       if (GET_CODE (operands[1]) == CONST_DOUBLE)
        {
          rtx xoperands[2];
          return \"\";
        }
       return \"mov %1,%0\";
-    case 3:
-    case 4:
+    case 5:
+    case 6:
       return \"movhu %1,%0\";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
-  [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit")])
+  [(set_attr "cc" "none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 ;; movsi and helpers
 
   DONE;
 }")
 
+(define_insn "pop_pic_reg"
+  [(set (reg:SI PIC_REG)
+       (mem:SI (post_inc:SI (reg:SI SP_REG))))]
+  "reload_completed"
+  "movm (sp),[a2]")
+
 (define_expand "movsi"
   [(set (match_operand:SI 0 "general_operand" "")
        (match_operand:SI 1 "general_operand" ""))]
   if (!register_operand (operand1, SImode)
       && !register_operand (operand0, SImode))
     operands[1] = copy_to_mode_reg (SImode, operand1);
+  if (flag_pic)
+    {
+      rtx temp;
+      if (SYMBOLIC_CONST_P (operands[1]))
+       {
+         if (GET_CODE (operands[0]) == MEM)
+           operands[1] = force_reg (Pmode, operands[1]);
+         else
+           {
+             temp = (!can_create_pseudo_p ()
+                     ? operands[0]
+                     : gen_reg_rtx (Pmode));
+             operands[1] = legitimize_pic_address (operands[1], temp);
+           }
+       }
+      else if (GET_CODE (operands[1]) == CONST
+              && GET_CODE (XEXP (operands[1], 0)) == PLUS
+              && SYMBOLIC_CONST_P (XEXP (XEXP (operands[1], 0), 0)))
+       {
+         temp = !can_create_pseudo_p () ? operands[0] : gen_reg_rtx (Pmode);
+         temp = legitimize_pic_address (XEXP (XEXP (operands[1], 0), 0),
+                                        temp);
+         operands[1] = expand_binop (SImode, add_optab, temp,
+                                     XEXP (XEXP (operands[1], 0), 1),
+                                     (!can_create_pseudo_p ()
+                                      ? temp
+                                      : gen_reg_rtx (Pmode)),
+                                     0, OPTAB_LIB_WIDEN);
+       }
+    }
 }")
 
 (define_insn ""
   [(set (match_operand:SI 0 "nonimmediate_operand"
-                               "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,!*y")
+                               "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,axR,!*y,*f,*f,dxaQ")
        (match_operand:SI 1 "general_operand"
-                               "0,0,I,I,dx,ax,dx,ax,dixm,aixm,dixm,aixm,!*y,axR"))]
+                               "0,0,I,I,dx,ax,dx,ax,dixm,aixm,dixm,aixm,!*y,axR,0,dxaQi*f,*f"))]
   "register_operand (operands[0], SImode)
    || register_operand (operands[1], SImode)"
   "*
            return \"movu %1,%0\";
        }
       return \"mov %1,%0\";
+    case 14:
+      return \"nop\";
+    case 15:
+    case 16:
+      return \"fmov %1,%0\";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none,none_0hit,none_0hit")])
 
 (define_expand "movsf"
   [(set (match_operand:SF 0 "general_operand" "")
 }")
 
 (define_insn ""
-  [(set (match_operand:SF 0 "nonimmediate_operand" "=dx,ax,dx,a,daxm,dax")
-       (match_operand:SF 1 "general_operand" "0,0,G,G,dax,daxFm"))]
+  [(set (match_operand:SF 0 "nonimmediate_operand" "=f,dx,ax,dx,a,f,dxaQ,daxm,dax")
+       (match_operand:SF 1 "general_operand" "0,0,0,G,G,fdxaQF,f,dax,daxFm"))]
   "register_operand (operands[0], SFmode)
    || register_operand (operands[1], SFmode)"
   "*
     {
     case 0:
     case 1:
-      return \"nop\";
     case 2:
-      return \"clr %0\";
+      return \"nop\";
     case 3:
-    case 4:
+      return \"clr %0\";
+    /* case 4: below */
     case 5:
+    case 6:
+      return \"fmov %1, %0\";
+    case 4:
+    case 7:
+    case 8:
       if (REGNO_REG_CLASS (true_regnum (operands[0])) == EXTENDED_REGS
          && GET_CODE (operands[1]) == CONST_INT)
        {
        }
       return \"mov %1,%0\";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit")])
+  [(set_attr "cc" "none,none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
 
 (define_expand "movdi"
   [(set (match_operand:DI 0 "general_operand" "")
 
 (define_insn ""
   [(set (match_operand:DI 0 "nonimmediate_operand"
-                               "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax")
+                               "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax,*f,*f,*f,dxa,*f,Q")
        (match_operand:DI 1 "general_operand"
-                               "0,0,I,I,dx,ax,dx,ax,dxim,axim,dxim,axim"))]
+                               "0,0,I,I,dx,ax,dx,ax,dxim,axim,dxim,axim,0,*f,dxai,*f,Q,*f"))]
   "register_operand (operands[0], DImode)
    || register_operand (operands[1], DImode)"
   "*
            while (GET_CODE (temp) == SUBREG)
              temp = SUBREG_REG (temp);
 
-           if (GET_CODE (temp) != REG)
-             abort ();
+           gcc_assert (GET_CODE (temp) == REG);
 
            if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
                                         XEXP (operands[1], 0)))
              return \"mov %H1,%H0\;mov %L1,%L0\";
            else
              return \"mov %L1,%L0\;mov %H1,%H0\";
-             
+
          }
        else if (GET_CODE (operands[1]) == MEM
                 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
                         == EXTENDED_REGS)
                     && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
                         || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
-             output_asm_insn (\"movu %1,%0\", operands);
+             output_asm_insn (\"movu %L1,%L0\", operands);
            else
              output_asm_insn (\"mov %L1,%L0\", operands);
 
                         == EXTENDED_REGS)
                     && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
                         || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
-             output_asm_insn (\"movu %1,%0\", operands);
+             output_asm_insn (\"movu %H1,%H0\", operands);
            else
              output_asm_insn (\"mov %H1,%H0\", operands);
            return \"\";
          }
+      case 12:
+        return \"nop\";
+      case 13:
+      case 14:
+      case 15:
+        return \"fmov %L1, %L0\;fmov %H1, %H0\";
+      case 16:
+       if (GET_CODE (operands[1]) == MEM
+           && GET_CODE (XEXP (operands[1], 0)) == CONST_INT
+           && (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
+         return \"fmov %D1, %D0\";
+       else
+          return \"fmov %L1, %L0\;fmov %H1, %H0\";
+      case 17:
+       if (GET_CODE (operands[0]) == MEM
+           && GET_CODE (XEXP (operands[0], 0)) == CONST_INT
+           && (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
+         return \"fmov %D1, %D0\";
+       else
+          return \"fmov %L1, %L0\;fmov %H1, %H0\";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+  [(set (attr "cc")
+       (cond
+        [
+        (ior (lt (symbol_ref "which_alternative") (const_int 2))
+             (eq (symbol_ref "which_alternative") (const_int 12))
+             ) (const_string "none")
+        (eq (symbol_ref "which_alternative") (const_int 2)
+            ) (const_string "clobber")
+        (eq (symbol_ref "which_alternative") (const_int 3)
+            ) (if_then_else
+               (ne (symbol_ref "rtx_equal_p (operands[0], operands[1])")
+                   (const_int 0)) (const_string "clobber")
+                   (const_string "none_0hit"))
+        (ior (eq (symbol_ref "which_alternative") (const_int 8))
+             (eq (symbol_ref "which_alternative") (const_int 9))
+             ) (if_then_else
+                (ne (symbol_ref "mn10300_wide_const_load_uses_clr
+                                 (operands)")
+                    (const_int 0)) (const_string "clobber")
+                    (const_string "none_0hit"))
+        ] (const_string "none_0hit")))])
 
 (define_expand "movdf"
   [(set (match_operand:DF 0 "general_operand" "")
 
 (define_insn ""
   [(set (match_operand:DF 0 "nonimmediate_operand"
-                               "=dx,ax,dx,a,dxm,dxm,axm,axm,dx,dx,ax,ax")
+                               "=f,dx,ax,dx,f,f,dxa,f,Q,a,dxm,dxm,axm,axm,dx,dx,ax,ax")
        (match_operand:DF 1 "general_operand"
-                               "0,0,G,G,dx,ax,dx,ax,dxFm,axFm,dxFm,axFm"))]
+                               "0,0,0,G,f,dxaF,f,Q,f,G,dx,ax,dx,ax,dxFm,axFm,dxFm,axFm"))]
   "register_operand (operands[0], DFmode)
    || register_operand (operands[1], DFmode)"
   "*
     {
       case 0:
       case 1:
+      case 2:
        return \"nop\";
 
-      case 2:
+      case 3:
        return \"clr %L0\;clr %H0\";
 
-      case 3:
-        if (rtx_equal_p (operands[0], operands[1]))
-          return \"sub %L1,%L0\;mov %L0,%H0\";
-        else
-          return \"mov %1,%L0\;mov %L0,%H0\";
       case 4:
       case 5:
       case 6:
+        return \"fmov %L1, %L0\;fmov %H1, %H0\";
+
       case 7:
+       if (GET_CODE (operands[1]) == MEM
+           && GET_CODE (XEXP (operands[1], 0)) == CONST_INT
+           && (INTVAL (XEXP (operands[1], 0)) & 7) == 0)
+         return \"fmov %D1, %D0\";
+       else
+          return \"fmov %L1, %L0\;fmov %H1, %H0\";
+
       case 8:
+       if (GET_CODE (operands[0]) == MEM
+           && GET_CODE (XEXP (operands[0], 0)) == CONST_INT
+           && (INTVAL (XEXP (operands[0], 0)) & 7) == 0)
+         return \"fmov %D1, %D0\";
+       else
+          return \"fmov %L1, %L0\;fmov %H1, %H0\";
+
       case 9:
+        if (rtx_equal_p (operands[0], operands[1]))
+          return \"sub %L1,%L0\;mov %L0,%H0\";
+        else
+          return \"mov %1,%L0\;mov %L0,%H0\";
       case 10:
       case 11:
+      case 12:
+      case 13:
+      case 14:
+      case 15:
+      case 16:
+      case 17:
        if (GET_CODE (operands[1]) == CONST_INT)
          {
            rtx low, high;
            while (GET_CODE (temp) == SUBREG)
              temp = SUBREG_REG (temp);
 
-           if (GET_CODE (temp) != REG)
-             abort ();
+           gcc_assert (GET_CODE (temp) == REG);
 
            if (reg_overlap_mentioned_p (gen_rtx_REG (SImode, REGNO (temp)),
                                         XEXP (operands[1], 0)))
              return \"mov %H1,%H0\;mov %L1,%L0\";
            else
              return \"mov %L1,%L0\;mov %H1,%H0\";
-             
+
          }
        else if (GET_CODE (operands[1]) == MEM
                 && CONSTANT_ADDRESS_P (XEXP (operands[1], 0))
                         == EXTENDED_REGS)
                     && (((val[0] & 0x80) && ! (val[0] & 0xffffff00))
                         || ((val[0] & 0x800000) && ! (val[0] & 0xff000000))))
-             output_asm_insn (\"movu %1,%0\", operands);
+             output_asm_insn (\"movu %L1,%L0\", operands);
            else
              output_asm_insn (\"mov %L1,%L0\", operands);
 
                         == EXTENDED_REGS)
                     && (((val[1] & 0x80) && ! (val[1] & 0xffffff00))
                         || ((val[1] & 0x800000) && ! (val[1] & 0xff000000))))
-             output_asm_insn (\"movu %1,%0\", operands);
+             output_asm_insn (\"movu %H1,%H0\", operands);
            else
              output_asm_insn (\"mov %H1,%H0\", operands);
            return \"\";
          }
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
-  [(set_attr "cc" "none,none,clobber,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit,none_0hit")])
+  [(set (attr "cc")
+       (cond
+        [
+        (lt (symbol_ref "which_alternative") (const_int 3)
+            ) (const_string "none")
+        (eq (symbol_ref "which_alternative") (const_int 3)
+            ) (const_string "clobber")
+        (eq (symbol_ref "which_alternative") (const_int 9)
+            ) (if_then_else
+               (ne (symbol_ref "rtx_equal_p (operands[0], operands[1])")
+                   (const_int 0)) (const_string "clobber")
+                   (const_string "none_0hit"))
+        (ior (eq (symbol_ref "which_alternative") (const_int 14))
+             (eq (symbol_ref "which_alternative") (const_int 15))
+             ) (if_then_else
+                (ne (symbol_ref "mn10300_wide_const_load_uses_clr
+                                 (operands)")
+                    (const_int 0)) (const_string "clobber")
+                    (const_string "none_0hit"))
+        ] (const_string "none_0hit")))])
 
 
 \f
 ;; but will have the proper effect on cc0.  Using d0 is arbitrary; any
 ;; data register would work.)
 
-;; Even though the first alternative would be preferrable if it can
+;; Even though the first alternative would be preferable if it can
 ;; possibly match, reload must not be given the opportunity to attempt
 ;; to use it.  It assumes that such matches can only occur when one of
 ;; the operands is used for input and the other for output.  Since
   btst 0,d0
   cmp %1,%0"
   [(set_attr "cc" "compare,compare")])
+
+(define_insn "cmpsf"
+  [(set (cc0)
+       (compare (match_operand:SF 0 "register_operand" "f,f")
+                (match_operand:SF 1 "nonmemory_operand" "f,F")))]
+  "TARGET_AM33_2"
+  "fcmp %1,%0"
+  [(set_attr "cc" "compare,compare")])
 \f
 ;; ----------------------------------------------------------------------
 ;; ADD INSTRUCTIONS
        src1_class = REGNO_REG_CLASS (true_regnum (operands[1]));
        src2_class = REGNO_REG_CLASS (true_regnum (operands[2]));
        dst_class = REGNO_REG_CLASS (true_regnum (operands[0]));
-       
+
        /* I'm not sure if this can happen or not.  Might as well be prepared
          and generate the best possible code if it does happen.  */
        if (true_regnum (operands[0]) == true_regnum (operands[1]))
               add the other source to the destination.
 
               Carefully select which source to copy to the destination; a naive
-              implementation will waste a byte when the source classes are 
+              implementation will waste a byte when the source classes are
               different and the destination is an address register.  Selecting
               the lowest cost register copy will optimize this sequence.  */
            if (REGNO_REG_CLASS (true_regnum (operands[1]))
       return \"mov %2,%0\;add %1,%0\";
       }
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
   [(set_attr "cc" "set_zn,none_0hit,set_zn,none_0hit,set_zn,none_0hit,set_zn")])
        return \"mov %1,%0\;add %2,%0\";
       return \"mov %2,%0\;add %1,%0\";
     default:
-      abort ();
+      gcc_unreachable ();
     }
 }"
   [(set_attr "cc" "set_zn,none_0hit,none_0hit,set_zn,none_0hit,set_zn")])
 {
   rtx target = gen_reg_rtx (SImode);
 
-  emit_move_insn (target, GEN_INT (0));
+  emit_move_insn (target, const0_rtx);
   emit_insn (gen_subsi3 (target, target, operands[1]));
   emit_move_insn (operands[0], target);
   DONE;
     return \"mul %2,%0\";
 }"
   [(set_attr "cc" "set_zn")])
-  
+
 (define_insn ""
   [(set (match_operand:SI 0 "register_operand" "=dx")
        (mult:SI (match_operand:SI 1 "register_operand" "%0")
     return \"and %1,%0\";
   return \"and %2,%0\";
 }"
-  [(set_attr "cc" "none_0hit,set_znv,set_znv")])
+  [(set (attr "cc")
+       (cond
+        [
+        (eq (symbol_ref "which_alternative") (const_int 0)
+            ) (const_string "none_0hit")
+        (ne (symbol_ref "GET_CODE (operands[2]) == CONST_INT
+                         && (INTVAL (operands[2]) == 0x7fffffff
+                             || INTVAL (operands[2]) == 0x3fffffff
+                             || INTVAL (operands[2]) == 0x1fffffff
+                             || INTVAL (operands[2]) == 0x0fffffff
+                             || INTVAL (operands[2]) == 0xfffffffe
+                             || INTVAL (operands[2]) == 0xfffffffc
+                             || INTVAL (operands[2]) == 0xfffffff8
+                             || INTVAL (operands[2]) == 0xfffffff0)")
+            (const_int 0)) (const_string "set_zn")
+         ] (const_string "set_znv")))])
 
 (define_insn ""
   [(set (match_operand:SI 0 "register_operand" "=dx,dx")
     return \"lsr 4,%0\;asl2 %0\;asl2 %0\";
   return \"and %2,%0\";
 }"
-  [(set_attr "cc" "none_0hit,set_znv")])
+  [(set (attr "cc")
+       (cond
+        [
+        (eq (symbol_ref "which_alternative") (const_int 0)
+            ) (const_string "none_0hit")
+        ;; Shifts don't set the V flag, but bitwise operations clear
+        ;; it (which correctly reflects the absence of overflow in a
+        ;; compare-with-zero that might follow).  As for the
+        ;; 0xfffffffe case, the add may overflow, so we can't use the
+        ;; V flag.
+        (ne (symbol_ref "GET_CODE (operands[2]) == CONST_INT
+                         && (INTVAL (operands[2]) == 0x7fffffff
+                             || INTVAL (operands[2]) == 0x3fffffff
+                             || INTVAL (operands[2]) == 0x1fffffff
+                             || INTVAL (operands[2]) == 0x0fffffff
+                             || INTVAL (operands[2]) == 0xfffffffe
+                             || INTVAL (operands[2]) == 0xfffffffc
+                             || INTVAL (operands[2]) == 0xfffffff8
+                             || INTVAL (operands[2]) == 0xfffffff0)")
+            (const_int 0)) (const_string "set_zn")
+         ] (const_string "set_znv")))])
 
 ;; ----------------------------------------------------------------------
 ;; OR INSTRUCTIONS
   and %1,%0"
   [(set_attr "cc" "clobber,set_znv")])
 
+(define_insn ""
+  [(set (match_operand:QI 0 "memory_operand" "=R,T")
+       (and:QI
+        (match_dup 0)
+        (not:QI (match_operand:QI 1 "nonmemory_operand" "i,d"))))]
+  ""
+  "@
+  bclr %U1,%A0
+  bclr %1,%0"
+  [(set_attr "cc" "clobber,clobber")])
+
 (define_insn ""
   [(set (match_operand:QI 0 "nonimmediate_operand" "+R,d")
        (subreg:QI
                  (match_operand:SI 1 "const_int_operand" "i,i")) 0))]
   ""
   "@
-  bset %1,%A0
+  bset %U1,%A0
   or %1,%0"
   [(set_attr "cc" "clobber,set_znv")])
 
+(define_expand "iorqi3"
+  [(set (match_operand:QI 0 "nonimmediate_operand" "")
+       (ior:QI (match_operand:QI 1 "nonimmediate_operand" "")
+               (match_operand:QI 2 "nonmemory_operand" "")))]
+  ""
+  "")
+
+(define_insn ""
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=R,T,r")
+       (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
+               ;; This constraint should really be nonmemory_operand,
+               ;; but making it general_operand, along with the
+               ;; condition that not both input operands are MEMs, it
+               ;; here helps combine do a better job.
+               (match_operand:QI 2 "general_operand" "i,d,ir")))]
+  "TARGET_AM33 &&
+   (GET_CODE (operands[2]) != MEM || GET_CODE (operands[1]) != MEM)"
+  "@
+  bset %U2,%A0
+  bset %2,%0
+  or %2,%0"
+  [(set_attr "cc" "clobber,clobber,set_znv")])
+
+(define_insn ""
+  [(set (match_operand:QI 0 "nonimmediate_operand" "=R,T,d")
+       (ior:QI (match_operand:QI 1 "nonimmediate_operand" "%0,0,0")
+               ;; This constraint should really be nonmemory_operand,
+               ;; but making it general_operand, along with the
+               ;; condition that not both input operands are MEMs, it
+               ;; here helps combine do a better job.
+               (match_operand:QI 2 "general_operand" "i,d,id")))]
+  "GET_CODE (operands[2]) != MEM || GET_CODE (operands[1]) != MEM"
+  "@
+  bset %U2,%A0
+  bset %2,%0
+  or %2,%0"
+  [(set_attr "cc" "clobber,clobber,set_znv")])
+
 (define_insn ""
   [(set (cc0)
      (zero_extract:SI (match_operand:SI 0 "register_operand" "dx")
       len--;
     }
 
-  /* If the source operand is not a reg (ie it is memory), then extract the
+  /* If the source operand is not a reg (i.e. it is memory), then extract the
      bits from mask that we actually want to test.  Note that the mask will
      never cross a byte boundary.  */
   if (!REG_P (operands[0]))
       else if (mask & 0xff000000)
        mask = (mask >> 24) & 0xff;
     }
-  
+
   xoperands[0] = operands[0];
   xoperands[1] = GEN_INT (trunc_int_for_mode (mask, SImode));
   if (GET_CODE (operands[0]) == REG)
     output_asm_insn (\"btst %1,%0\", xoperands);
   else
-    output_asm_insn (\"btst %1,%A0\", xoperands);
+    output_asm_insn (\"btst %U1,%A0\", xoperands);
   return \"\";
 }"
   [(set_attr "cc" "clobber")])
        (match_operand:SI 1 "const_8bit_operand" "")))]
   ""
   "@
-  btst %1,%A0
+  btst %U1,%A0
   btst %1,%0"
   [(set_attr "cc" "clobber")])
 
   ""
   "*
 {
+  if (cc_status.mdep.fpCC)
+    return \"fb%b1 %0\";
   if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
       && (GET_CODE (operands[1]) == GT
          || GET_CODE (operands[1]) == GE
   ""
   "*
 {
+  if (cc_status.mdep.fpCC)
+    return \"fb%B1 %0\";
   if ((cc_status.flags & CC_OVERFLOW_UNUSABLE) != 0
       && (GET_CODE (operands[1]) == GT
          || GET_CODE (operands[1]) == GE
   "jmp (%0)"
   [(set_attr "cc" "none")])
 
+(define_expand "builtin_setjmp_receiver"
+  [(match_operand 0 "" "")]
+  "flag_pic"
+  "
+{
+  if (flag_pic)
+    emit_insn (gen_GOTaddr2picreg ());
+
+  DONE;
+}")
+
+(define_expand "casesi"
+  [(match_operand:SI 0 "register_operand" "")
+   (match_operand:SI 1 "immediate_operand" "")
+   (match_operand:SI 2 "immediate_operand" "")
+   (match_operand 3 "" "") (match_operand 4 "" "")]
+  ""
+  "
+{
+  rtx table = gen_reg_rtx (SImode);
+  rtx index = gen_reg_rtx (SImode);
+  rtx addr = gen_reg_rtx (Pmode);
+
+  emit_move_insn (table, gen_rtx_LABEL_REF (VOIDmode, operands[3]));
+  emit_move_insn (index, plus_constant (operands[0], - INTVAL (operands[1])));
+  emit_insn (gen_cmpsi (index, operands[2]));
+  emit_jump_insn (gen_bgtu (operands[4]));
+  emit_move_insn (index, gen_rtx_ASHIFT (SImode, index, const2_rtx));
+  emit_move_insn (addr, gen_rtx_MEM (SImode,
+                                    gen_rtx_PLUS (SImode, table, index)));
+  if (flag_pic)
+    emit_move_insn (addr, gen_rtx_PLUS (SImode, addr, table));
+
+  emit_jump_insn (gen_tablejump (addr, operands[3]));
+  DONE;
+}")
+
 (define_insn "tablejump"
   [(set (pc) (match_operand:SI 0 "register_operand" "a"))
    (use (label_ref (match_operand 1 "" "")))]
   ""
   "
 {
+  if (flag_pic && GET_CODE (XEXP (operands[0], 0)) == SYMBOL_REF)
+    {
+      if (MN10300_GLOBAL_P (XEXP (operands[0], 0)))
+       {
+         /* The PLT code won't run on AM30, but then, there's no
+            shared library support for AM30 either, so we just assume
+            the linker is going to adjust all @PLT relocs to the
+            actual symbols.  */
+         emit_use (pic_offset_table_rtx);
+         XEXP (operands[0], 0) = gen_sym2PLT (XEXP (operands[0], 0));
+       }
+      else
+       XEXP (operands[0], 0) = gen_sym2PIC (XEXP (operands[0], 0));
+    }
   if (! call_address_operand (XEXP (operands[0], 0), VOIDmode))
     XEXP (operands[0], 0) = force_reg (SImode, XEXP (operands[0], 0));
   emit_call_insn (gen_call_internal (XEXP (operands[0], 0), operands[1]));
   DONE;
 }")
 
+;; NB: Mode on match_operand 0 deliberately omitted in
+;;     order to be able to match UNSPECs in PIC mode.
 (define_insn "call_internal"
-  [(call (mem:QI (match_operand:SI 0 "call_address_operand" "aS"))
+  [(call (mem:QI (match_operand 0 "call_address_operand" "aS"))
         (match_operand:SI 1 "general_operand" "g"))]
   ""
   "*
   ""
   "
 {
+  if (flag_pic && GET_CODE (XEXP (operands[1], 0)) == SYMBOL_REF)
+    {
+      if (MN10300_GLOBAL_P (XEXP (operands[1], 0)))
+       {
+         /* The PLT code won't run on AM30, but then, there's no
+            shared library support for AM30 either, so we just assume
+            the linker is going to adjust all @PLT relocs to the
+            actual symbols.  */
+         emit_use (pic_offset_table_rtx);
+         XEXP (operands[1], 0) = gen_sym2PLT (XEXP (operands[1], 0));
+       }
+      else
+       XEXP (operands[1], 0) = gen_sym2PIC (XEXP (operands[1], 0));
+    }
   if (! call_address_operand (XEXP (operands[1], 0), VOIDmode))
     XEXP (operands[1], 0) = force_reg (SImode, XEXP (operands[1], 0));
   emit_call_insn (gen_call_value_internal (operands[0],
   DONE;
 }")
 
+;; NB: Mode on match_operands 0 and 1 deliberately omitted
+;;     in order to be able to match UNSPECs in PIC mode.
 (define_insn "call_value_internal"
-  [(set (match_operand 0 "" "=dax")
-       (call (mem:QI (match_operand:SI 1 "call_address_operand" "aS"))
-             (match_operand:SI 2 "general_operand" "g")))]
+  [(set (match_operand               0 "register_operand" "=dax")
+       (call (mem:QI (match_operand 1 "call_address_operand" "aS"))
+             (match_operand:SI      2 "general_operand" "g")))]
   ""
   "*
 {
                         operand_subword_force (operands[1], 1, DFmode),
                         GEN_INT (0x7fffffff), target, 0, OPTAB_WIDEN);
 
-  if (result == 0)
-    abort ();
+  gcc_assert (result);
 
   if (result != target)
     emit_move_insn (result, target);
   insns = get_insns ();
   end_sequence ();
 
-  emit_no_conflict_block (insns, operands[0], operands[1], 0, 0);
+  emit_insn (insns);
   DONE;
 }")
 
   rtx result;
   rtx target;
 
+  if (TARGET_AM33_2)
+    {
+      emit_insn (gen_abssf2_am33_2 (operands[0], operands[1]));
+      DONE;
+    }
+
   target = operand_subword_force (operands[0], 0, SFmode);
   result = expand_binop (SImode, and_optab,
                         operand_subword_force (operands[1], 0, SFmode),
                         GEN_INT (0x7fffffff), target, 0, OPTAB_WIDEN);
-  if (result == 0)
-    abort ();
+  gcc_assert (result);
 
   if (result != target)
     emit_move_insn (result, target);
 }")
 
 
+(define_insn "abssf2_am33_2"
+  [(set (match_operand:SF 0 "register_operand" "=f,f")
+       (abs:SF (match_operand:SF 1 "register_operand" "0,?f")))]
+  "TARGET_AM33_2"
+  "@
+   fabs %0
+   fabs %1, %0"
+  [(set_attr "cc" "none_0hit")])
+
 (define_expand "negdf2"
   [(set (match_operand:DF 0 "register_operand" "")
         (neg:DF (match_operand:DF 1 "register_operand" "")))]
                         GEN_INT (trunc_int_for_mode (0x80000000, SImode)),
                         target, 0, OPTAB_WIDEN);
 
-  if (result == 0)
-    abort ();
+  gcc_assert (result);
 
   if (result != target)
     emit_move_insn (result, target);
   insns = get_insns ();
   end_sequence ();
 
-  emit_no_conflict_block (insns, operands[0], operands[1], 0, 0);
+  emit_insn (insns);
   DONE;
 }")
 
   rtx result;
   rtx target;
 
+  if (TARGET_AM33_2)
+    {
+      emit_insn (gen_negsf2_am33_2 (operands[0], operands[1]));
+      DONE;
+    }
+
   target = operand_subword_force (operands[0], 0, SFmode);
   result = expand_binop (SImode, xor_optab,
                         operand_subword_force (operands[1], 0, SFmode),
                         GEN_INT (trunc_int_for_mode (0x80000000, SImode)),
                         target, 0, OPTAB_WIDEN);
-  if (result == 0)
-    abort ();
+  gcc_assert (result);
 
   if (result != target)
     emit_move_insn (result, target);
   DONE;
 }")
 
+(define_insn "negsf2_am33_2"
+  [(set (match_operand:SF 0 "register_operand" "=f,f")
+       (neg:SF (match_operand:SF 1 "register_operand" "0,?f")))]
+  "TARGET_AM33_2"
+  "@
+   fneg %0
+   fneg %1, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_expand "sqrtsf2"
+  [(set (match_operand:SF 0 "register_operand" "")
+       (sqrt:SF (match_operand:SF 1 "register_operand" "")))]
+  "TARGET_AM33_2 && flag_unsafe_math_optimizations"
+  "
+{
+  rtx scratch = gen_reg_rtx (SFmode);
+  emit_insn (gen_rsqrtsf2 (scratch, operands[1], CONST1_RTX (SFmode)));
+  emit_insn (gen_divsf3 (operands[0], force_reg (SFmode, CONST1_RTX (SFmode)),
+                        scratch));
+  DONE;
+}")
+
+(define_insn "rsqrtsf2"
+  [(set (match_operand:SF 0 "register_operand" "=f,f")
+       (div:SF (match_operand:SF 2 "const_1f_operand" "F,F")
+               (sqrt:SF (match_operand:SF 1 "register_operand" "0,?f"))))]
+  "TARGET_AM33_2"
+  "@
+   frsqrt %0
+   frsqrt %1, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_insn "addsf3"
+  [(set (match_operand:SF 0 "register_operand" "=f,f")
+       (plus:SF (match_operand:SF 1 "register_operand" "%0,f")
+                (match_operand:SF 2 "general_operand" "f,?fF")))]
+  "TARGET_AM33_2"
+  "@
+   fadd %2, %0
+   fadd %2, %1, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_insn "subsf3"
+  [(set (match_operand:SF 0 "register_operand" "=f,f")
+       (minus:SF (match_operand:SF 1 "register_operand" "0,f")
+                 (match_operand:SF 2 "general_operand" "f,?fF")))]
+  "TARGET_AM33_2"
+  "@
+   fsub %2, %0
+   fsub %2, %1, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_insn "mulsf3"
+  [(set (match_operand:SF 0 "register_operand" "=f,f")
+       (mult:SF (match_operand:SF 1 "register_operand" "%0,f")
+                (match_operand:SF 2 "general_operand" "f,?fF")))]
+  "TARGET_AM33_2"
+  "@
+   fmul %2, %0
+   fmul %2, %1, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_insn "divsf3"
+  [(set (match_operand:SF 0 "register_operand" "=f,f")
+       (div:SF (match_operand:SF 1 "register_operand" "0,f")
+               (match_operand:SF 2 "general_operand" "f,?fF")))]
+  "TARGET_AM33_2"
+  "@
+   fdiv %2, %0
+   fdiv %2, %1, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_insn "fmaddsf4"
+  [(set (match_operand:SF 0 "register_operand" "=A")
+       (plus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
+                         (match_operand:SF 2 "register_operand" "f"))
+                (match_operand:SF 3 "register_operand" "f")))]
+  "TARGET_AM33_2"
+  "fmadd %1, %2, %3, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_insn "fmsubsf4"
+  [(set (match_operand:SF 0 "register_operand" "=A")
+       (minus:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
+                          (match_operand:SF 2 "register_operand" "f"))
+                 (match_operand:SF 3 "register_operand" "f")))]
+  "TARGET_AM33_2"
+  "fmsub %1, %2, %3, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_insn "fnmaddsf4"
+  [(set (match_operand:SF 0 "register_operand" "=A")
+       (minus:SF (match_operand:SF 3 "register_operand" "f")
+                 (mult:SF (match_operand:SF 1 "register_operand" "%f")
+                          (match_operand:SF 2 "register_operand" "f"))))]
+  "TARGET_AM33_2"
+  "fnmadd %1, %2, %3, %0"
+  [(set_attr "cc" "none_0hit")])
+
+(define_insn "fnmsubsf4"
+  [(set (match_operand:SF 0 "register_operand" "=A")
+       (minus:SF (neg:SF (mult:SF (match_operand:SF 1 "register_operand" "%f")
+                                  (match_operand:SF 2 "register_operand" "f")))
+                 (match_operand:SF 3 "register_operand" "f")))]
+  "TARGET_AM33_2"
+  "fnmsub %1, %2, %3, %0"
+  [(set_attr "cc" "none_0hit")])
+
 
 ;; ----------------------------------------------------------------------
 ;; PROLOGUE/EPILOGUE
   return \"\";
 }"
   [(set_attr "cc" "clobber")])
-  
+
 (define_insn "return"
   [(return)]
   "can_use_return_insn ()"
   "add %0,%0\;bcc %1"
   [(set_attr "cc" "clobber")])
 
+(define_expand "int_label"
+  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_INT_LABEL)]
+  "" "")
+
+(define_expand "GOTaddr2picreg"
+  [(match_dup 0)]
+  "" "
+{
+  /* It would be nice to be able to have int_label keep track of the
+     counter and all, but if we add C code to it, we'll get an insn
+     back, and we just want the pattern.  */
+  operands[0] = gen_int_label (GEN_INT (mn10300_unspec_int_label_counter++));
+  if (TARGET_AM33)
+    emit_insn (gen_am33_loadPC (operands[0]));
+  else
+    emit_insn (gen_mn10300_loadPC (operands[0]));
+  emit_insn (gen_add_GOT_to_pic_reg (copy_rtx (operands[0])));
+  DONE;
+}
+")
+
+(define_insn "am33_loadPC"
+  [(parallel
+    [(set (reg:SI PIC_REG) (pc))
+     (use (match_operand 0 "" ""))])]
+  "TARGET_AM33"
+  "%0:\;mov pc,a2")
+
+
+(define_insn_and_split "mn10300_loadPC"
+  [(parallel
+    [(set (reg:SI PIC_REG) (pc))
+     (use (match_operand 0 "" ""))])]
+  ""
+  "#"
+  "reload_completed"
+  [(match_operand 0 "" "")]
+  "
+{
+  rtx sp_reg = gen_rtx_REG (SImode, SP_REG);
+  int need_stack_space = (get_frame_size () == 0
+                         && crtl->outgoing_args_size == 0);
+
+  if (need_stack_space)
+    emit_move_insn (sp_reg, plus_constant (sp_reg, -4));
+
+  emit_insn (gen_call_next_insn (operands[0]));
+
+  if (need_stack_space)
+    emit_insn (gen_pop_pic_reg ());
+  else
+    emit_move_insn (pic_offset_table_rtx, gen_rtx_MEM (SImode, sp_reg));
+
+  DONE;
+}")
+
+(define_insn "call_next_insn"
+  [(parallel
+    [(set (mem:SI (reg:SI SP_REG)) (pc))
+     (use (match_operand 0 "" ""))])]
+  "reload_completed"
+  "calls %0\;%0:")
+
+(define_expand "add_GOT_to_pic_reg"
+  [(set (reg:SI PIC_REG)
+       (plus:SI
+        (reg:SI PIC_REG)
+        (const:SI
+         (unspec:SI [(match_operand:SI 0 "" "")] UNSPEC_GOTSYM_OFF))))]
+  "")
+
+(define_expand "symGOT2reg"
+  [(match_operand:SI 0 "" "")
+   (match_operand:SI 1 "" "")]
+  ""
+  "
+{
+  rtx insn = emit_insn (gen_symGOT2reg_i (operands[0], operands[1]));
+
+  MEM_READONLY_P (SET_SRC (PATTERN (insn))) = 1;
+
+  set_unique_reg_note (insn, REG_EQUAL, operands[1]);
+
+  DONE;
+}")
+
+(define_expand "symGOT2reg_i"
+  [(set (match_operand:SI 0 "" "")
+       (mem:SI (plus:SI (reg:SI PIC_REG)
+                        (const (unspec [(match_operand:SI 1 "" "")]
+                                       UNSPEC_GOT)))))]
+  ""
+  "")
+
+(define_expand "symGOTOFF2reg"
+  [(match_operand:SI 0 "" "") (match_operand:SI 1 "" "")]
+  ""
+  "
+{
+  rtx insn = emit_insn (gen_symGOTOFF2reg_i (operands[0], operands[1]));
+
+  set_unique_reg_note (insn, REG_EQUAL, operands[1]);
+
+  DONE;
+}")
+
+(define_expand "symGOTOFF2reg_i"
+  [(set (match_operand:SI 0 "" "")
+       (const (unspec [(match_operand:SI 1 "" "")] UNSPEC_GOTOFF)))
+  (set (match_dup 0) (plus:SI (match_dup 0) (reg:SI PIC_REG)))]
+  ""
+  "")
+
+(define_expand "sym2PIC"
+  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_PIC)]
+  "" "")
+
+(define_expand "sym2PLT"
+  [(unspec [(match_operand:SI 0 "" "")] UNSPEC_PLT)]
+  "" "")