summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/ChangeLog18
-rw-r--r--gcc/builtins.c4
-rw-r--r--gcc/config/i386/i386.md38
-rw-r--r--gcc/genopinit.c1
-rw-r--r--gcc/optabs.c2
-rw-r--r--gcc/optabs.h5
-rw-r--r--gcc/reg-stack.c21
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/builtins-63.c28
9 files changed, 121 insertions, 0 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 8c0bbcbea07..ba55b7c30db 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,21 @@
+2007-01-31 Uros Bizjak <ubizjak@gmail.com>
+
+ * optabs.h (enum optab_index): Add new OTI_isinf.
+ (isinf_optab): Define corresponding macro.
+ * optabs.c (init_optabs): Initialize isinf_optab.
+ * genopinit.c (optabs): Implement isinf_optab using isinf?f2
+ patterns.
+ * builtins.c (mathfn_built_in): Handle BUILT_IN_ISINF{,F,L}.
+ (expand_builtin_interclass_mathfn): Expand BUILT_IN_ISINF{,F,L}
+ using isinf_optab.
+ (expand_builtin): Expand BUILT_IN_ISINF{,F,L} using
+ expand_builtin_interclass_mathfn.
+ * reg_stack.c (subst_stack_regs_pat): Handle UNSPEC_FXAM.
+ * config/i386/i386.md (UNSPEC_FXAM): New constant.
+ (fxam<mode>2_i387): New insn pattern.
+ (isinf<mode>2) New expander to implement isinf, isinff and isinfl
+ built-in functions as x87 inline asm.
+
2007-01-31 Kazu Hirata <kazu@codesourcery.com>
* gcc/config/arm/unwind-arm.h (_sleb128_t, _uleb128_t): New.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 5ba1eae5eb6..777206c83a0 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1676,6 +1676,7 @@ mathfn_built_in (tree type, enum built_in_function fn)
CASE_MATHFN (BUILT_IN_HYPOT)
CASE_MATHFN (BUILT_IN_ILOGB)
CASE_MATHFN (BUILT_IN_INF)
+ CASE_MATHFN (BUILT_IN_ISINF)
CASE_MATHFN (BUILT_IN_J0)
CASE_MATHFN (BUILT_IN_J1)
CASE_MATHFN (BUILT_IN_JN)
@@ -2198,6 +2199,8 @@ expand_builtin_interclass_mathfn (tree exp, rtx target, rtx subtarget)
{
CASE_FLT_FN (BUILT_IN_ILOGB):
errno_set = true; builtin_optab = ilogb_optab; break;
+ CASE_FLT_FN (BUILT_IN_ISINF):
+ builtin_optab = isinf_optab; break;
default:
gcc_unreachable ();
}
@@ -5923,6 +5926,7 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
CASE_FLT_FN (BUILT_IN_ILOGB):
if (! flag_unsafe_math_optimizations)
break;
+ CASE_FLT_FN (BUILT_IN_ISINF):
target = expand_builtin_interclass_mathfn (exp, target, subtarget);
if (target)
return target;
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index a9620e2242b..cfe48c446da 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -122,6 +122,7 @@
(UNSPEC_FIST 66)
(UNSPEC_F2XM1 67)
(UNSPEC_TAN 68)
+ (UNSPEC_FXAM 69)
; x87 Rounding
(UNSPEC_FRNDINT_FLOOR 70)
@@ -17597,6 +17598,43 @@
DONE;
})
+(define_insn "fxam<mode>2_i387"
+ [(set (match_operand:HI 0 "register_operand" "=a")
+ (unspec:HI
+ [(match_operand:X87MODEF 1 "register_operand" "f")]
+ UNSPEC_FXAM))]
+ "TARGET_USE_FANCY_MATH_387"
+ "fxam\n\tfnstsw\t%0"
+ [(set_attr "type" "multi")
+ (set_attr "unit" "i387")
+ (set_attr "mode" "<MODE>")])
+
+(define_expand "isinf<mode>2"
+ [(use (match_operand:SI 0 "register_operand" ""))
+ (use (match_operand:X87MODEF 1 "register_operand" ""))]
+ "TARGET_USE_FANCY_MATH_387
+ && (!(SSE_FLOAT_MODE_P (<MODE>mode) && TARGET_SSE_MATH)
+ || TARGET_MIX_SSE_I387)"
+{
+ rtx mask = GEN_INT (0x45);
+ rtx val = GEN_INT (0x05);
+
+ rtx cond;
+
+ rtx scratch = gen_reg_rtx (HImode);
+ rtx res = gen_reg_rtx (QImode);
+
+ emit_insn (gen_fxam<mode>2_i387 (scratch, operands[1]));
+ emit_insn (gen_andqi_ext_0 (scratch, scratch, mask));
+ emit_insn (gen_cmpqi_ext_3 (scratch, val));
+ cond = gen_rtx_fmt_ee (EQ, QImode,
+ gen_rtx_REG (CCmode, FLAGS_REG),
+ const0_rtx);
+ emit_insn (gen_rtx_SET (VOIDmode, res, cond));
+ emit_insn (gen_zero_extendqisi2 (operands[0], res));
+ DONE;
+})
+
;; Block operation instructions
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index ad72637b902..1e70c6d07a8 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -118,6 +118,7 @@ static const char * const optabs[] =
abs_optab->handlers[$A].insn_code = CODE_FOR_$(abs$F$a2$)",
"absv_optab->handlers[$A].insn_code = CODE_FOR_$(absv$I$a2$)",
"copysign_optab->handlers[$A].insn_code = CODE_FOR_$(copysign$F$a3$)",
+ "isinf_optab->handlers[$A].insn_code = CODE_FOR_$(isinf$a2$)",
"sqrt_optab->handlers[$A].insn_code = CODE_FOR_$(sqrt$a2$)",
"floor_optab->handlers[$A].insn_code = CODE_FOR_$(floor$a2$)",
"lfloor_optab->handlers[$B][$A].insn_code = CODE_FOR_$(lfloor$F$a$I$b2$)",
diff --git a/gcc/optabs.c b/gcc/optabs.c
index c7f16c29e59..e66c115c0c0 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -5378,6 +5378,8 @@ init_optabs (void)
atan_optab = init_optab (UNKNOWN);
copysign_optab = init_optab (UNKNOWN);
+ isinf_optab = init_optab (UNKNOWN);
+
strlen_optab = init_optab (UNKNOWN);
cbranch_optab = init_optab (UNKNOWN);
cmov_optab = init_optab (UNKNOWN);
diff --git a/gcc/optabs.h b/gcc/optabs.h
index 85d9ca7f32f..d3cfd742136 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -204,6 +204,9 @@ enum optab_index
/* Copy sign */
OTI_copysign,
+ /* Test for infinite value */
+ OTI_isinf,
+
/* Compare insn; two operands. */
OTI_cmp,
/* Used only for libcalls for unsigned comparisons. */
@@ -370,6 +373,8 @@ extern GTY(()) optab optab_table[OTI_MAX];
#define atan_optab (optab_table[OTI_atan])
#define copysign_optab (optab_table[OTI_copysign])
+#define isinf_optab (optab_table[OTI_isinf])
+
#define cmp_optab (optab_table[OTI_cmp])
#define ucmp_optab (optab_table[OTI_ucmp])
#define tst_optab (optab_table[OTI_tst])
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index 0df425eebeb..f21d833c00b 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -1629,6 +1629,27 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
replace_reg (src1, FIRST_STACK_REG);
break;
+ case UNSPEC_FXAM:
+
+ /* This insn only operate on the top of the stack. */
+
+ src1 = get_true_reg (&XVECEXP (pat_src, 0, 0));
+ emit_swap_insn (insn, regstack, *src1);
+
+ src1_note = find_regno_note (insn, REG_DEAD, REGNO (*src1));
+
+ replace_reg (src1, FIRST_STACK_REG);
+
+ if (src1_note)
+ {
+ remove_regno_note (insn, REG_DEAD,
+ REGNO (XEXP (src1_note, 0)));
+ emit_pop_insn (insn, regstack, XEXP (src1_note, 0),
+ EMIT_AFTER);
+ }
+
+ break;
+
case UNSPEC_SIN:
case UNSPEC_COS:
case UNSPEC_FRNDINT:
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index d28f8e6d5d7..97bf5f17fca 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2007-01-31 Uros Bizjak <ubizjak@gmail.com>
+
+ * gcc.dg/builtins-63.c: New test.
+
2007-01-31 Tobias Burnus <burnus@net-b.de>
PR fortran/27588
diff --git a/gcc/testsuite/gcc.dg/builtins-63.c b/gcc/testsuite/gcc.dg/builtins-63.c
new file mode 100644
index 00000000000..8fcbc68e6f1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-63.c
@@ -0,0 +1,28 @@
+/* Copyright (C) 2007 Free Software Foundation.
+
+ Check that isinf, isinff and isinfl built-in functions compile.
+
+ Written by Uros Bizjak, 31st January 2007. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+extern int isinf(double);
+extern int isinff(float);
+extern int isinfl(long double);
+
+int test1(double x)
+{
+ return isinf(x);
+}
+
+int test1f(float x)
+{
+ return isinff(x);
+}
+
+int test1l(long double x)
+{
+ return isinfl(x);
+}
+