Make long longs use normal CONST_DOUBLE in movdi, do not split too early
authorMichael Meissner <meissner@gcc.gnu.org>
Mon, 11 Mar 1996 18:57:23 +0000 (18:57 +0000)
committerMichael Meissner <meissner@gcc.gnu.org>
Mon, 11 Mar 1996 18:57:23 +0000 (18:57 +0000)
From-SVN: r11513

gcc/config/rs6000/rs6000.c
gcc/config/rs6000/rs6000.h
gcc/config/rs6000/rs6000.md

index 6d89bea6ff816207685d6e3e25e6a44dfae52310..34fdab7b23993b1515686550e834b115a7c6af82 100644 (file)
@@ -524,6 +524,90 @@ reg_or_cint_operand (op, mode)
      return GET_CODE (op) == CONST_INT || gpc_reg_operand (op, mode);
 }
 
+/* Return the number of instructions it takes to form a constant in an
+   integer register.  */
+
+static int
+num_insns_constant_wide (value)
+     HOST_WIDE_INT value;
+{
+  /* signed constant loadable with {cal|addi} */
+  if (((unsigned HOST_WIDE_INT)value + 0x8000) < 0x10000)
+    return 1;
+
+#if HOST_BITS_PER_WIDE_INT == 32
+  /* constant loadable with {cau|addis} */
+  else if ((value & 0xffff) == 0)
+    return 1;
+
+#else
+  /* constant loadable with {cau|addis} */
+  else if ((value & 0xffff) == 0 && (value & ~0xffffffff) == 0)
+    return 1;
+
+  else if (TARGET_64BIT)
+    {
+      HOST_WIDE_INT low  = value & 0xffffffff;
+      HOST_WIDE_INT high = value >> 32;
+
+      if (high == 0 && (low & 0x80000000) == 0)
+       return 2;
+
+      else if (high == 0xffffffff && (low & 0x80000000) != 0)
+       return 2;
+
+      else if (!low)
+       return num_insns_constant_wide (high) + 1;
+
+      else
+       return (num_insns_constant_wide (high)
+               + num_insns_constant_low (low) + 1);
+    }
+#endif
+
+  else
+    return 2;
+}
+
+int
+num_insns_constant (op, mode)
+     rtx op;
+     enum machine_mode mode;
+{
+  if (mode != SImode && mode != DImode)
+    abort ();
+
+  if (GET_CODE (op) == CONST_INT)
+    return num_insns_constant_wide (INTVAL (op));
+
+  else if (GET_CODE (op) == CONST_DOUBLE && TARGET_32BIT)
+    return (num_insns_constant_wide (CONST_DOUBLE_LOW (op))
+           + num_insns_constant_wide (CONST_DOUBLE_HIGH (op)));
+
+  else if (GET_CODE (op) == CONST_DOUBLE && TARGET_64BIT)
+    {
+      HOST_WIDE_INT low  = CONST_DOUBLE_LOW (op);
+      HOST_WIDE_INT high = CONST_DOUBLE_HIGH (op);
+
+      if (high == 0 && (low & 0x80000000) == 0)
+       return num_insns_constant_wide (low);
+
+      else if (((high & 0xffffffff) == 0xffffffff)
+              && ((low & 0x80000000) != 0))
+       return num_insns_constant_wide (low);
+
+      else if (low == 0)
+       return num_insns_constant_wide (high) + 1;
+
+      else
+       return (num_insns_constant_wide (high)
+               + num_insns_constant_wide (low) + 1);
+    }
+
+  else
+    abort ();
+}
+
 /* Return 1 if the operand is a CONST_DOUBLE and it can be put into a register
    with one instruction per word.  We only do this if we can safely read
    CONST_DOUBLE_{LOW,HIGH}.  */
@@ -535,11 +619,11 @@ easy_fp_constant (op, mode)
 {
   if (GET_CODE (op) != CONST_DOUBLE
       || GET_MODE (op) != mode
-      || GET_MODE_CLASS (mode) != MODE_FLOAT)
+      || (GET_MODE_CLASS (mode) != MODE_FLOAT && mode != DImode))
     return 0;
 
   /* Consider all constants with -msoft-float to be easy */
