(divmodsi4, udivsi3, divsi3, udivmodsi4): Add AIX common-mode cases.
authorRichard Kenner <kenner@gcc.gnu.org>
Fri, 18 Mar 1994 22:52:27 +0000 (17:52 -0500)
committerRichard Kenner <kenner@gcc.gnu.org>
Fri, 18 Mar 1994 22:52:27 +0000 (17:52 -0500)
(mulh_call, mull_call, divss_call, divus_call, quoss_call, quous_call):
AIX common-mode call patterns.
(ashlsi3): More TARGET_POWERPC to ! TARGET_POWER changes.
(addsf3, subsf3, mulsf3, divsf3, etc.): Change TARGET_POWER
to ! TARGET_POWERPC.
(fix_truncdfsi2): Use POWER/2 and PowerPC FP convert instruction.
(fpcvtsi): New pattern.
(mulsidi3): Add AIX common-mode case, add imul attribute to POWER
pattern, add PowerPC pattern, flag input operands as commutative.
(smulsi3_highpart): Add AIX common-mode case.
(movsi matcher): Add mtjmpr attribute to ! TARGET_POWER case.
(movsf): Clean up load from memory or integer register test.
(movdi matcher): Add FP register support.
(smulsi3_highpart): New patterns.
(umulsi3_highpart_power): New pattern.

From-SVN: r6816

gcc/config/rs6000/rs6000.md

index aa55d33..316c7be 100644 (file)
 ;; 0 and remainder to operand 3.
 ;; ??? At some point, see what, if anything, we can do about if (x % y == 0).
 
-(define_insn "divmodsi4"
+(define_expand "divmodsi4"
+  [(parallel [(set (match_operand:SI 0 "gpc_reg_operand" "")
+                  (div:SI (match_operand:SI 1 "gpc_reg_operand" "")
+                          (match_operand:SI 2 "gpc_reg_operand" "")))
+             (set (match_operand:SI 3 "gpc_reg_operand" "")
+                  (mod:SI (match_dup 1) (match_dup 2)))])]
+  "TARGET_POWER || (! TARGET_POWER && ! TARGET_POWERPC)"
+  "
+{
+  if (! TARGET_POWER && ! TARGET_POWERPC)
+    {
+      emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+      emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+      emit_insn (gen_divss_call ());
+      emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+      emit_move_insn (operands[3], gen_rtx (REG, SImode, 4));
+      DONE;
+    }
+}")
+(define_insn ""
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (div:SI (match_operand:SI 1 "gpc_reg_operand" "r")
                (match_operand:SI 2 "gpc_reg_operand" "r")))
   "divw %0, %1, %2"
   [(set_attr "type" "idiv")])
 
-(define_insn "udivsi3"
+(define_expand "udivsi3"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+        (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "")
+                 (match_operand:SI 2 "gpc_reg_operand" "")))]
+  "TARGET_POWERPC || (! TARGET_POWER && ! TARGET_POWERPC)"
+  "
+{
+  if (! TARGET_POWER && ! TARGET_POWERPC)
+    {
+      emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+      emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+      emit_insn (gen_quous_call ());
+      emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+      DONE;
+    }
+}")
+(define_insn ""
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
         (udiv:SI (match_operand:SI 1 "gpc_reg_operand" "r")
                  (match_operand:SI 2 "gpc_reg_operand" "r")))]
 
 ;; For powers of two we can do srai/aze for divide and then adjust for
 ;; modulus.  If it isn't a power of two, FAIL on POWER so divmodsi4 will be
