Patchwork [RS6000] IBM long double little-endian

login
register
mail settings
Submitter Alan Modra
Date June 12, 2013, 2:53 p.m.
Message ID <20130612145322.GA21523@bubble.grove.modra.org>
Download mbox | patch
Permalink /patch/250807/
State New
Headers show

Comments

Alan Modra - June 12, 2013, 2:53 p.m.
FLOAT_WORDS_BIG_ENDIAN doesn't work out too well for IBM extended
double when little-endian, because we're thinking to keep the large
magnitude double first.  See the comment below on
LONG_DOUBLE_LARGE_FIRST.

This patch fixes all occurrences of FLOAT_WORDS_BIG_ENDIAN in the
rs6000 backend (all of them are dealing with long doubles), and adds
an expander that results in us avoiding all current code in builtins.c
and optabs.c that uses FLOAT_WORDS_BIG_ENDIAN.  Bootstrapped etc.
powerpc64-linux.  signbittf2 is written to use the 64-bit shift when
available as this lets optimisers know the state of the high 32-bits,
and avoid a sign/zero extend if the SImode result is later extended to
DImode.

	* config/rs6000/rs6000.h (LONG_DOUBLE_LARGE_FIRST): Define.
	* config/rs6000/rs6000.md (signbittf2): New insn.
	(extenddftf2_internal): Use LONG_DOUBLE_LARGE_FIRST.
	(abstf2_internal, cmptf_internal2): Likewise.
	* config/rs6000/spe.md (spe_abstf2_cmp, spe_abstf2_tst): Likewise.
David Edelsohn - June 12, 2013, 3:09 p.m.
On Wed, Jun 12, 2013 at 10:53 AM, Alan Modra <amodra@gmail.com> wrote:

>         * config/rs6000/rs6000.h (LONG_DOUBLE_LARGE_FIRST): Define.
>         * config/rs6000/rs6000.md (signbittf2): New insn.
>         (extenddftf2_internal): Use LONG_DOUBLE_LARGE_FIRST.
>         (abstf2_internal, cmptf_internal2): Likewise.
>         * config/rs6000/spe.md (spe_abstf2_cmp, spe_abstf2_tst): Likewise.


Why create and define LONG_DOUBLE_LARGE_FIRST if it always is "1"
(True)?  To retain flexibility?

Thanks, David
Alan Modra - June 12, 2013, 3:17 p.m.
On Wed, Jun 12, 2013 at 11:09:03AM -0400, David Edelsohn wrote:
> On Wed, Jun 12, 2013 at 10:53 AM, Alan Modra <amodra@gmail.com> wrote:
> 
> >         * config/rs6000/rs6000.h (LONG_DOUBLE_LARGE_FIRST): Define.
> >         * config/rs6000/rs6000.md (signbittf2): New insn.
> >         (extenddftf2_internal): Use LONG_DOUBLE_LARGE_FIRST.
> >         (abstf2_internal, cmptf_internal2): Likewise.
> >         * config/rs6000/spe.md (spe_abstf2_cmp, spe_abstf2_tst): Likewise.
> 
> 
> Why create and define LONG_DOUBLE_LARGE_FIRST if it always is "1"
> (True)?  To retain flexibility?

Yes.  We don't have anything like an ABI fixed in stone at the moment.
David Edelsohn - June 12, 2013, 3:39 p.m.
What is your model for the way that the RTL and C statements in the
new signbittf2 pattern interact?

The C preparation statements are executed before the RTL code
generated from the RTL template.  In the patch, it seems that the new
pattern is assuming that it can rely on some results produced by the
RTL template.  Maybe this seems to work because data dependence
reorders the statements when compiled with optimization.

Thanks, David
David Edelsohn - June 13, 2013, 1:21 a.m.
On Wed, Jun 12, 2013 at 10:53 AM, Alan Modra <amodra@gmail.com> wrote:
> FLOAT_WORDS_BIG_ENDIAN doesn't work out too well for IBM extended
> double when little-endian, because we're thinking to keep the large
> magnitude double first.  See the comment below on
> LONG_DOUBLE_LARGE_FIRST.
>
> This patch fixes all occurrences of FLOAT_WORDS_BIG_ENDIAN in the
> rs6000 backend (all of them are dealing with long doubles), and adds
> an expander that results in us avoiding all current code in builtins.c
> and optabs.c that uses FLOAT_WORDS_BIG_ENDIAN.  Bootstrapped etc.
> powerpc64-linux.  signbittf2 is written to use the 64-bit shift when
> available as this lets optimisers know the state of the high 32-bits,
> and avoid a sign/zero extend if the SImode result is later extended to
> DImode.
>
>         * config/rs6000/rs6000.h (LONG_DOUBLE_LARGE_FIRST): Define.
>         * config/rs6000/rs6000.md (signbittf2): New insn.
>         (extenddftf2_internal): Use LONG_DOUBLE_LARGE_FIRST.
>         (abstf2_internal, cmptf_internal2): Likewise.
>         * config/rs6000/spe.md (spe_abstf2_cmp, spe_abstf2_tst): Likewise.

The patch is okay.

That style of writing a pattern is not very common.

Thanks, David

Patch

Index: gcc/config/rs6000/rs6000.h
===================================================================
--- gcc/config/rs6000/rs6000.h	(revision 199948)
+++ gcc/config/rs6000/rs6000.h	(working copy)
@@ -715,6 +715,11 @@  extern unsigned char rs6000_recip_bits[];
    instructions for them.  Might as well be consistent with bits and bytes.  */
 #define WORDS_BIG_ENDIAN 1
 