-  if (TARGET_SOFT_FLOAT)
+  if (TARGET_SOFT_FLOAT && mode != DImode)
     return 1;
 
   if (mode == DFmode)
@@ -550,10 +634,11 @@ easy_fp_constant (op, mode)
       REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
       REAL_VALUE_TO_TARGET_DOUBLE (rv, k);
 
-      return (((unsigned) (k[0] + 0x8000) < 0x10000 || (k[0] & 0xffff) == 0)
-             && ((unsigned) (k[1] + 0x8000) < 0x10000 || (k[1] & 0xffff) == 0));
+      return (num_insns_constant_wide ((HOST_WIDE_INT)k[0]) == 1
+             && num_insns_constant_wide ((HOST_WIDE_INT)k[1]) == 1);
     }
-  else
+
+  else if (mode == SFmode)
     {
       long l;
       REAL_VALUE_TYPE rv;
@@ -561,8 +646,14 @@ easy_fp_constant (op, mode)
       REAL_VALUE_FROM_CONST_DOUBLE (rv, op);
       REAL_VALUE_TO_TARGET_SINGLE (rv, l);
 
-      return ((unsigned) (l + 0x8000) < 0x10000 || (l & 0xffff) == 0);
+      return num_insns_constant_wide (l) == 1;
     }