-;; used; for PowerPC, force operands into register and do a normal divide.
+;; used; for PowerPC, force operands into register and do a normal divide;
+;; for AIX common-mode, use quoss call on register operands.
 (define_expand "divsi3"
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
        (div:SI (match_operand:SI 1 "gpc_reg_operand" "")
   if (GET_CODE (operands[2]) == CONST_INT
       && exact_log2 (INTVAL (operands[2])) >= 0)
     ;
-  else if (! TARGET_POWERPC)
+  else if (TARGET_POWER && ! TARGET_POWERPC)
     FAIL;
   else
     operands[2] = force_reg (SImode, operands[2]);
+  if (! TARGET_POWER && ! TARGET_POWERPC)
+    {
+      emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+      emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+      emit_insn (gen_quoss_call ());
+      emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+      DONE;
+    }
 }")
 
 (define_expand "modsi3"
   emit_insn (gen_ashlsi3 (temp2, temp1, GEN_INT (i)));
   emit_insn (gen_subsi3 (operands[0], operands[1], temp2));
   DONE;
-
 }")
 
 (define_insn ""
                            (match_operand:SI 2 "reg_or_cint_operand" "")))
              (set (match_operand:SI 3 "gpc_reg_operand" "")
                   (umod:SI (match_dup 1) (match_dup 2)))])]
-  "TARGET_POWER"
+  ""
   "
 {
   rtx label = 0;
 
+  if (! TARGET_POWER)
+    if (! TARGET_POWERPC)
+      {
+       emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+       emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+       emit_insn (gen_divus_call ());
+       emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+       emit_move_insn (operands[3], gen_rtx (REG, SImode, 4));
+       DONE;
+      }
+    else
+      FAIL;
   if (GET_CODE (operands[2]) != CONST_INT || INTVAL (operands[2]) < 0)
     {
       operands[2] = force_reg (SImode, operands[2]);
 
   DONE;
 }")
-    
+;; AIX architecture-independent common-mode multiply (DImode),
+;; divide/modulus, and quotient subroutine calls.  Input operands in R3 and
+;; R4; results in R3 and somtimes R4; link register always clobbered by bla
+;; instruction; R0 sometimes clobbered; also, MQ sometimes clobbered but
+;; assumed unused if generating common-mode, so ignore.
+(define_insn "mulh_call"
+  [(set (reg:SI 3)
+       (truncate:SI
+        (lshiftrt:DI (mult:DI (sign_extend:DI (reg:SI 3))
+                              (sign_extend:DI (reg:SI 4)))
+                     (const_int 32))))
+   (clobber (match_scratch:SI 0 "=l"))]
+  "! TARGET_POWER && ! TARGET_POWERPC"
+  "bla __mulh")
+(define_insn "mull_call"
+  [(set (reg:DI 3)
+       (mult:DI (sign_extend:DI (reg:SI 3))
+                (sign_extend:DI (reg:SI 4))))
+   (clobber (match_scratch:SI 0 "=l"))
+   (clobber (reg:SI 0))]
+  "! TARGET_POWER && ! TARGET_POWERPC"
+  "bla __mull")
+(define_insn "divss_call"
+  [(set (reg:SI 3)
+       (div:SI (reg:SI 3) (reg:SI 4)))
+   (set (reg:SI 4)
+       (mod:SI (reg:SI 3) (reg:SI 4)))
+   (clobber (match_scratch:SI 0 "=l"))
+   (clobber (reg:SI 0))]
+  "! TARGET_POWER && ! TARGET_POWERPC"
+  "bla __divss")
+(define_insn "divus_call"
+  [(set (reg:SI 3)
+       (udiv:SI (reg:SI 3) (reg:SI 4)))
+   (set (reg:SI 4)
+       (umod:SI (reg:SI 3) (reg:SI 4)))
+   (clobber (match_scratch:SI 0 "=l"))
+   (clobber (reg:SI 0))]
+  "! TARGET_POWER && ! TARGET_POWERPC"
+  "bla __divus")
+(define_insn "quoss_call"
+  [(set (reg:SI 3)
+       (div:SI (reg:SI 3) (reg:SI 4)))
+   (clobber (match_scratch:SI 0 "=l"))]
+  "! TARGET_POWER && ! TARGET_POWERPC"
+  "bla __quoss")
+(define_insn "quous_call"
+  [(set (reg:SI 3)
+       (udiv:SI (reg:SI 3) (reg:SI 4)))
+   (clobber (match_scratch:SI 0 "=l"))
+   (clobber (reg:SI 0))]
+  "! TARGET_POWER && ! TARGET_POWERPC"
+  "bla __quous")
+\f
 (define_insn "andsi3"
   [(set (match_operand:SI 0 "gpc_reg_operand" "=r,r,r,r")
        (and:SI (match_operand:SI 1 "gpc_reg_operand" "%r,r,r,r")
                               (match_operand:SI 2 "reg_or_cint_operand" "ri"))
                    (const_int 0)))
    (clobber (match_scratch:SI 3 "=r"))]
-  "TARGET_POWERPC"
+  "! TARGET_POWER"
   "slw%I2. %3,%1,%2"
   [(set_attr "type" "delayed_compare")])
 
                    (const_int 0)))
    (set (match_operand:SI 0 "gpc_reg_operand" "=r")
        (ashift:SI (match_dup 1) (match_dup 2)))]
