This patch aims to prevent long sequences loading soft-float
constants.  For 32-bit, it makes sense to load values inline to a gpr
with lis, addi, but not so much for 64-bit where a 5 insn sequence
might be needed for each gpr.  For TFmode in particular, a 10 insn
sequence is reduced to 2 loads from memory plus 1 or 2 address setup
insns.

Bootstrapped etc. powerpc64le-linux and powerpc64-linux.  OK for
next stage1?

        * config/rs6000/predicates.md (easy_fp_constant): Avoid long
        dependent insn sequences.
        * config/rs6000/rs6000.c (num_insns_constant): Support long
        double constants.
        * config/rs6000/rs6000.md (mov<mode>_softfloat128) Adjust length
        attribute.

diff --git a/gcc/config/rs6000/predicates.md b/gcc/config/rs6000/predicates.md
index 9fbeb928fe6..349f38c44f2 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -565,8 +565,19 @@ (define_predicate "easy_fp_constant"
   gcc_assert (GET_MODE (op) == mode
              && SCALAR_FLOAT_MODE_P (mode));
 
-  /* Consider all constants with -msoft-float to be easy.  */
-  if (TARGET_SOFT_FLOAT)
+  /* Consider all constants with -msoft-float to be easy when regs are
+     32-bit and thus can be loaded with a maximum of 2 insns.  For
+     64-bit avoid long dependent insn sequences.  */
+  if (TARGET_SOFT_FLOAT
+      && (!TARGET_POWERPC64
+         || mode == SFmode || mode == SDmode
+         || ((mode == DFmode || mode == DDmode)
+             && (num_insns_constant (op, mode)
+                 <= (TARGET_CMODEL != CMODEL_SMALL ? 3 : 2)))
+         || ((mode == TFmode || mode == TDmode
+              || mode == KFmode || mode == IFmode)
+             && (num_insns_constant (op, mode)
+                 <= (TARGET_CMODEL != CMODEL_SMALL ? 4 : 3)))))
     return 1;
 
   /* 0.0D is not all zero bits.  */
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index 3364068d976..212e9facb3a 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -5934,6 +5934,25 @@ num_insns_constant (rtx op, machine_mode mode)
            val |= l[WORDS_BIG_ENDIAN ? 1 : 0] & 0xffffffffUL;
            mode = DImode;
          }
+       else if (mode == TFmode || mode == TDmode
+                || mode == KFmode || mode == IFmode)
+         {
+           long l[4];
+           int ins;
+
+           if (mode == TDmode)
+             REAL_VALUE_TO_TARGET_DECIMAL128 (*rv, l);
+           else
+             REAL_VALUE_TO_TARGET_LONG_DOUBLE (*rv, l);
+
+           val = l[WORDS_BIG_ENDIAN ? 0 : 3] << 32;
+           val |= l[WORDS_BIG_ENDIAN ? 1 : 2] & 0xffffffffUL;
+           ins = num_insns_constant_multi (val, DImode);
+           val = l[WORDS_BIG_ENDIAN ? 2 : 1] << 32;
+           val |= l[WORDS_BIG_ENDIAN ? 3 : 0] & 0xffffffffUL;
+           ins += num_insns_constant_multi (val, DImode);
+           return ins;
+         }
        else
          gcc_unreachable ();
       }
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index 11097717268..e75f35dac60 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -7729,7 +7729,7 @@ (define_insn_and_split "*mov<mode>_softfloat128"
            (const_string "8")
            (const_string "16"))
        (if_then_else (match_test "TARGET_POWERPC64")
-           (const_string "40")
+           (const_string "16")
            (const_string "32"))
        (if_then_else (match_test "TARGET_POWERPC64")
            (const_string "8")

-- 
Alan Modra
Australia Development Lab, IBM

Reply via email to