Jakub Jelinek <jj@ultra.linux.cz>
authorJakub Jelinek <jj@ultra.linux.cz>
Fri, 30 Jul 1999 21:55:06 +0000 (23:55 +0200)
committerRichard Henderson <rth@gcc.gnu.org>
Fri, 30 Jul 1999 21:55:06 +0000 (14:55 -0700)
        * 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.

From-SVN: r28346

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 3f88c97ec2461d10520e0eda9621e895e317f50b..ff7ea7405beb9948a9f20b5444a489c35e1f9762 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 a1a32dd7a3720e6c9b74f5a72d700b0093ad3f10..cc01c76510ca16e1855be1bfd00f73d53ca03427 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 c2518d8def0b50afbe3097282126b86f11808c44..aa107a8b9e4bcfb5563e3a0fcea6474c3194dd56 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 da575641f07d5ac770d6601bbd19a5a74e8cf0fd..78a198ba98c91248725faf64071a77538e52fe3d 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 52f911a5245522a52fa51a9c7d5d9025d4088b13..2933a38ee28093fe8408535c97aa952a3bcf6bf2 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 02170b75fca8a644a1d65a859701e1d3720d2006..34e311f162010d225c1314ef9dc331fe9fb6cfed 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