OSDN Git Service

Jakub Jelinek <jj@ultra.linux.cz>
authorrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 30 Jul 1999 21:55:06 +0000 (21:55 +0000)
committerrth <rth@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 30 Jul 1999 21:55:06 +0000 (21:55 +0000)
        * config/sparc/linux64.h (CC1_SPEC): Preserve CPU specified by
        the user if using the non-default arch size in BI_ARCH configuration.
        * config/sparc/sol2-sld-64.h (CC1_SPEC): Ditto.

        * config/sparc/sparc.md (cmp_mul_set, cmp_udiv_cc_set):
        Fix patterns so that they actually match.
        (cmp_sdiv_cc_set): Ditto, also don't require g0 to be zero.
        (mulsidi3_sp64, const_mulsidi3_sp64): New patterns.
        (const_mulsidi3_sp32): Renamed from const_mulsidi3, only on
        TARGET_HARD_MUL32.
        (mulsidi3): Reflect this in the expand.
        (smulsi3_highpart): Only on TARGET_ARCH32.
        (umulsidi3_sp64, const_umulsidi3_sp64): New patterns.
        (const_umulsidi3_sp32): Renamed from const_umulsidi3.
        (umulsidi3): Reflect this in the expand.
        (umulsi3_highpart): Only on TARGET_ARCH32.
        (divsi3_sp32): Renamed from divsi3, only on TARGET_ARCH32,
        don't require g0 to be zero.
        (udivsi3_sp32): Renamed from udivsi3, only on TARGET_ARCH32.
        ({,u}divsi3): New expands.
        ({,u}divsi3_sp64): New patterns.
        (after lshrdi3_v8plus): Four new patterns to help combiner
        optimizing nested mixed mode shifts.

        * config/sparc/sparc.c (sparc_override_options): Use deprecated
        v8 instructions if optimizing for UltraSPARC I, II, IIi, as it
        speed things up. Don't use them by default on plain v9 in 64bit
        mode, according to what SPAMv9 sais.

        * config/sparc/sparc.h: Fix comments, e.g. Linux already preserves
        top 32 bits of %[og][0-7] in signal handlers.
        Also, TARGET_HARD_MUL32 now is only true for TARGET_ARCH32.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@28346 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/config/sparc/linux64.h
gcc/config/sparc/sol2-sld-64.h
gcc/config/sparc/sparc.c
gcc/config/sparc/sparc.h
gcc/config/sparc/sparc.md

index 3f88c97..ff7ea74 100644 (file)
@@ -1,3 +1,38 @@
+Fri Jul 30 14:53:56 1999  Jakub Jelinek  <jj@ultra.linux.cz>
+
+       * config/sparc/linux64.h (CC1_SPEC): Preserve CPU specified by
+       the user if using the non-default arch size in BI_ARCH configuration.
+       * config/sparc/sol2-sld-64.h (CC1_SPEC): Ditto.
+
+       * config/sparc/sparc.md (cmp_mul_set, cmp_udiv_cc_set):
+       Fix patterns so that they actually match.
+       (cmp_sdiv_cc_set): Ditto, also don't require g0 to be zero.
+       (mulsidi3_sp64, const_mulsidi3_sp64): New patterns.
+       (const_mulsidi3_sp32): Renamed from const_mulsidi3, only on
+       TARGET_HARD_MUL32.
+       (mulsidi3): Reflect this in the expand.
+       (smulsi3_highpart): Only on TARGET_ARCH32.
+       (umulsidi3_sp64, const_umulsidi3_sp64): New patterns.
+       (const_umulsidi3_sp32): Renamed from const_umulsidi3.
+       (umulsidi3): Reflect this in the expand.
+       (umulsi3_highpart): Only on TARGET_ARCH32.
+       (divsi3_sp32): Renamed from divsi3, only on TARGET_ARCH32,
+       don't require g0 to be zero.
+       (udivsi3_sp32): Renamed from udivsi3, only on TARGET_ARCH32.
+       ({,u}divsi3): New expands.
+       ({,u}divsi3_sp64): New patterns.
+       (after lshrdi3_v8plus): Four new patterns to help combiner
+       optimizing nested mixed mode shifts.
+
+       * config/sparc/sparc.c (sparc_override_options): Use deprecated
+       v8 instructions if optimizing for UltraSPARC I, II, IIi, as it
+       speed things up. Don't use them by default on plain v9 in 64bit
+       mode, according to what SPAMv9 sais.
+
+       * config/sparc/sparc.h: Fix comments, e.g. Linux already preserves
+       top 32 bits of %[og][0-7] in signal handlers.
+       Also, TARGET_HARD_MUL32 now is only true for TARGET_ARCH32.
+
 Fri Jul 30 03:00:41 1999  Jeffrey A Law  (law@cygnus.com)
 
        * pa.md (zvdep_imm32): Renamed from zvdep_imm.
