aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog31
-rw-r--r--gcc/builtins.c14
-rw-r--r--gcc/config/i386/i386-protos.h1
-rw-r--r--gcc/config/i386/i386.c21
-rw-r--r--gcc/config/i386/i386.md174
-rw-r--r--gcc/genopinit.c2
-rw-r--r--gcc/optabs.c2
-rw-r--r--gcc/optabs.h5
-rw-r--r--gcc/reg-stack.c4
-rw-r--r--gcc/testsuite/ChangeLog4
-rw-r--r--gcc/testsuite/gcc.dg/builtins-40.c47
11 files changed, 303 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 0831dc0..0159b7a 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,34 @@
+2004-05-05 Uros Bizjak <uros@kss-loka.si>
+
+ * optabs.h (enum optab_index): Add new OTI_fmod and OTI_drem.
+ (fmod_optab): Define corresponding macros.
+ * optabs.c (init_optabs): Initialize fmod_optab and drem_optab.
+ * genopinit.c (optabs): Implement fmod_optab and drem_optab
+ using fmod?f3 and drem?f3 patterns.
+ * builtins.c (expand_builtin_mathfn_2): Handle BUILT_IN_FMOD{,F,L}
+ using fmod_optab and BUILT_IN_DREM{,F,L} using drem_optab.
+ (expand_builtin): Expand BUILT_IN_FMOD{,F,L} and
+ BUILT_IN_DREM{,F,L} using expand_builtin_mathfn_2 if
+ flag_unsafe_math_optimizations is set.
+
+ * reg-stack.c (subst_stack_regs_pat): Handle UNSPEC_FPREM_F,
+ UNSPEC_FPREM_U, UNSPEC_FPREM1_F and UNSPEC_FPREM1_U.
+
+ * config/i386/i386.c (ix86_emit_fp_unordered_jump): New function.
+ * config/i386/i386-protos.h (ix86_emit_fp_unordered_jump):
+ Prototype here.
+ * config/i386/i386.md (UNSPEC_FPREM_F, UNSPEC_FPREM_U,
+ UNSPEC_FPREM1_F, UNSPEC_FPREM1_U): New unspecs to represent x87's
+ fprem and fprem1 instructions.
+ (*x86_fnstsw_1): Change input parameter to (reg:CCFP 18).
+ Rename insn definition to x86_fnstsw_1.
+ (fpremxf4, fprem1xf4): New patterns to implement fprem and fprem1
+ x87 instructions.
+ (fmodsf3, fmoddf3, fmodxf3): New expanders to implement fmodf, fmod
+ and fmodl built-ins as inline x87 intrinsics.
+ (dremsf3, dremdf3, dremxf3): New expanders to implement dremf, drem
+ and dreml built-ins as inline x87 intrinsics.
+
2004-05-05 Roger Sayle <roger@eyesopen.com>
* reload1.c (inherit_piecemeal_p): Mark parameters potentially unused.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index c42a423..6126842 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -1793,6 +1793,14 @@ expand_builtin_mathfn_2 (tree exp, rtx target, rtx subtarget)
case BUILT_IN_ATAN2F:
case BUILT_IN_ATAN2L:
builtin_optab = atan2_optab; break;
+ case BUILT_IN_FMOD:
+ case BUILT_IN_FMODF:
+ case BUILT_IN_FMODL:
+ builtin_optab = fmod_optab; break;
+ case BUILT_IN_DREM:
+ case BUILT_IN_DREMF:
+ case BUILT_IN_DREML:
+ builtin_optab = drem_optab; break;
default:
abort ();
}
@@ -5364,6 +5372,12 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
case BUILT_IN_ATAN2:
case BUILT_IN_ATAN2F:
case BUILT_IN_ATAN2L:
+ case BUILT_IN_FMOD:
+ case BUILT_IN_FMODF:
+ case BUILT_IN_FMODL:
+ case BUILT_IN_DREM:
+ case BUILT_IN_DREMF:
+ case BUILT_IN_DREML:
if (! flag_unsafe_math_optimizations)
break;
target = expand_builtin_mathfn_2 (exp, target, subtarget);
diff --git a/gcc/config/i386/i386-protos.h b/gcc/config/i386/i386-protos.h
index d95be60..636d50b 100644
--- a/gcc/config/i386/i386-protos.h
+++ b/gcc/config/i386/i386-protos.h
@@ -182,6 +182,7 @@ extern bool ix86_fp_jump_nontrivial_p (enum rtx_code);
extern void x86_order_regs_for_local_alloc (void);
extern void x86_function_profiler (FILE *, int);
extern void x86_emit_floatuns (rtx [2]);
+extern void ix86_emit_fp_unordered_jump (rtx);
extern enum rtx_code ix86_reverse_condition (enum rtx_code, enum machine_mode);
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index 2890d04..a561d4f 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -15928,4 +15928,25 @@ output_387_reg_move (rtx insn, rtx *operands)
return "fst\t%y0";
}
+/* Output code to perform a conditional jump to LABEL, if C2 flag in
+ FP status register is set. */
+
+void
+ix86_emit_fp_unordered_jump (rtx label)
+{
+ rtx reg = gen_reg_rtx (HImode);
+ rtx temp;
+
+ emit_insn (gen_x86_fnstsw_1 (reg));
+ emit_insn (gen_x86_sahf_1 (reg));
+
+ temp = gen_rtx_REG (CCmode, FLAGS_REG);
+ temp = gen_rtx_UNORDERED (VOIDmode, temp, const0_rtx);
+ temp = gen_rtx_IF_THEN_ELSE (VOIDmode, temp,
+ gen_rtx_LABEL_REF (VOIDmode, label),
+ pc_rtx);
+ temp = gen_rtx_SET (VOIDmode, pc_rtx, temp);
+ emit_jump_insn (temp);
+}
+
#include "gt-i386.h"
diff --git a/gcc/config/i386/i386.md b/gcc/config/i386/i386.md
index 26132f1..e5edad4 100644
--- a/gcc/config/i386/i386.md
+++ b/gcc/config/i386/i386.md
@@ -129,6 +129,10 @@
(UNSPEC_XTRACT_EXP 85)
(UNSPEC_FSCALE_FRACT 86)
(UNSPEC_FSCALE_EXP 87)
+ (UNSPEC_FPREM_F 88)
+ (UNSPEC_FPREM_U 89)
+ (UNSPEC_FPREM1_F 90)
+ (UNSPEC_FPREM1_U 91)
; REP instruction
(UNSPEC_REP 75)
@@ -941,9 +945,9 @@
;; FP compares, step 2
;; Move the fpsw to ax.
-(define_insn "*x86_fnstsw_1"
+(define_insn "x86_fnstsw_1"
[(set (match_operand:HI 0 "register_operand" "=a")
- (unspec:HI [(reg 18)] UNSPEC_FNSTSW))]
+ (unspec:HI [(reg:CCFP 18)] UNSPEC_FNSTSW))]
"TARGET_80387"
"fnstsw\t%0"
[(set_attr "length" "2")
@@ -14858,6 +14862,172 @@
(set_attr "mode" "XF")
(set_attr "athlon_decode" "direct")])
+(define_insn "fpremxf4"
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (unspec:XF [(match_operand:XF 2 "register_operand" "0")
+ (match_operand:XF 3 "register_operand" "1")]
+ UNSPEC_FPREM_F))
+ (set (match_operand:XF 1 "register_operand" "=u")
+ (unspec:XF [(match_dup 2) (match_dup 3)]
+ UNSPEC_FPREM_U))
+ (set (reg:CCFP 18)
+ (unspec:CCFP [(const_int 0)] UNSPEC_NOP))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+ "fprem"
+ [(set_attr "type" "fpspc")
+ (set_attr "mode" "XF")])
+
+(define_expand "fmodsf3"
+ [(use (match_operand:SF 0 "register_operand" ""))
+ (use (match_operand:SF 1 "register_operand" ""))
+ (use (match_operand:SF 2 "register_operand" ""))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+{
+ rtx label = gen_label_rtx ();
+
+ rtx op1 = gen_reg_rtx (XFmode);
+ rtx op2 = gen_reg_rtx (XFmode);
+
+ emit_insn(gen_extendsfxf2 (op1, operands[1]));
+ emit_insn(gen_extendsfxf2 (op2, operands[2]));
+
+ emit_label (label);
+
+ emit_insn (gen_fpremxf4 (op1, op2, op1, op2));
+ ix86_emit_fp_unordered_jump (label);
+
+ emit_insn (gen_truncxfsf2_noop (operands[0], op1));
+ DONE;
+})
+
+(define_expand "fmoddf3"
+ [(use (match_operand:DF 0 "register_operand" ""))
+ (use (match_operand:DF 1 "register_operand" ""))
+ (use (match_operand:DF 2 "register_operand" ""))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+{
+ rtx label = gen_label_rtx ();
+
+ rtx op1 = gen_reg_rtx (XFmode);
+ rtx op2 = gen_reg_rtx (XFmode);
+
+ emit_insn (gen_extenddfxf2 (op1, operands[1]));
+ emit_insn (gen_extenddfxf2 (op2, operands[2]));
+
+ emit_label (label);
+
+ emit_insn (gen_fpremxf4 (op1, op2, op1, op2));
+ ix86_emit_fp_unordered_jump (label);
+
+ emit_insn (gen_truncxfdf2_noop (operands[0], op1));
+ DONE;
+})
+
+(define_expand "fmodxf3"
+ [(use (match_operand:XF 0 "register_operand" ""))
+ (use (match_operand:XF 1 "register_operand" ""))
+ (use (match_operand:XF 2 "register_operand" ""))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+{
+ rtx label = gen_label_rtx ();
+
+ emit_label (label);
+
+ emit_insn (gen_fpremxf4 (operands[1], operands[2],
+ operands[1], operands[2]));
+ ix86_emit_fp_unordered_jump (label);
+
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+})
+
+(define_insn "fprem1xf4"
+ [(set (match_operand:XF 0 "register_operand" "=f")
+ (unspec:XF [(match_operand:XF 2 "register_operand" "0")
+ (match_operand:XF 3 "register_operand" "1")]
+ UNSPEC_FPREM1_F))
+ (set (match_operand:XF 1 "register_operand" "=u")
+ (unspec:XF [(match_dup 2) (match_dup 3)]
+ UNSPEC_FPREM1_U))
+ (set (reg:CCFP 18)
+ (unspec:CCFP [(const_int 0)] UNSPEC_NOP))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+ "fprem1"
+ [(set_attr "type" "fpspc")
+ (set_attr "mode" "XF")])
+
+(define_expand "dremsf3"
+ [(use (match_operand:SF 0 "register_operand" ""))
+ (use (match_operand:SF 1 "register_operand" ""))
+ (use (match_operand:SF 2 "register_operand" ""))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+{
+ rtx label = gen_label_rtx ();
+
+ rtx op1 = gen_reg_rtx (XFmode);
+ rtx op2 = gen_reg_rtx (XFmode);
+
+ emit_insn(gen_extendsfxf2 (op1, operands[1]));
+ emit_insn(gen_extendsfxf2 (op2, operands[2]));
+
+ emit_label (label);
+
+ emit_insn (gen_fprem1xf4 (op1, op2, op1, op2));
+ ix86_emit_fp_unordered_jump (label);
+
+ emit_insn (gen_truncxfsf2_noop (operands[0], op1));
+ DONE;
+})
+
+(define_expand "dremdf3"
+ [(use (match_operand:DF 0 "register_operand" ""))
+ (use (match_operand:DF 1 "register_operand" ""))
+ (use (match_operand:DF 2 "register_operand" ""))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+{
+ rtx label = gen_label_rtx ();
+
+ rtx op1 = gen_reg_rtx (XFmode);
+ rtx op2 = gen_reg_rtx (XFmode);
+
+ emit_insn (gen_extenddfxf2 (op1, operands[1]));
+ emit_insn (gen_extenddfxf2 (op2, operands[2]));
+
+ emit_label (label);
+
+ emit_insn (gen_fprem1xf4 (op1, op2, op1, op2));
+ ix86_emit_fp_unordered_jump (label);
+
+ emit_insn (gen_truncxfdf2_noop (operands[0], op1));
+ DONE;
+})
+
+(define_expand "dremxf3"
+ [(use (match_operand:XF 0 "register_operand" ""))
+ (use (match_operand:XF 1 "register_operand" ""))
+ (use (match_operand:XF 2 "register_operand" ""))]
+ "! TARGET_NO_FANCY_MATH_387 && TARGET_80387
+ && flag_unsafe_math_optimizations"
+{
+ rtx label = gen_label_rtx ();
+
+ emit_label (label);
+
+ emit_insn (gen_fprem1xf4 (operands[1], operands[2],
+ operands[1], operands[2]));
+ ix86_emit_fp_unordered_jump (label);
+
+ emit_move_insn (operands[0], operands[1]);
+ DONE;
+})
+
(define_insn "*sindf2"
[(set (match_operand:DF 0 "register_operand" "=f")
(unspec:DF [(match_operand:DF 1 "register_operand" "0")] UNSPEC_SIN))]
diff --git a/gcc/genopinit.c b/gcc/genopinit.c
index 8793449..307849a 100644
--- a/gcc/genopinit.c
+++ b/gcc/genopinit.c
@@ -91,6 +91,8 @@ static const char * const optabs[] =
"udivmod_optab->handlers[$A].insn_code = CODE_FOR_$(udivmod$a4$)",
"smod_optab->handlers[$A].insn_code = CODE_FOR_$(mod$a3$)",
"umod_optab->handlers[$A].insn_code = CODE_FOR_$(umod$a3$)",
+ "fmod_optab->handlers[$A].insn_code = CODE_FOR_$(fmod$a3$)",
+ "drem_optab->handlers[$A].insn_code = CODE_FOR_$(drem$a3$)",
"ftrunc_optab->handlers[$A].insn_code = CODE_FOR_$(ftrunc$F$a2$)",
"and_optab->handlers[$A].insn_code = CODE_FOR_$(and$a3$)",
"ior_optab->handlers[$A].insn_code = CODE_FOR_$(ior$a3$)",
diff --git a/gcc/optabs.c b/gcc/optabs.c
index 1632ecf..719fbb4 100644
--- a/gcc/optabs.c
+++ b/gcc/optabs.c
@@ -5328,6 +5328,8 @@ init_optabs (void)
udivmod_optab = init_optab (UNKNOWN);
smod_optab = init_optab (MOD);
umod_optab = init_optab (UMOD);
+ fmod_optab = init_optab (UNKNOWN);
+ drem_optab = init_optab (UNKNOWN);
ftrunc_optab = init_optab (UNKNOWN);
and_optab = init_optab (AND);
ior_optab = init_optab (IOR);
diff --git a/gcc/optabs.h b/gcc/optabs.h
index a7aac19..84d8957 100644
--- a/gcc/optabs.h
+++ b/gcc/optabs.h
@@ -93,6 +93,9 @@ enum optab_index
/* Signed remainder */
OTI_smod,
OTI_umod,
+ /* Floating point remainder functions */
+ OTI_fmod,
+ OTI_drem,
/* Convert float to integer in float fmt */
OTI_ftrunc,
@@ -245,6 +248,8 @@ extern GTY(()) optab optab_table[OTI_MAX];
#define udivmod_optab (optab_table[OTI_udivmod])
#define smod_optab (optab_table[OTI_smod])
#define umod_optab (optab_table[OTI_umod])
+#define fmod_optab (optab_table[OTI_fmod])
+#define drem_optab (optab_table[OTI_drem])
#define ftrunc_optab (optab_table[OTI_ftrunc])
#define and_optab (optab_table[OTI_and])
#define ior_optab (optab_table[OTI_ior])
diff --git a/gcc/reg-stack.c b/gcc/reg-stack.c
index 8464ab4..bab401f 100644
--- a/gcc/reg-stack.c
+++ b/gcc/reg-stack.c
@@ -1779,6 +1779,8 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
break;
case UNSPEC_FSCALE_FRACT:
+ case UNSPEC_FPREM_F:
+ case UNSPEC_FPREM1_F:
/* These insns operate on the top two stack slots.
first part of double input, double output insn. */
@@ -1808,6 +1810,8 @@ subst_stack_regs_pat (rtx insn, stack regstack, rtx pat)
break;
case UNSPEC_FSCALE_EXP:
+ case UNSPEC_FPREM_U:
+ case UNSPEC_FPREM1_U:
/* These insns operate on the top two stack slots./
second part of double input, double output insn. */
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index aeff648..c08a35e 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,7 @@
+2004-05-05 Uros Bizjak <uros@kss-loka.si>
+
+ * gcc.dg/builtins-40.c: New test.
+
2004-05-05 Richard Sandiford <rsandifo@redhat.com>
* gcc.dg/torture/mips-hilo-2.c: Provide dummy __mips16 version.
diff --git a/gcc/testsuite/gcc.dg/builtins-40.c b/gcc/testsuite/gcc.dg/builtins-40.c
new file mode 100644
index 0000000..405c872
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtins-40.c
@@ -0,0 +1,47 @@
+/* Copyright (C) 2004 Free Software Foundation.
+
+ Check that fmod, fmodf, fmodl, drem, dremf and dreml
+ built-in functions compile.
+
+ Written by Uros Bizjak, 5th May 2004. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -ffast-math" } */
+
+extern double fmod(double, double);
+extern double drem(double, double);
+extern float fmodf(float, float);
+extern float dremf(float, float);
+extern long double fmodl(long double, long double);
+extern long double dreml(long double, long double);
+
+
+double test1(double x, double y)
+{
+ return fmod(x, y);
+}
+
+double test2(double x, double y)
+{
+ return drem(x, y);
+}
+
+float test1f(float x, float y)
+{
+ return fmodf(x, y);
+}
+
+float test2f(float x, float y)
+{
+ return dremf(x, y);
+}
+
+long double test1l(long double x, long double y)
+{
+ return fmodl(x, y);
+}
+
+long double test2l(long double x, long double y)
+{
+ return dreml(x, y);
+}