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]

Slight improvement to ia64 TFmode comparisons


The system-provided library routine for this, _U_Qfcmp, takes three
arguments: the two comparands, and a magic number that indicates what
comparison to do.  To date we've been wrapping this routine with a
bunch of libgcc routines that take two arguments.  This patch teaches
us to call _U_Qfcmp directly.  Proper handling for isunordered() falls
out as a side effect, and we could do UNEQ, UNLT, UNLE, UNGT, UNGE,
LTGT as well (but that would require more extensive changes to ia64.md
to be worthwhile).  The old libgcc routines are preserved for backward
compatibility.

The change adds an additional instruction to the setup for the
function call; in my tests this can almost always fit in a slot that
had to take a NOP before, so there's no code size increase.  Given

  extern void a(void);
  void b(long double x, long double y)
  {
    if (x > y) a();
  }

the difference is

    --- before ---                       --- after ---

    .mmi                                 .mmi
    mov r40 = r33                        mov r40 = r33
    mov r42 = r35                        mov r42 = r35
    mov r39 = r32                        mov r39 = r32
    .mmb                              |  .mfi
    nop 0                             |  addl r43 = 17, r0
    mov r41 = r34                     |  nop 0
    nop 0                             |  mov r41 = r34
    ;;                                   ;;
    .bbb                                 .bbb
    nop 0                                nop 0
    nop 0                                nop 0
    br.call.sptk.many b0 = _U_Qfgt#   |  br.call.sptk.many b0 = _U_Qfcmp#
    ;;                                   ;;
    .mmb                                 .mmb
    nop 0                                nop 0
    cmp.ne p6, p7 = 0, r8                cmp.ne p6, p7 = 0, r8
    nop 0                                nop 0
    .mib                                 .mib
    mov r1 = r38                         mov r1 = r38
    mov b0 = r36                         mov b0 = r36
    (p6) br.cond.dpnt .L5                (p6) br.cond.dpnt .L5

You can see that this just affects the packing of the second bundle.
(The code is still not as good as what acc generates for this test,
mainly because acc is capable of predicating calls, and is more
sensible about where to put the stop bits.  On the other hand, acc
does save and restore PR, whatever that is, for no apparent reason.)

Bootstrapped ia64-hp-hpux11.23.

zw

        * config/ia64/ia64.c (cmptf_libfunc): New static.
        (ia64_expand_compare): Add logic to open-code calls to
        _U_Qfcmp for TFmode comparisons.
        (ia64_hpux_init_libfuncs): Initialize cmptf_libfunc.
        Set libfuncs for TFmode eq/ne/gt/ge/lt/gt to 0; these should
        never be generated anymore.
        * config/ia64/ia64.md (cmptf): New expander.

===================================================================
Index: config/ia64/ia64.c
--- config/ia64/ia64.c	25 Oct 2003 02:03:39 -0000	1.256
+++ config/ia64/ia64.c	29 Oct 2003 01:18:02 -0000
@@ -1465,6 +1465,8 @@ spill_xfmode_operand (rtx in, int force)
 /* Emit comparison instruction if necessary, returning the expression
    that holds the compare result in the proper mode.  */
 