+
+  else if (mode == DImode && TARGET_32BIT)
+    return num_insns_constant (op, DImode) == 2;
+
+  else
+    abort ();
 }
 
 /* Return 1 if the operand is in volatile memory.  Note that during the
@@ -821,6 +912,11 @@ input_operand (op, mode)
       && easy_fp_constant (op, mode))
     return 1;
 
+  /* Allow any integer constant.  */
+  if (GET_MODE_CLASS (mode) == MODE_INT
+      && (GET_CODE (op) == CONST_INT || GET_CODE (op) == CONST_DOUBLE))
+    return 1;
+
   /* For floating-point or multi-word mode, the only remaining valid type
      is a register.  */
   if (GET_MODE_CLASS (mode) == MODE_FLOAT
@@ -833,10 +929,6 @@ input_operand (op, mode)
   if (register_operand (op, mode))
     return 1;
 
-  /* For integer modes, any constant is ok.  */
-  if (GET_CODE (op) == CONST_INT)
-    return 1;
-
   /* A SYMBOL_REF referring to the TOC is valid.  */
   if (LEGITIMATE_CONSTANT_POOL_ADDRESS_P (op))
     return 1;
index f49c687b36bfae21bdbea86a6757b7d64360018e..aa1e5f0af539a6557701f2773eff7f359634d1c7 100644 (file)
@@ -995,10 +995,14 @@ enum reg_class
    Here VALUE is the CONST_DOUBLE rtx itself.
 
    We flag for special constants when we can copy the constant into
-   a general register in two insns for DF and one insn for SF.  */
+   a general register in two insns for DF/DI and one insn for SF.
 
-#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)  \
-  ((C) == 'G' ? easy_fp_constant (VALUE, GET_MODE (VALUE)) : 0)
+   'H' is used for DI constants that take 3 insns.  */
+
+#define CONST_DOUBLE_OK_FOR_LETTER_P(VALUE, C)                         \
+  ((C) == 'G' ? easy_fp_constant (VALUE, GET_MODE (VALUE)) :           \
+   (C) == 'H' ? (num_insns_constant (VALUE, DImode) == 3) :            \
+   0)
 
 /* Optional extra constraints for this machine.
 
@@ -2819,6 +2823,7 @@ extern int reg_or_short_operand ();
 extern int reg_or_neg_short_operand ();
 extern int reg_or_u_short_operand ();
 extern int reg_or_cint_operand ();
+extern int num_insns_constant ();
 extern int easy_fp_constant ();
 extern int volatile_mem_operand ();
 extern int offsettable_addr_operand ();
index aa1b0fe6146c5c686ba21e77c31e25cec3ebff0b..5c47d6a36483ec091f23df836e1b8935c903ed69 100644 (file)
   if (GET_CODE (operands[0]) != REG)
     operands[1] = force_reg (DImode, operands[1]);
 
-  if (GET_CODE (operands[1]) == CONST_DOUBLE
-      || GET_CODE (operands[1]) == CONST_INT)
+  if (TARGET_64BIT
+      && (GET_CODE (operands[1]) == CONST_DOUBLE
+         || GET_CODE (operands[1]) == CONST_INT))
     {
       HOST_WIDE_INT low;
       HOST_WIDE_INT high;
        }
 #endif
 
-      if (! TARGET_POWERPC64)
-       {
-         emit_move_insn (gen_rtx (SUBREG, SImode, operands[0],
-                         WORDS_BIG_ENDIAN), GEN_INT (low));
-
-         emit_move_insn (gen_rtx (SUBREG, SImode, operands[0],
-                         ! WORDS_BIG_ENDIAN), GEN_INT (high));
-         DONE;
-       }
-      else
-       {
-         if (high + 0x8000 >= 0x10000)
-           {
-             emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], 1),
-                             GEN_INT (high));
-             emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT(32)));
-             if (low)
-               {
-                 HOST_WIDE_INT low_low = low & 0xffff;
-                 HOST_WIDE_INT low_high = low & (~ (HOST_WIDE_INT) 0xffff);
-                 if (low_high)
-                   emit_insn (gen_iordi3 (operands[0], operands[0],
-                                          GEN_INT (low_high)));
-                 if (low_low)
-                   emit_insn (gen_iordi3 (operands[0], operands[0],
-                                          GEN_INT (low_low)));
-               }
-           }
-         else if (low)
-           emit_move_insn (gen_rtx (SUBREG, SImode, operands[0], 1),
-                           GEN_INT (low));
-         DONE;
-        }
+       if (high)
+         {
+           emit_move_insn (operands[0], GEN_INT (high));
+           emit_insn (gen_ashldi3 (operands[0], operands[0], GEN_INT(32)));
+           if (low)
+             {
+               HOST_WIDE_INT low_low = low & 0xffff;
+               HOST_WIDE_INT low_high = low & (~ (HOST_WIDE_INT) 0xffff);
+               if (low_high)
+                 emit_insn (gen_iordi3 (operands[0], operands[0],
+                                        GEN_INT (low_high)));
+               if (low_low)
+                 emit_insn (gen_iordi3 (operands[0], operands[0],
+                                        GEN_INT (low_low)));
+             }
+             DONE;
+         }
     }
 
       /* Stores between FPR and any non-FPR registers must go through a
 }")
 
 (define_insn ""
-  [(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"))]
-  "! TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode)
-   || gpc_reg_operand (operands[1], DImode))"
+  [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,f,f,m,r,r,r,r,r")
+       (match_operand:DI 1 "input_operand" "r,m,r,f,m,f,IJK,n,G,H,F"))]
+  "TARGET_32BIT
+   && (gpc_reg_operand (operands[0], DImode)
+       || gpc_reg_operand (operands[1], DImode))"
   "*
 {
   switch (which_alternative)
       return \"lfd%U1%X1 %0,%1\";
     case 5:
       return \"stfd%U0%X0 %1,%0\";
+    case 6:
+    case 7:
+    case 8:
+    case 9:
+    case 10:
+      return \"#\";
     }
 }"
-  [(set_attr "type" "*,load,store,fp,fpload,fpstore")
-   (set_attr "length" "8,8,8,*,*,*")])
+  [(set_attr "type" "*,load,store,fp,fpload,fpstore,*,*,*,*,*")
+   (set_attr "length" "8,8,8,*,*,*,8,12,8,12,16")])
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (match_operand:DI 1 "const_int_operand" ""))]
+  "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) <= 1"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 1))]
+  "
+{
+  operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
+  operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
+  operands[4] = (INTVAL (operands[1]) & 0x80000000) ? constm1_rtx : const0_rtx;
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (match_operand:DI 1 "const_int_operand" ""))]
+  "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) >= 2"
+  [(set (match_dup 3) (match_dup 5))
+   (set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (ior:SI (match_dup 3) (match_dup 6)))]
+  "
+{
+  HOST_WIDE_INT value = INTVAL (operands[1]);
+  operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
+  operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
+  operands[4] = (value & 0x80000000) ? constm1_rtx : const0_rtx;
+  operands[5] = GEN_INT (value & 0xffff0000);
+  operands[6] = GEN_INT (value & 0x0000ffff);
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (match_operand:DI 1 "const_double_operand" ""))]
+  "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) <= 2"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))]
+  "
+{
+  operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
+  operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
+  operands[4] = GEN_INT (CONST_DOUBLE_HIGH (operands[1]));
+  operands[5] = GEN_INT (CONST_DOUBLE_LOW  (operands[1]));
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (match_operand:DI 1 "const_double_operand" ""))]
+  "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) == 3"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))
+   (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6)))]
+  "
+{
+  HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]);
+  HOST_WIDE_INT low  = CONST_DOUBLE_LOW  (operands[1]);
+  rtx high_reg = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
+  rtx low_reg  = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
+
+  if (((unsigned HOST_WIDE_INT) (low + 0x8000) < 0x10000)
+      || (low & 0xffff) == 0)
+    {
+      operands[2] = high_reg;
+      operands[3] = low_reg;
+      operands[4] = GEN_INT (high & 0xffff0000);
+      operands[5] = GEN_INT (low);
+      operands[6] = GEN_INT (high & 0x0000ffff);
+    }
+  else
+    {
+      operands[2] = low_reg;
+      operands[3] = high_reg;
+      operands[4] = GEN_INT (low & 0xffff0000);
+      operands[5] = GEN_INT (high);
+      operands[6] = GEN_INT (low & 0x0000ffff);
+    }
+}")
+
+(define_split
+  [(set (match_operand:DI 0 "gpc_reg_operand" "")
+       (match_operand:DI 1 "const_double_operand" ""))]
+  "TARGET_32BIT && reload_completed && num_insns_constant (operands[1], DImode) >= 4"
+  [(set (match_dup 2) (match_dup 4))
+   (set (match_dup 3) (match_dup 5))
+   (set (match_dup 2) (ior:SI (match_dup 2) (match_dup 6)))
+   (set (match_dup 3) (ior:SI (match_dup 3) (match_dup 7)))]
+  "
+{
+  HOST_WIDE_INT high = CONST_DOUBLE_HIGH (operands[1]);
+  HOST_WIDE_INT low  = CONST_DOUBLE_LOW  (operands[1]);
+
+  operands[2] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN == 0);
+  operands[3] = gen_rtx (SUBREG, SImode, operands[0], WORDS_BIG_ENDIAN != 0);
+  operands[4] = GEN_INT (high & 0xffff0000);
+  operands[5] = GEN_INT (low  & 0xffff0000);
+  operands[6] = GEN_INT (high & 0x0000ffff);
+  operands[7] = GEN_INT (low  & 0x0000ffff);
+}")
 
 (define_insn ""
   [(set (match_operand:DI 0 "nonimmediate_operand" "=r,r,m,r,r,r,r,f,f,m,r,*h,*h")
-       (match_operand:DI 1 "input_operand" "r,m,r,I,J,n,R,f,m,f,*h,r,0"))]
-  "TARGET_POWERPC64 && (gpc_reg_operand (operands[0], DImode)
-   || gpc_reg_operand (operands[1], DImode))"
+       (match_operand:DI 1 "input_operand" "r,m,r,I,J,nF,R,f,m,f,*h,r,0"))]
+  "TARGET_64BIT
+   && (gpc_reg_operand (operands[0], DImode)
+       || gpc_reg_operand (operands[1], DImode))"
   "@
    mr %0,%1
    ld%U1%X1 %0,%1
 (define_split
   [(set (match_operand:DI 0 "gpc_reg_operand" "")
        (match_operand:DI 1 "const_double_operand" ""))]
-  "TARGET_POWERPC64"
+  "TARGET_64BIT && num_insns_constant (operands[1], DImode) > 1"
   [(set (match_dup 0)
        (match_dup 2))
    (set (match_dup 0)