diff mbox series

[RS6000] PowerPC64 soft-float

Message ID 20181125122027.GP21617@bubble.grove.modra.org
State New
Headers show
Series [RS6000] PowerPC64 soft-float | expand

Commit Message

Alan Modra Nov. 25, 2018, 12:20 p.m. UTC
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.

Comments

Segher Boessenkool Nov. 29, 2018, 6:15 p.m. UTC | #1
Hi!

On Sun, Nov 25, 2018 at 10:50:27PM +1030, Alan Modra wrote:
> 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?

It's okay now, even.

> 	* 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.

> -  /* 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;

Maybe this can be written simpler with  MODE_SIZE (mode) >= 16  or such.

  if (TARGET_SOFT_FLOAT)
    {
      if (!TARGET_POWERPC64)
	return 1;

      int size = MODE_SIZE (mode);
      if (size == 4)
	return 1;

      int max_insns = 3;
      if (TARGET_CMODEL == CMODEL_SMALL)
	max_insns--;
      if (size >= 16)
	max_insns++;
      if (num_insns_constant (op, mode) <= max_insns)
	return 1;
    }

Something like that, perhaps.  It's not really shorter :-/

> +	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;

You can't shift a "long" left by 32 bits.  Cast to HOST_WIDE_INT?
Maybe there is some helper already?

> --- 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")

I really would love to see this in stage3 still; it's arguably a bugfix.


Segher
Alan Modra Nov. 30, 2018, 7:58 a.m. UTC | #2
On Thu, Nov 29, 2018 at 12:15:06PM -0600, Segher Boessenkool wrote:
> On Sun, Nov 25, 2018 at 10:50:27PM +1030, Alan Modra wrote:
> > 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?
> 
> It's okay now, even.

Thanks!  Revised patch as per your other comments bootstrapped and
regression tested powerpc64le-linux.

	* 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 cf07d5c6372..94feae28c02 100644
--- a/gcc/config/rs6000/predicates.md
+++ b/gcc/config/rs6000/predicates.md
@@ -564,9 +564,26 @@ (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.  */
+  /* 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)
-    return 1;
+    {
+      if (!TARGET_POWERPC64)
+        return 1;
+
+      int size = GET_MODE_SIZE (mode);
+      if (size < 8)
+        return 1;
+
+      int load_from_mem_insns = 2;
+      if (size > 8)
+        load_from_mem_insns++;
+      if (TARGET_CMODEL != CMODEL_SMALL)
+        load_from_mem_insns++;
+      if (num_insns_constant (op, mode) <= load_from_mem_insns)
+        return 1;
+    }
 
   /* 0.0D is not all zero bits.  */
   if (DECIMAL_FLOAT_MODE_P (mode))
diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c
index c438fdc64fe..60c319de467 100644
--- a/gcc/config/rs6000/rs6000.c
+++ b/gcc/config/rs6000/rs6000.c
@@ -5940,6 +5940,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 insns;
+
+	    if (mode == TDmode)
+	      REAL_VALUE_TO_TARGET_DECIMAL128 (*rv, l);
+	    else
+	      REAL_VALUE_TO_TARGET_LONG_DOUBLE (*rv, l);
+
+	    val = (unsigned HOST_WIDE_INT) l[WORDS_BIG_ENDIAN ? 0 : 3] << 32;
+	    val |= l[WORDS_BIG_ENDIAN ? 1 : 2] & 0xffffffffUL;
+	    insns = num_insns_constant_multi (val, DImode);
+	    val = (unsigned HOST_WIDE_INT) l[WORDS_BIG_ENDIAN ? 2 : 1] << 32;
+	    val |= l[WORDS_BIG_ENDIAN ? 3 : 0] & 0xffffffffUL;
+	    insns += num_insns_constant_multi (val, DImode);
+	    return insns;
+	  }
 	else
 	  gcc_unreachable ();
       }
diff --git a/gcc/config/rs6000/rs6000.md b/gcc/config/rs6000/rs6000.md
index d2f6f11b3e5..797d5c32e64 100644
--- a/gcc/config/rs6000/rs6000.md
+++ b/gcc/config/rs6000/rs6000.md
@@ -7729,7 +7729,7 @@ (define_insn_and_split "*mov<mode>_softfloat"
 	    (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")
Segher Boessenkool Nov. 30, 2018, 1:03 p.m. UTC | #3
On Fri, Nov 30, 2018 at 06:28:28PM +1030, Alan Modra wrote:
> On Thu, Nov 29, 2018 at 12:15:06PM -0600, Segher Boessenkool wrote:
> > On Sun, Nov 25, 2018 at 10:50:27PM +1030, Alan Modra wrote:
> > > 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?
> > 
> > It's okay now, even.
> 
> Thanks!  Revised patch as per your other comments bootstrapped and
> regression tested powerpc64le-linux.

That looks great.  Okay for trunk.  Thanks!

> 	* 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.

Missing colon on that last line.


Segher
diff mbox series

Patch

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")