index a1a32dd..cc01c76 100644 (file)
@@ -225,7 +225,8 @@ Boston, MA 02111-1307, USA.  */
 %{mcypress:-mcpu=cypress} \
 %{msparclite:-mcpu=sparclite} %{mf930:-mcpu=f930} %{mf934:-mcpu=f934} \
 %{mv8:-mcpu=v8} %{msupersparc:-mcpu=supersparc} \
-%{m64:-mptr64 -mcpu=ultrasparc -mstack-bias} \
+%{m64:-mptr64 -mstack-bias \
+  %{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:-mcpu=ultrasparc}}}}}}}} \
 "
 #else
 #define CC1_SPEC "\
@@ -233,7 +234,8 @@ Boston, MA 02111-1307, USA.  */
 %{mcypress:-mcpu=cypress} \
 %{msparclite:-mcpu=sparclite} %{mf930:-mcpu=f930} %{mf934:-mcpu=f934} \
 %{mv8:-mcpu=v8} %{msupersparc:-mcpu=supersparc} \
-%{m32:-mptr32 -mcpu=cypress -mno-stack-bias} \
+%{m32:-mptr32 -mno-stack-bias \
+  %{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:-mcpu=cypress}}}}}}}} \
 "
 #endif
 
index c2518d8..aa107a8 100644 (file)
 %{mcypress:-mcpu=cypress} \
 %{msparclite:-mcpu=sparclite} %{mf930:-mcpu=f930} %{mf934:-mcpu=f934} \
 %{mv8:-mcpu=v8} %{msupersparc:-mcpu=supersparc} \
-%{m64:-mptr64 -mcpu=v9 -mstack-bias -mno-v8plus} \
+%{m64:-mptr64 -mstack-bias -mno-v8plus \
+  %{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8*:%{!msupersparc:-mcpu=v9}}}}}}}} \
 "
 #else
 #define CC1_SPEC "\
 %{mcypress:-mcpu=cypress} \
 %{msparclite:-mcpu=sparclite} %{mf930:-mcpu=f930} %{mf934:-mcpu=f934} \
 %{mv8:-mcpu=v8} %{msupersparc:-mcpu=supersparc} \
-%{m32:-mptr32 -mcpu=cypress -mno-stack-bias} \
-%{mv8plus:-m32 -mptr32 -mcpu=cypress -mno-stack-bias} \
+%{m32:-mptr32 -mno-stack-bias \
+  %{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8*:%{!msupersparc:-mcpu=cypress}}}}}}}} \
+%{mv8plus:-m32 -mptr32 -mno-stack-bias \
+  %{!mcpu*:%{!mcypress:%{!msparclite:%{!mf930:%{!mf934:%{!mv8:%{!msupersparc:-mcpu=v9}}}}}}}} \
 "
 #endif
 
index da57564..78a198b 100644 (file)
@@ -213,8 +213,11 @@ sparc_override_options ()
     /* TEMIC sparclet */
     { "tsc701",     PROCESSOR_TSC701, MASK_ISA, MASK_SPARCLET },
     { "v9",         PROCESSOR_V9, MASK_ISA, MASK_V9 },
-    /* TI ultrasparc */
-    { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9 },
+    /* TI ultrasparc I, II, IIi */
+    { "ultrasparc", PROCESSOR_ULTRASPARC, MASK_ISA, MASK_V9
+    /* Although insns using %y are deprecated, it is a clear win on current
+       ultrasparcs. */
+                                                   |MASK_DEPRECATED_V8_INSNS },
     { 0, 0, 0, 0 }
   };
   struct cpu_table *cpu;