-  "TARGET_POWERPC"
+  "! TARGET_POWER"
   "slw%I2. %0,%1,%2"
   [(set_attr "type" "delayed_compare")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (plus:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                 (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "TARGET_POWER"
+  "! TARGET_POWERPC"
   "{fa|fadd} %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (minus:SF (match_operand:SF 1 "gpc_reg_operand" "f")
                  (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "TARGET_POWER"
+  "! TARGET_POWERPC"
   "{fs|fsub} %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                 (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "TARGET_POWER"
+  "! TARGET_POWERPC"
   "{fm|fmul} %0,%1,%2"
   [(set_attr "type" "fp")])
 
   [(set (match_operand:SF 0 "gpc_reg_operand" "=f")
        (div:SF (match_operand:SF 1 "gpc_reg_operand" "f")
                (match_operand:SF 2 "gpc_reg_operand" "f")))]
-  "TARGET_POWER"
+  "! TARGET_POWERPC"
   "{fd|fdiv} %0,%1,%2"
   [(set_attr "type" "sdiv")])
 
        (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                          (match_operand:SF 2 "gpc_reg_operand" "f"))
                 (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "TARGET_POWER"
+  "! TARGET_POWERPC"
   "{fma|fmadd} %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                           (match_operand:SF 2 "gpc_reg_operand" "f"))
                  (match_operand:SF 3 "gpc_reg_operand" "f")))]
-  "TARGET_POWER"
+  "! TARGET_POWERPC"
   "{fms|fmsub} %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (neg:SF (plus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                                  (match_operand:SF 2 "gpc_reg_operand" "f"))
                         (match_operand:SF 3 "gpc_reg_operand" "f"))))]
-  "TARGET_POWER"
+  "! TARGET_POWERPC"
   "{fnma|fnmadd} %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
        (neg:SF (minus:SF (mult:SF (match_operand:SF 1 "gpc_reg_operand" "%f")
                                   (match_operand:SF 2 "gpc_reg_operand" "f"))
                          (match_operand:SF 3 "gpc_reg_operand" "f"))))]
-  "TARGET_POWER"
+  "! TARGET_POWERPC"
   "{fnms|fnmsub} %0,%1,%2,%3"
   [(set_attr "type" "fp")])
 
   ""
   "
 {
-  emit_insn (gen_trunc_call (operands[0], operands[1],
-                            gen_rtx (SYMBOL_REF, Pmode, RS6000_ITRUNC)));
-  DONE;
+  if (TARGET_POWER2 || TARGET_POWERPC)
+    {
+      rtx stack_slot, temp = gen_reg_rtx (DImode);
+      emit_insn (gen_fpcvtsi (temp, operands[1]));
+      stack_slot = gen_rtx (MEM, DImode,
+                           plus_constant (stack_pointer_rtx, 8));
+      emit_move_insn (stack_slot, temp);
+      emit_move_insn (operands[0],
+                     operand_subword (stack_slot, 1, 0, DImode));
+      DONE;
+    }
+  else
+    {
+      emit_insn (gen_trunc_call (operands[0], operands[1],
+                                gen_rtx (SYMBOL_REF, Pmode, RS6000_ITRUNC)));
+      DONE;
+    }
 }")
 
