This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Slight improvement to ia64 TFmode comparisons
- From: "Zack Weinberg" <zack at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 28 Oct 2003 17:23:21 -0800
- Subject: 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"