index 52f911a..2933a38 100644 (file)
@@ -50,11 +50,11 @@ Boston, MA 02111-1307, USA.  */
 
 /* Code model selection.
    -mcmodel is used to select the v9 code model.
-   Different code models aren't supported for v8 code.
+   Different code models aren't supported for v7/8 code.
 
    TARGET_CM_32:     32 bit address space, top 32 bits = 0,
                     pointers are 32 bits.  Note that this isn't intended
-                     to imply a v8 abi.
+                     to imply a v7/8 abi.
 
    TARGET_CM_MEDLOW: 32 bit address space, top 32 bits = 0,
                      avoid generating %uhi and %ulo terms,
@@ -542,9 +542,8 @@ extern int target_flags;
 #define TARGET_VIS (target_flags & MASK_VIS)
 
 /* Compile for Solaris V8+.  32 bit Solaris preserves the high bits of
-   the current out and global registers.  Linux saves the high bits on
-   context switches but not signals.  */
-#define MASK_V8PLUS 0x2000000                 
+   the current out and global registers and Linux 2.2+ as well.  */
+#define MASK_V8PLUS 0x2000000
 #define TARGET_V8PLUS (target_flags & MASK_V8PLUS)                            
 
 /* TARGET_HARD_MUL: Use hardware multiply instructions but not %y.
@@ -555,7 +554,7 @@ extern int target_flags;
 #define TARGET_HARD_MUL32                              \
   ((TARGET_V8 || TARGET_SPARCLITE                      \
     || TARGET_SPARCLET || TARGET_DEPRECATED_V8_INSNS)  \
-   && ! TARGET_V8PLUS)
+   && ! TARGET_V8PLUS && TARGET_ARCH32)
 
 #define TARGET_HARD_MUL                                        \
   (TARGET_V8 || TARGET_SPARCLITE || TARGET_SPARCLET    \
index 02170b7..34e311f 100644 (file)
 \f
 ;; Integer Multiply/Divide.
 
-;; The 32 bit multiply/divide instructions are deprecated on v9 and shouldn't
-;; we used.  We still use them in 32 bit v9 compilers.
-;; The 64 bit v9 compiler will (/should) widen the args and use muldi3.
+;; The 32 bit multiply/divide instructions are deprecated on v9, but at
+;; least in UltraSPARC I, II and IIi it is a win tick-wise.
 
 (define_insn "mulsi3"
   [(set (match_operand:SI 0 "register_operand" "=r")
 }"
   [(set_attr "length" "9,8")])
 
-;; It is not known whether this will match.
-
 (define_insn "*cmp_mul_set"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (mult:SI (match_operand:SI 1 "arith_operand" "%r")
-                (match_operand:SI 2 "arith_operand" "rI")))
-   (set (reg:CC_NOOV 100)
-       (compare:CC_NOOV (mult:SI (match_dup 1) (match_dup 2))
-                        (const_int 0)))]
+  [(set (reg:CC 100)
+       (compare:CC (mult:SI (match_operand:SI 1 "arith_operand" "%r")
+                   (match_operand:SI 2 "arith_operand" "rI"))
+                   (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=r")
+       (mult:SI (match_dup 1) (match_dup 2)))]
   "TARGET_V8 || TARGET_SPARCLITE || TARGET_DEPRECATED_V8_INSNS"
   "smulcc\\t%1, %2, %0"
   [(set_attr "type" "imul")
   if (CONSTANT_P (operands[2]))
     {
       if (TARGET_V8PLUS)
-       {
-         emit_insn (gen_const_mulsidi3_v8plus (operands[0], operands[1],
-                                               operands[2]));
-         DONE;
-       }
-      emit_insn (gen_const_mulsidi3 (operands[0], operands[1], operands[2]));
+       emit_insn (gen_const_mulsidi3_v8plus (operands[0], operands[1],
+                                             operands[2]));
+      else
+       emit_insn (gen_const_mulsidi3_sp32 (operands[0], operands[1],
+                                           operands[2]));
       DONE;
     }
   if (TARGET_V8PLUS)
        (if_then_else (eq_attr "isa" "sparclet")
                      (const_int 1) (const_int 2)))])
 
+(define_insn "*mulsidi3_sp64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                (sign_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+  "TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
+  "smul\\t%1, %2, %0"
+  [(set_attr "length" "1")])
+
 ;; Extra pattern, because sign_extend of a constant isn't valid.
 
 ;; XXX
-(define_insn "const_mulsidi3"
+(define_insn "const_mulsidi3_sp32"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
                 (match_operand:SI 2 "small_int" "I")))]
-  "TARGET_HARD_MUL"
+  "TARGET_HARD_MUL32"
   "*
 {
   return TARGET_SPARCLET ? \"smuld\\t%1, %2, %L0\" : \"smul\\t%1, %2, %L0\\n\\trd\\t%%y, %H0\";
        (if_then_else (eq_attr "isa" "sparclet")
                      (const_int 1) (const_int 2)))])
 
+(define_insn "const_mulsidi3_sp64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                (match_operand:SI 2 "small_int" "I")))]
+  "TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
+  "smul\\t%1, %2, %0"
+  [(set_attr "length" "1")])
+
 (define_expand "smulsi3_highpart"
   [(set (match_operand:SI 0 "register_operand" "")
        (truncate:SI
         (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" ""))
                               (sign_extend:DI (match_operand:SI 2 "arith_operand" "")))
                      (const_int 32))))]
-  "TARGET_HARD_MUL"
+  "TARGET_HARD_MUL && TARGET_ARCH32"
   "
 {
   if (CONSTANT_P (operands[2]))
         (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
                               (sign_extend:DI (match_operand:SI 2 "register_operand" "r")))
                      (const_int 32))))]
-  "TARGET_HARD_MUL32
-   && ! TARGET_LIVE_G0"
+  "TARGET_HARD_MUL32 && ! TARGET_LIVE_G0"
   "smul\\t%1, %2, %%g0\\n\\trd\\t%%y, %0"
   [(set_attr "length" "2")])
 
         (lshiftrt:DI (mult:DI (sign_extend:DI (match_operand:SI 1 "register_operand" "r"))
                               (match_operand:SI 2 "register_operand" "r"))
                      (const_int 32))))]
-  "TARGET_HARD_MUL32
-   && ! TARGET_LIVE_G0"
+  "TARGET_HARD_MUL32 && ! TARGET_LIVE_G0"
   "smul\\t%1, %2, %%g0\\n\\trd\\t%%y, %0"
   [(set_attr "length" "2")])
 
   if (CONSTANT_P (operands[2]))
     {
       if (TARGET_V8PLUS)
-       {
-         emit_insn (gen_const_umulsidi3_v8plus (operands[0], operands[1],
-                                                operands[2]));
-         DONE;
-       }
-      emit_insn (gen_const_umulsidi3 (operands[0], operands[1], operands[2]));
+       emit_insn (gen_const_umulsidi3_v8plus (operands[0], operands[1],
+                                              operands[2]));
+      else
+       emit_insn (gen_const_umulsidi3_sp32 (operands[0], operands[1],
+                                            operands[2]));
       DONE;
     }
   if (TARGET_V8PLUS)
        (if_then_else (eq_attr "isa" "sparclet")
                      (const_int 1) (const_int 2)))])
 
+(define_insn "*umulsidi3_sp64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                (zero_extend:DI (match_operand:SI 2 "register_operand" "r"))))]
+  "TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
+  "umul\\t%1, %2, %0"
+  [(set_attr "length" "1")])
+
 ;; Extra pattern, because sign_extend of a constant isn't valid.
 
 ;; XXX
-(define_insn "const_umulsidi3"
+(define_insn "const_umulsidi3_sp32"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
                 (match_operand:SI 2 "uns_small_int" "")))]
        (if_then_else (eq_attr "isa" "sparclet")
                      (const_int 1) (const_int 2)))])
 
+(define_insn "const_umulsidi3_sp64"
+  [(set (match_operand:DI 0 "register_operand" "=r")
+       (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
+                (match_operand:SI 2 "uns_small_int" "")))]
+  "TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
+  "umul\\t%1, %2, %0"
+  [(set_attr "length" "1")])
+
 ;; XXX
 (define_insn "const_umulsidi3_v8plus"
   [(set (match_operand:DI 0 "register_operand" "=h,r")
         (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" ""))
                               (zero_extend:DI (match_operand:SI 2 "uns_arith_operand" "")))
                      (const_int 32))))]
-  "TARGET_HARD_MUL"
+  "TARGET_HARD_MUL && TARGET_ARCH32"
   "
 {
   if (CONSTANT_P (operands[2]))
         (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
                               (zero_extend:DI (match_operand:SI 2 "register_operand" "r")))
                      (const_int 32))))]
-  "TARGET_HARD_MUL32
-   && ! TARGET_LIVE_G0"
+  "TARGET_HARD_MUL32 && ! TARGET_LIVE_G0"
   "umul\\t%1, %2, %%g0\\n\\trd\\t%%y, %0"
   [(set_attr "length" "2")])
 
         (lshiftrt:DI (mult:DI (zero_extend:DI (match_operand:SI 1 "register_operand" "r"))
                               (match_operand:SI 2 "uns_small_int" ""))
                      (const_int 32))))]
-  "TARGET_HARD_MUL32
-   && ! TARGET_LIVE_G0"
+  "TARGET_HARD_MUL32 && ! TARGET_LIVE_G0"
   "umul\\t%1, %2, %%g0\\n\\trd\\t%%y, %0"
   [(set_attr "length" "2")])
 
 ;; The v8 architecture specifies that there must be 3 instructions between
 ;; a y register write and a use of it for correct results.
 
-;; XXX SHEESH
-(define_insn "divsi3"
+(define_expand "divsi3"
+  [(parallel [(set (match_operand:SI 0 "register_operand" "=r,r")
+                  (div:SI (match_operand:SI 1 "register_operand" "r,r")
+                          (match_operand:SI 2 "input_operand" "rI,m")))
+             (clobber (match_scratch:SI 3 "=&r,&r"))])]
+  "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
+  "
+{
+  if (TARGET_ARCH64)
+    {
+      operands[3] = gen_reg_rtx(SImode);
+      emit_insn (gen_ashrsi3 (operands[3], operands[1], GEN_INT (31)));
+      emit_insn (gen_divsi3_sp64 (operands[0], operands[1], operands[2],
+                                 operands[3]));
+      DONE;
+    }
+}")
+
+(define_insn "divsi3_sp32"
   [(set (match_operand:SI 0 "register_operand" "=r,r")
        (div:SI (match_operand:SI 1 "register_operand" "r,r")
                (match_operand:SI 2 "input_operand" "rI,m")))
    (clobber (match_scratch:SI 3 "=&r,&r"))]
-  "(TARGET_V8
-    || TARGET_DEPRECATED_V8_INSNS)
-   && ! TARGET_LIVE_G0"
+  "(TARGET_V8 || TARGET_DEPRECATED_V8_INSNS)
+   && TARGET_ARCH32"
   "*
 {
   if (which_alternative == 0)
-  if (TARGET_V9)
-    return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tsdiv\\t%1, %2, %0\";
-  else
-    return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tnop\\n\\tnop\\n\\tnop\\n\\tsdiv\\t%1, %2, %0\";
+    if (TARGET_V9)
+      return \"sra\\t%1, 31, %3\\n\\twr\\t%3, 0, %%y\\n\\tsdiv\\t%1, %2, %0\";
+    else
+      return \"sra\\t%1, 31, %3\\n\\twr\\t%3, 0, %%y\\n\\tnop\\n\\tnop\\n\\tnop\\n\\tsdiv\\t%1, %2, %0\";
   else
     if (TARGET_V9)
-      return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tld\\t%2, %3\\n\\tsdiv\\t%1, %3, %0\";
+      return \"sra\\t%1, 31, %3\\n\\twr\\t%3, 0, %%y\\n\\tld\\t%2, %3\\n\\tsdiv\\t%1, %3, %0\";
     else
-      return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tld\\t%2, %3\\n\\tnop\\n\\tnop\\n\\tsdiv\\t%1, %3, %0\";
+      return \"sra\\t%1, 31, %3\\n\\twr\\t%3, 0, %%y\\n\\tld\\t%2, %3\\n\\tnop\\n\\tnop\\n\\tsdiv\\t%1, %3, %0\";
 }"
   [(set (attr "length")
        (if_then_else (eq_attr "isa" "v9")
                      (const_int 4) (const_int 7)))])
 
+(define_insn "divsi3_sp64"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (div:SI (match_operand:SI 1 "register_operand" "r")
+               (match_operand:SI 2 "input_operand" "rI")))
+   (use (match_operand:SI 3 "register_operand" "r"))]
+  "TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
+  "wr\\t%%g0, %3, %%y\\n\\tsdiv\\t%1, %2, %0"
+  [(set_attr "length" "2")])
+
 (define_insn "divdi3"
   [(set (match_operand:DI 0 "register_operand" "=r")
        (div:DI (match_operand:DI 1 "register_operand" "r")
   "TARGET_ARCH64"
   "sdivx\\t%1, %2, %0")
 
-;; It is not known whether this will match.
-
-;; XXX I hope it doesn't fucking match...
 (define_insn "*cmp_sdiv_cc_set"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (div:SI (match_operand:SI 1 "register_operand" "r")
-               (match_operand:SI 2 "arith_operand" "rI")))
-   (set (reg:CC 100)
-       (compare:CC (div:SI (match_dup 1) (match_dup 2))
+  [(set (reg:CC 100)
+       (compare:CC (div:SI (match_operand:SI 1 "register_operand" "r")
+                           (match_operand:SI 2 "arith_operand" "rI"))
                    (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=r")
+       (div:SI (match_dup 1) (match_dup 2)))
    (clobber (match_scratch:SI 3 "=&r"))]
-  "(TARGET_V8
-    || TARGET_DEPRECATED_V8_INSNS)
-   && ! TARGET_LIVE_G0"
+  "TARGET_V8 || TARGET_DEPRECATED_V8_INSNS"
   "*
 {
   if (TARGET_V9)
-    return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tsdivcc\\t%1, %2, %0\";
+    return \"sra\\t%1, 31, %3\\n\\twr\\t%3, 0, %%y\\n\\tsdivcc\\t%1, %2, %0\";
   else
-    return \"sra\\t%1, 31, %3\\n\\twr\\t%%g0, %3, %%y\\n\\tnop\\n\\tnop\\n\\tnop\\n\\tsdivcc\\t%1, %2, %0\";
+    return \"sra\\t%1, 31, %3\\n\\twr\\t%3, 0, %%y\\n\\tnop\\n\\tnop\\n\\tnop\\n\\tsdivcc\\t%1, %2, %0\";
 }"
   [(set (attr "length")
        (if_then_else (eq_attr "isa" "v9")
                      (const_int 3) (const_int 6)))])
 
 ;; XXX
-(define_insn "udivsi3"
+(define_expand "udivsi3"
+  [(set (match_operand:SI 0 "register_operand" "")
+       (udiv:SI (match_operand:SI 1 "reg_or_nonsymb_mem_operand" "")
+                (match_operand:SI 2 "input_operand" "")))]
+  "(TARGET_V8 || TARGET_DEPRECATED_V8_INSNS) && ! TARGET_LIVE_G0"
+  "")
+
+(define_insn "udivsi3_sp32"
   [(set (match_operand:SI 0 "register_operand" "=r,&r,&r")
        (udiv:SI (match_operand:SI 1 "reg_or_nonsymb_mem_operand" "r,r,m")
                 (match_operand:SI 2 "input_operand" "rI,m,r")))]
   "(TARGET_V8
     || TARGET_DEPRECATED_V8_INSNS)
-   && ! TARGET_LIVE_G0"
+   && TARGET_ARCH32 && ! TARGET_LIVE_G0"
   "*
 {
   output_asm_insn (\"wr\\t%%g0, %%g0, %%y\", operands);
   switch (which_alternative)
     {
     default:
-  if (TARGET_V9)
-       return \"udiv\\t%1, %2, %0\";
       return \"nop\\n\\tnop\\n\\tnop\\n\\tudiv\\t%1, %2, %0\";
     case 1:
       return \"ld\\t%2, %0\\n\\tnop\\n\\tnop\\n\\tudiv\\t%1, %0, %0\";
       return \"ld\\t%1, %0\\n\\tnop\\n\\tnop\\n\\tudiv\\t%0, %2, %0\";
     }
 }"
-  [(set (attr "length")
-       (if_then_else (and (eq_attr "isa" "v9")
-                          (eq_attr "alternative" "0"))
-                     (const_int 2) (const_int 5)))])
+  [(set_attr "length" "5")])
+
+(define_insn "udivsi3_sp64"
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (udiv:SI (match_operand:SI 1 "reg_or_nonsymb_mem_operand" "r")
+                (match_operand:SI 2 "input_operand" "rI")))]
+  "TARGET_DEPRECATED_V8_INSNS && TARGET_ARCH64"
+  "wr\\t%%g0, 0, %%y\\n\\tudiv\\t%1, %2, %0"
+  [(set_attr "length" "2")])
 
 (define_insn "udivdi3"
   [(set (match_operand:DI 0 "register_operand" "=r")
   "TARGET_ARCH64"
   "udivx\\t%1, %2, %0")
 
-;; It is not known whether this will match.
-
-;; XXX I hope it doesn't fucking match...
 (define_insn "*cmp_udiv_cc_set"
-  [(set (match_operand:SI 0 "register_operand" "=r")
-       (udiv:SI (match_operand:SI 1 "register_operand" "r")
-               (match_operand:SI 2 "arith_operand" "rI")))
-   (set (reg:CC 100)
-       (compare:CC (udiv:SI (match_dup 1) (match_dup 2))
-                   (const_int 0)))]
+  [(set (reg:CC 100)
+       (compare:CC (udiv:SI (match_operand:SI 1 "register_operand" "r")
+                            (match_operand:SI 2 "arith_operand" "rI"))
+                   (const_int 0)))
+   (set (match_operand:SI 0 "register_operand" "=r")
+       (udiv:SI (match_dup 1) (match_dup 2)))]
   "(TARGET_V8
     || TARGET_DEPRECATED_V8_INSNS)
    && ! TARGET_LIVE_G0"
   "TARGET_V8PLUS"
   "*return sparc_v8plus_shift (operands, insn, \"srlx\");"
   [(set_attr "length" "5,5,6")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ashiftrt:SI (subreg:SI (lshiftrt:DI (match_operand:DI 1 "register_operand" "r")
+                                            (const_int 32)) 0)
+                    (match_operand:SI 2 "small_int_or_double" "n")))]
+  "TARGET_ARCH64
+   && ((GET_CODE (operands[2]) == CONST_INT
+        && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 32)
+       || (GET_CODE (operands[2]) == CONST_DOUBLE
+          && !CONST_DOUBLE_HIGH (operands[2])
+           && (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (operands[2]) < 32))"
+  "*
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) + 32);
+
+  return \"srax\\t%1, %2, %0\";
+}"
+  [(set_attr "type" "shift")
+   (set_attr "length" "1")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (lshiftrt:SI (subreg:SI (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
+                                            (const_int 32)) 0)
+                    (match_operand:SI 2 "small_int_or_double" "n")))]
+  "TARGET_ARCH64
+   && ((GET_CODE (operands[2]) == CONST_INT
+        && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) < 32)
+       || (GET_CODE (operands[2]) == CONST_DOUBLE
+          && !CONST_DOUBLE_HIGH (operands[2])
+           && (unsigned HOST_WIDE_INT) CONST_DOUBLE_LOW (operands[2]) < 32))"
+  "*
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) + 32);
+
+  return \"srlx\\t%1, %2, %0\";
+}"
+  [(set_attr "type" "shift")
+   (set_attr "length" "1")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (ashiftrt:SI (subreg:SI (ashiftrt:DI (match_operand:DI 1 "register_operand" "r")
+                                            (match_operand:SI 2 "small_int_or_double" "n")) 0)
+                    (match_operand:SI 3 "small_int_or_double" "n")))]
+  "TARGET_ARCH64
+   && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[3]) == CONST_INT
+   && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 32
+   && (unsigned HOST_WIDE_INT) INTVAL (operands[3]) < 32
+   && (unsigned HOST_WIDE_INT) (INTVAL (operands[2]) + INTVAL (operands[3])) < 64"
+  "*
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]));
+
+  return \"srax\\t%1, %2, %0\";
+}"
+  [(set_attr "type" "shift")
+   (set_attr "length" "1")])
+
+(define_insn ""
+  [(set (match_operand:SI 0 "register_operand" "=r")
+       (lshiftrt:SI (subreg:SI (lshiftrt:DI (match_operand:DI 1 "register_operand" "r")
+                                            (match_operand:SI 2 "small_int_or_double" "n")) 0)
+                    (match_operand:SI 3 "small_int_or_double" "n")))]
+  "TARGET_ARCH64
+   && GET_CODE (operands[2]) == CONST_INT && GET_CODE (operands[3]) == CONST_INT
+   && (unsigned HOST_WIDE_INT) INTVAL (operands[2]) >= 32
+   && (unsigned HOST_WIDE_INT) INTVAL (operands[3]) < 32
+   && (unsigned HOST_WIDE_INT) (INTVAL (operands[2]) + INTVAL (operands[3])) < 64"
+  "*
+{
+  operands[2] = GEN_INT (INTVAL (operands[2]) + INTVAL (operands[3]));
+
+  return \"srlx\\t%1, %2, %0\";
+}"
+  [(set_attr "type" "shift")
+   (set_attr "length" "1")])
 \f
 ;; Unconditional and other jump instructions
 ;; On the Sparc, by setting the annul bit on an unconditional branch, the