+(define_insn "fpcvtsi"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=f")
+       (sign_extend:DI
+        (fix:SI (match_operand:DF 1 "gpc_reg_operand" "f"))))]
+  "TARGET_POWER2 || TARGET_POWERPC"
+  "{fcirz|fctiwz} %0,%1"
+  [(set_attr "type" "fp")])
 (define_expand "fixuns_truncdfsi2"
   [(set (match_operand:SI 0 "gpc_reg_operand" "")
        (unsigned_fix:SI (match_operand:DF 1 "gpc_reg_operand" "")))]
-  ""
+  "! TARGET_POWER2 && ! TARGET_POWERPC"
   "
 {
   emit_insn (gen_trunc_call (operands[0], operands[1],
   "{sfi|subfic} %L0,%L1,0\;{sfze|subfze} %0,%1"
   [(set_attr "length" "8")])
 
-(define_insn "mulsidi3"
+(define_expand "mulsidi3"
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" ""))
+                (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" ""))))]
+  ""
+  "
+{
+  if (! TARGET_POWER && ! TARGET_POWERPC)
+    {
+      emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+      emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+      emit_insn (gen_mull_call ());
+      emit_move_insn (operand_subword (operands[0], 0, 0, DImode),
+                     gen_rtx (REG, SImode, 3));
+      emit_move_insn (operand_subword (operands[0], 1, 0, DImode),
+                     gen_rtx (REG, SImode, 4));
+      DONE;
+    }
+  else if (TARGET_POWER)
+    {
+      emit_insn (gen_mulsidi3_mq (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+}")
+(define_insn "mulsidi3_mq"
   [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
-       (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "r"))
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
                 (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))
    (clobber (match_scratch:SI 3 "=q"))]
   "TARGET_POWER"
   "mul %0,%1,%2\;mfmq %L0"
-  [(set_attr "length" "8")])
+  [(set_attr "type" "imul")
+   (set_attr "length" "8")])
+(define_insn ""
+  [(set (match_operand:DI 0 "gpc_reg_operand" "=r")
+       (mult:DI (sign_extend:DI (match_operand:SI 1 "gpc_reg_operand" "%r"))
+                (sign_extend:DI (match_operand:SI 2 "gpc_reg_operand" "r"))))]
+  "TARGET_POWERPC"
+  "mulhw %0,%1,%2\;mullw %L0,%1,%2"
+  [(set_attr "type" "imul")
+   (set_attr "length" "8")])
+(define_expand "smulsi3_highpart"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "")
+       (truncate:SI
+        (lshiftrt:DI (mult:DI (sign_extend:DI
+                               (match_operand:SI 1 "gpc_reg_operand" "%r"))
+                              (sign_extend:DI
+                               (match_operand:SI 2 "gpc_reg_operand" "r")))
+                     (const_int 32))))]
+  ""
+  "
+{
+  if (! TARGET_POWER && ! TARGET_POWERPC)
+    {
+      emit_move_insn (gen_rtx (REG, SImode, 3), operands[1]);
+      emit_move_insn (gen_rtx (REG, SImode, 4), operands[2]);
+      emit_insn (gen_mulh_call ());
+      emit_move_insn (operands[0], gen_rtx (REG, SImode, 3));
+      DONE;
+    }
+  else if (TARGET_POWER)
+    {
+      emit_insn (gen_smulsi3_highpart_mq (operands[0], operands[1], operands[2]));
+      DONE;
+    }
+}")
+(define_insn "smulsi3_highpart_mq"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+       (truncate:SI
+        (lshiftrt:DI (mult:DI (sign_extend:DI
+                               (match_operand:SI 1 "gpc_reg_operand" "%r"))
+                              (sign_extend:DI
+                               (match_operand:SI 2 "gpc_reg_operand" "r")))
+                     (const_int 32))))
+   (clobber (match_scratch:SI 3 "=q"))]
+  "TARGET_POWER"
+  "mul %0,%1,%2"
+  [(set_attr "type" "imul")])
+(define_insn ""
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+       (truncate:SI
+        (lshiftrt:DI (mult:DI (sign_extend:DI
+                               (match_operand:SI 1 "gpc_reg_operand" "%r"))
+                              (sign_extend:DI
+                               (match_operand:SI 2 "gpc_reg_operand" "r")))
+                     (const_int 32))))]
+  "TARGET_POWERPC"
+  "mulhw %0,%1,%2"
+  [(set_attr "type" "imul")])
+(define_insn "umulsi3_highpart"
+  [(set (match_operand:SI 0 "gpc_reg_operand" "=r")
+       (truncate:SI
+        (lshiftrt:DI (mult:DI (zero_extend:DI
+                               (match_operand:SI 1 "gpc_reg_operand" "%r"))
+                              (zero_extend:DI
+                               (match_operand:SI 2 "gpc_reg_operand" "r")))
+                     (const_int 32))))]
+  "TARGET_POWERPC"
+  "mulhwu %0,%1,%2"
+  [(set_attr "type" "imul")])
 
 ;; If operands 0 and 2 are in the same register, we have a problem.  But
 ;; operands 0 and 1 (the usual case) can be in the same register.  That's
    lis %0,%u1
    mf%1 %0
    mt%0 %1"