+/* This says that for the IBM long double the larger magnitude double
+   comes first.  It's really a two element double array, and arrays
+   don't index differently between little- and big-endian.  */
+#define LONG_DOUBLE_LARGE_FIRST 1
+
 #define MAX_BITS_PER_WORD 64
 
 /* Width of a word, in units (bytes).  */
Index: gcc/config/rs6000/rs6000.md
===================================================================
--- gcc/config/rs6000/rs6000.md	(revision 199948)
+++ gcc/config/rs6000/rs6000.md	(working copy)
@@ -5178,6 +5178,41 @@ 
   "frsqrtes %0,%1"
   [(set_attr "type" "fp")])
 
+;; This expander is here to avoid FLOAT_WORDS_BIGENDIAN tests in
+;; builtins.c and optabs.c that are not correct for IBM long double
+;; when little-endian.
+(define_expand "signbittf2"
+  [(set (match_dup 2)
+	(float_truncate:DF (match_operand:TF 1 "gpc_reg_operand" "")))
+   (set (match_dup 3)
+   	(subreg:DI (match_dup 2) 0))
+   (set (match_dup 4)
+   	(match_dup 5))
+   (set (match_operand:SI 0 "gpc_reg_operand" "")
+  	(match_dup 6))]
+  "!TARGET_IEEEQUAD
+   && TARGET_HARD_FLOAT
+   && (TARGET_FPRS || TARGET_E500_DOUBLE)
+   && TARGET_LONG_DOUBLE_128"
+{
+  operands[2] = gen_reg_rtx (DFmode);
+  operands[3] = gen_reg_rtx (DImode);
+  if (TARGET_POWERPC64)
+    {
+      operands[4] = gen_reg_rtx (DImode);
+      operands[5] = gen_rtx_LSHIFTRT (DImode, operands[3], GEN_INT (63));
+      operands[6] = gen_rtx_SUBREG (SImode, operands[4],
+				    WORDS_BIG_ENDIAN ? 4 : 0);
+    }
+  else
+    {
+      operands[4] = gen_reg_rtx (SImode);
+      operands[5] = gen_rtx_SUBREG (SImode, operands[3],
+				    WORDS_BIG_ENDIAN ? 0 : 4);
+      operands[6] = gen_rtx_LSHIFTRT (SImode, operands[4], GEN_INT (31));
+    }
+})
+
 (define_expand "copysign<mode>3"
   [(set (match_dup 3)
         (abs:SFDF (match_operand:SFDF 1 "gpc_reg_operand" "")))
@@ -9260,8 +9295,8 @@ 
   "&& reload_completed"
   [(pc)]
 {
-  const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
-  const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode);
+  const int lo_word = LONG_DOUBLE_LARGE_FIRST ? GET_MODE_SIZE (DFmode) : 0;
+  const int hi_word = LONG_DOUBLE_LARGE_FIRST ? 0 : GET_MODE_SIZE (DFmode);
   emit_move_insn (simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word),
 		  operands[1]);
   emit_move_insn (simplify_gen_subreg (DFmode, operands[0], TFmode, lo_word),
@@ -9490,8 +9525,8 @@ 
    && TARGET_LONG_DOUBLE_128"
   "
 {
-  const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode);
-  const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
+  const int hi_word = LONG_DOUBLE_LARGE_FIRST ? 0 : GET_MODE_SIZE (DFmode);
+  const int lo_word = LONG_DOUBLE_LARGE_FIRST ? GET_MODE_SIZE (DFmode) : 0;
   operands[3] = gen_reg_rtx (DFmode);
   operands[4] = gen_reg_rtx (CCFPmode);
   operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word);
@@ -12879,8 +12914,8 @@ 
    (match_dup 13)]
 {
   REAL_VALUE_TYPE rv;
-  const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
-  const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode);
+  const int lo_word = LONG_DOUBLE_LARGE_FIRST ? GET_MODE_SIZE (DFmode) : 0;
+  const int hi_word = LONG_DOUBLE_LARGE_FIRST ? 0 : GET_MODE_SIZE (DFmode);
 
   operands[5] = simplify_gen_subreg (DFmode, operands[1], TFmode, hi_word);
   operands[6] = simplify_gen_subreg (DFmode, operands[1], TFmode, lo_word);
Index: gcc/config/rs6000/spe.md
===================================================================
--- gcc/config/rs6000/spe.md	(revision 199948)
+++ gcc/config/rs6000/spe.md	(working copy)
@@ -2604,8 +2604,8 @@ 
    && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
   "
 {
-  const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode);
-  const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
+  const int hi_word = LONG_DOUBLE_LARGE_FIRST ? 0 : GET_MODE_SIZE (DFmode);
+  const int lo_word = LONG_DOUBLE_LARGE_FIRST ? GET_MODE_SIZE (DFmode) : 0;
   operands[3] = gen_reg_rtx (DFmode);
   operands[4] = gen_reg_rtx (CCFPmode);
   operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word);
@@ -2627,8 +2627,8 @@ 
    && TARGET_HARD_FLOAT && TARGET_E500_DOUBLE && TARGET_LONG_DOUBLE_128"
   "
 {
-  const int hi_word = FLOAT_WORDS_BIG_ENDIAN ? 0 : GET_MODE_SIZE (DFmode);
-  const int lo_word = FLOAT_WORDS_BIG_ENDIAN ? GET_MODE_SIZE (DFmode) : 0;
+  const int hi_word = LONG_DOUBLE_LARGE_FIRST ? 0 : GET_MODE_SIZE (DFmode);
+  const int lo_word = LONG_DOUBLE_LARGE_FIRST ? GET_MODE_SIZE (DFmode) : 0;
   operands[3] = gen_reg_rtx (DFmode);
   operands[4] = gen_reg_rtx (CCFPmode);
   operands[5] = simplify_gen_subreg (DFmode, operands[0], TFmode, hi_word);