This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH] PR target/27968: x87's ffreep vs. the SUN assembler


The following pair of alternate solutions resolve PR target/27968 which
is a code generation issue on Solaris/x86.  The problem is that when
optimizing for k8, the processor family selected by GNU GMP's configure
on these Opteron boxes, GCC prefers to emit the faster "ffreep" insn
when popping the stack.  Unfortunately, although this is implemented
by all modern x86 hardware, the "ffreep" mnemonic isn't recognized by
SUN's assembler on Solaris.

The fix below starts with the obvious strategy for handling this kind
of issue, but adding a test to GCC's configure to check whether the
chosen assembler for the target understands the ffreep mnemonic, and
defines or undefines HAVE_AS_IX86_FFREEP as a result.  I'd initally
tried only testing for this on $target_os solaris*, but found it easier
to just test everywhere than to default to true on non-solaris targets.

Having established that the target assembler doesn't support ffreep,
the submission below offers two different approaches to the working
around the issue.  The first, and simpler, solution in config/i386/i386.h
is to simply force TARGET_USE_FFREEP to zero, when the assembler doesn't
support it.  The second alternate solution in config/i386/i386.c is to
instead generate ".word 0xc0df" instead of "ffreep %st(0)" when using
broken assemblers, allowing us to continue to generate/emit optimal
code.  There is some precedent for using ".byte" and ".word" directly
in the x86 backend.

I'm happy to go with either solution.  Working around brain-dead
assemblers by handling the instruction encoding ourselves is a hack,
but the alternative is to weaken GCC's performance relative to the
native compilers on such systems.


The following patch has been tested on x86_64-unknown-linux-gnu, with
a full "make bootstrap", all default languages, and regression tested
with a top-level "make -k check" with no new failures.  It's also been
partially tested (due to unrelated bootstrap failures) on
i386-pc-solaris2.10, where the configure test is confirmed to detect
the absence of ffreep, and the stage1 cc1 compiles and links fine.


Ok for mainline?  I'm interpreting this as a regression from previous
GCC releases, for example, gcc 3.4 could build g77, but mainline can't
(easily) build the equivalent gfortran.  I could dig deeper, testing
gcc-3.3, but I'm guessing the above "tenuous" argument is sufficient.

Thanks in advance,



2006-07-05  Roger Sayle  <roger@eyesopen.com>

	PR target/27968
	* configure.ac (HAVE_AS_IX86_FFREEP): On x86 targets check whether
	the configured assembler supports the x87's ffreep mnemonic.
	* configure: Regenerate.
	* config.in: Regenerate.

either
	* config/i386/i386.h (TARGET_USE_FFREEP): Honor HAVE_AS_IX86_FFREEP.

or
	* config/i386/i386.c (output_387_ffreep): New function.
	(output_fp_compare): Use output_387_ffreep to emit ffreep insns.
	(output_387_reg_move): Likewise.


Index: configure.ac
===================================================================
*** configure.ac	(revision 115195)
--- configure.ac	(working copy)
***************
*** 1,7 ****
  # configure.ac for GCC
  # Process this file with autoconf to generate a configuration script.

! # Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005
  # Free Software Foundation, Inc.

  #This file is part of GCC.
--- 1,7 ----
  # configure.ac for GCC
  # Process this file with autoconf to generate a configuration script.

! # Copyright 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006
  # Free Software Foundation, Inc.

  #This file is part of GCC.
*************** foo:	nop
*** 2815,2820 ****
--- 2815,2826 ----
        [AC_DEFINE(HAVE_AS_IX86_CMOV_SUN_SYNTAX, 1,
          [Define if your assembler supports the Sun syntax for cmov.])])