-  [(set_attr "type" "*,load,*,*,*,*,*")])
+  [(set_attr "type" "*,load,*,*,*,*,mtjmpr")])
 
 ;; Split a load of a large constant into the appropriate two-insn
 ;; sequence.
 #if HOST_FLOAT_FORMAT == TARGET_FLOAT_FORMAT && ! defined(REAL_IS_NOT_DOUBLE)
          || GET_CODE (operands[1]) == CONST_DOUBLE
 #endif
-         || (GET_CODE (operands[1]) == REG && REGNO (operands[1]) < 32)
-         || (reload_in_progress && GET_CODE (operands[1]) == REG
-             && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER))
+         || (GET_CODE (operands[1]) == REG
+             && (REGNO (operands[1]) < 32
+                 || (reload_in_progress
+                     && REGNO (operands[1]) >= FIRST_PSEUDO_REGISTER))))
        {
          emit_move_insn (operand_subword (operands[0], 0, 0, SFmode),
                          operand_subword (operands[1], 0, 0, SFmode));
 }")
 
 (define_insn ""
-  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m")
-       (match_operand:DI 1 "input_operand" "r,m,r"))]
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m")
+       (match_operand:DI 1 "input_operand" "r,m,r,f,m,f"))]
   "gpc_reg_operand (operands[0], DImode)
    || gpc_reg_operand (operands[1], DImode)"
   "*
        return \"{l%U1|lwz%U1} %0,%1\;{l|lwz} %L0,%L1\";
     case 2:
       return \"{st%U0|stw%U0} %1,%0\;{st|stw} %L1,%L0\";
+    case 3:
+      return \"fmr %0,%1\";
+    case 4:
+      return \"lfd%U1%X1 %0,%1\";
+    case 5:
+      return \"stfd%U0%X0 %1,%0\";
     }
 }"
-  [(set_attr "type" "*,load,*")
-   (set_attr "length" "8")])
+  [(set_attr "type" "*,load,*,fp,fpload,*")
+   (set_attr "length" "8,8,8,*,*,*")])
 \f
 ;; TImode is similar, except that we usually want to compute the address into
 ;; a register and use lsi/stsi (the exception is during reload).  MQ is also