+static GTY(()) rtx cmptf_libfunc;
+
 rtx
 ia64_expand_compare (enum rtx_code code, enum machine_mode mode)
 {
@@ -1480,6 +1482,59 @@ ia64_expand_compare (enum rtx_code code,
       else
 	abort ();
     }
+  /* HPUX TFmode compare requires a library call to _U_Qfcmp, which takes a
+     magic number as its third argument, that indicates what to do.
+     The return value is an integer to be compared against zero.  */
+  else if (TARGET_HPUX && GET_MODE (op0) == TFmode)
+    {
+      enum qfcmp_magic {
+	QCMP_INV = 1,	/* Raise FP_INVALID on SNaN as a side effect.  */
+	QCMP_UNORD = 2,
+	QCMP_EQ = 4,
+	QCMP_LT = 8,
+	QCMP_GT = 16
+      } magic;
+      enum rtx_code ncode;
+      rtx ret, insns;
+      if (GET_MODE (op1) != TFmode)
+	abort ();
+      switch (code)
+	{
+	  /* 1 = equal, 0 = not equal.  Equality operators do
+	     not raise FP_INVALID when given an SNaN operand.  */
+	case EQ:        magic = QCMP_EQ;                  ncode = NE; break;
+	case NE:        magic = QCMP_EQ;                  ncode = EQ; break;
+	  /* isunordered() from C99.  */
+	case UNORDERED: magic = QCMP_UNORD;               ncode = NE; break;
+	  /* Relational operators raise FP_INVALID when given
+	     an SNaN operand.  */
+	case LT:        magic = QCMP_LT        |QCMP_INV; ncode = NE; break;
+	case LE:        magic = QCMP_LT|QCMP_EQ|QCMP_INV; ncode = NE; break;
+	case GT:        magic = QCMP_GT        |QCMP_INV; ncode = NE; break;
+	case GE:        magic = QCMP_GT|QCMP_EQ|QCMP_INV; ncode = NE; break;
+	  /* FUTURE: Implement UNEQ, UNLT, UNLE, UNGT, UNGE, LTGT.
+	     Expanders for buneq etc. weuld have to be added to ia64.md
+	     for this to be useful.  */
+	default: abort ();
+	}
+
+      start_sequence ();
+
+      ret = emit_library_call_value (cmptf_libfunc, 0, LCT_CONST, DImode, 3,
+				     op0, TFmode, op1, TFmode,
+				     GEN_INT (magic), DImode);
+      cmp = gen_reg_rtx (BImode);
+      emit_insn (gen_rtx_SET (VOIDmode, cmp,
+			      gen_rtx_fmt_ee (ncode, BImode,
+					      ret, const0_rtx)));
+
+      insns = get_insns ();
+      end_sequence ();
+
+      emit_libcall_block (insns, cmp, cmp,
+			  gen_rtx_fmt_ee (code, BImode, op0, op1));
+      code = NE;
+    }
   else
     {
       cmp = gen_reg_rtx (BImode);
@@ -8324,12 +8379,16 @@ ia64_hpux_init_libfuncs (void)
   set_optab_libfunc (abs_optab, TFmode, "_U_Qfabs");
   set_optab_libfunc (neg_optab, TFmode, "_U_Qfneg");
 
-  set_optab_libfunc (eq_optab, TFmode, "_U_Qfeq");
-  set_optab_libfunc (ne_optab, TFmode, "_U_Qfne");
-  set_optab_libfunc (gt_optab, TFmode, "_U_Qfgt");
-  set_optab_libfunc (ge_optab, TFmode, "_U_Qfge");
-  set_optab_libfunc (lt_optab, TFmode, "_U_Qflt");
-  set_optab_libfunc (le_optab, TFmode, "_U_Qfle");
+  /* ia64_expand_compare uses this.  */
+  cmptf_libfunc = init_one_libfunc ("_U_Qfcmp");
+
+  /* These should never be used.  */
+  set_optab_libfunc (eq_optab, TFmode, 0);
+  set_optab_libfunc (ne_optab, TFmode, 0);
+  set_optab_libfunc (gt_optab, TFmode, 0);
+  set_optab_libfunc (ge_optab, TFmode, 0);
+  set_optab_libfunc (lt_optab, TFmode, 0);
+  set_optab_libfunc (le_optab, TFmode, 0);
 
   set_conv_libfunc (sext_optab,   TFmode, SFmode, "_U_Qfcnvff_sgl_to_quad");
   set_conv_libfunc (sext_optab,   TFmode, DFmode, "_U_Qfcnvff_dbl_to_quad");
===================================================================
Index: config/ia64/ia64.md
--- config/ia64/ia64.md	25 Oct 2003 02:03:40 -0000	1.115
+++ config/ia64/ia64.md	29 Oct 2003 01:18:04 -0000
@@ -4009,6 +4009,17 @@
   DONE;
 })
 
+(define_expand "cmptf"
+  [(set (cc0)
+        (compare (match_operand:TF 0 "gr_register_operand" "")
+  		 (match_operand:TF 1 "gr_register_operand" "")))]
+  "TARGET_HPUX"
+{
+  ia64_compare_op0 = operands[0];
+  ia64_compare_op1 = operands[1];
+  DONE;
+})
+
 (define_insn "*cmpsi_normal"
   [(set (match_operand:BI 0 "register_operand" "=c")
 	(match_operator:BI 1 "normal_comparison_operator"


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