+     gcc_GAS_CHECK_FEATURE([ffreep mnemonic],
+       gcc_cv_as_ix86_ffreep,,,
+       [ffreep %st(1)],,
+       [AC_DEFINE(HAVE_AS_IX86_FFREEP, 1,
+         [Define if your assembler supports the ffreep mnemonic.])])
+
      # This one is used unconditionally by i386.[ch]; it is to be defined
      # to 1 if the feature is present, 0 otherwise.
      gcc_GAS_CHECK_FEATURE([GOTOFF in data],



Index: config/i386/i386.h
===================================================================
*** config/i386/i386.h	(revision 115195)
--- config/i386/i386.h	(working copy)
*************** extern int x86_prefetch_sse;
*** 212,218 ****
  #define TARGET_EPILOGUE_USING_MOVE (x86_epilogue_using_move & TUNEMASK)
  #define TARGET_PREFETCH_SSE (x86_prefetch_sse)
  #define TARGET_SHIFT1 (x86_shift1 & TUNEMASK)
- #define TARGET_USE_FFREEP (x86_use_ffreep & TUNEMASK)
  #define TARGET_REP_MOVL_OPTIMAL (x86_rep_movl_optimal & TUNEMASK)
  #define TARGET_INTER_UNIT_MOVES (x86_inter_unit_moves & TUNEMASK)
  #define TARGET_FOUR_JUMP_LIMIT (x86_four_jump_limit & TUNEMASK)
--- 212,217 ----
*************** extern int x86_prefetch_sse;
*** 221,226 ****
--- 220,231 ----
  #define TARGET_USE_INCDEC (x86_use_incdec & TUNEMASK)
  #define TARGET_PAD_RETURNS (x86_pad_returns & TUNEMASK)

+ #ifdef HAVE_AS_IX86_FFREEP
+ #define TARGET_USE_FFREEP (x86_use_ffreep & TUNEMASK)
+ #else
+ #define TARGET_USE_FFREEP 0
+ #endif
+
  #define ASSEMBLER_DIALECT (ix86_asm_dialect)

  #define TARGET_SSE_MATH ((ix86_fpmath & FPMATH_SSE) != 0)


Index: config/i386/i386.c
===================================================================
*** config/i386/i386.c	(revision 115195)
--- config/i386/i386.c	(working copy)
*************** output_fix_trunc (rtx insn, rtx *operand
*** 8641,8646 ****
--- 8641,8674 ----
    return "";
  }

+ /* Output code for x87 ffreep insn.  The OPNO argument, which may only
+    have the values zero or one, indicates the ffreep insn's operand
+    from the OPERANDS array.  */
+
+ static const char *
+ output_387_ffreep (rtx *operands ATTRIBUTE_UNUSED, int opno)
+ {
+   if (TARGET_USE_FFREEP)
+ #if HAVE_AS_IX86_FFREEP
+     return opno ? "ffreep\t%y1" : "ffreep\t%y0";
+ #else
+     switch (REGNO (operands[opno]))
+       {
+       case FIRST_STACK_REG + 0: return ".word\t0xc0df";
+       case FIRST_STACK_REG + 1: return ".word\t0xc1df";
+       case FIRST_STACK_REG + 2: return ".word\t0xc2df";
+       case FIRST_STACK_REG + 3: return ".word\t0xc3df";
+       case FIRST_STACK_REG + 4: return ".word\t0xc4df";
+       case FIRST_STACK_REG + 5: return ".word\t0xc5df";
+       case FIRST_STACK_REG + 6: return ".word\t0xc6df";
+       case FIRST_STACK_REG + 7: return ".word\t0xc7df";
+       }
+ #endif
+
+   return opno ? "fstp\t%y1" : "fstp\t%y0";
+ }
+
+
  /* Output code for INSN to compare OPERANDS.  EFLAGS_P is 1 when fcomi
     should be used.  UNORDERED_P is true when fucom should be used.  */

*************** output_fp_compare (rtx insn, rtx *operan
*** 8685,8691 ****
        if (stack_top_dies)
  	{
  	  output_asm_insn ("ftst\n\tfnstsw\t%0", operands);
! 	  return TARGET_USE_FFREEP ? "ffreep\t%y1" : "fstp\t%y1";
  	}
        else
  	return "ftst\n\tfnstsw\t%0";
--- 8713,8719 ----
        if (stack_top_dies)
  	{
  	  output_asm_insn ("ftst\n\tfnstsw\t%0", operands);
! 	  return output_387_ffreep (operands, 1);
  	}
        else
  	return "ftst\n\tfnstsw\t%0";
*************** output_fp_compare (rtx insn, rtx *operan
*** 8708,8714 ****
  	    output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands);
  	  else
  	    output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands);
! 	  return TARGET_USE_FFREEP ? "ffreep\t%y0" : "fstp\t%y0";
  	}
        else
  	{
--- 8736,8742 ----
  	    output_asm_insn ("fucomip\t{%y1, %0|%0, %y1}", operands);
  	  else
  	    output_asm_insn ("fcomip\t{%y1, %0|%0, %y1}", operands);
! 	  return output_387_ffreep (operands, 0);
  	}
        else
  	{
*************** output_387_reg_move (rtx insn, rtx *oper
*** 18807,18815 ****
    if (REG_P (operands[1])
        && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
      {
!       if (REGNO (operands[0]) == FIRST_STACK_REG
! 	  && TARGET_USE_FFREEP)
! 	return "ffreep\t%y0";
        return "fstp\t%y0";
      }
    if (STACK_TOP_P (operands[0]))
--- 18835,18842 ----
    if (REG_P (operands[1])
        && find_regno_note (insn, REG_DEAD, REGNO (operands[1])))
      {
!       if (REGNO (operands[0]) == FIRST_STACK_REG)
! 	return output_387_ffreep (operands, 0);
        return "fstp\t%y0";
      }
    if (STACK_TOP_P (operands[0]))


Roger
--


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]