aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc')
-rw-r--r--gcc/ChangeLog25
-rw-r--r--gcc/builtins.c20
-rw-r--r--gcc/config/i386/i386.c138
-rw-r--r--gcc/config/i386/i386.h2
-rw-r--r--gcc/config/i386/i386.opt4
-rw-r--r--gcc/doc/extend.texi29
-rw-r--r--gcc/doc/invoke.texi8
-rw-r--r--gcc/expr.h1
-rw-r--r--gcc/gcc.c8
-rw-r--r--gcc/target-def.h2
-rw-r--r--gcc/target.h4
-rw-r--r--gcc/testsuite/ChangeLog8
-rw-r--r--gcc/testsuite/gcc.target/i386/sselibm-1.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/sselibm-2.c12
-rw-r--r--gcc/testsuite/gcc.target/i386/sselibm-3.c19
-rw-r--r--gcc/testsuite/gcc.target/i386/sselibm-4.c39
-rw-r--r--gcc/testsuite/gcc.target/i386/sselibm-5.c55
17 files changed, 384 insertions, 2 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 58a53d8..03b7cfe 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,4 +1,29 @@
2006-01-31 Richard Guenther <rguenther@suse.de>
+
+ * doc/invoke.texi (-msselibm): Document.
+ * target.h (expand_library_builtin): New target hook.
+ * builtins.c (expand_builtin): Use expand_library_builtin.
+ (default_expand_library_builtin): New function.
+ * gcc.c (LINK_GCC_MATH_SPEC): Define.
+ (LINK_COMMAND_SPEC): Handle %(link_gcc_math).
+ (link_gcc_math_spec): Declare.
+ (static_specs): Add link_gcc_math_spec.
+ * expr.h (default_expand_library_builtin): Declare.
+ * target-def.h (TARGET_EXPAND_LIBRARY_BUILTIN): Define.
+ (TARGET_INITIALIZER): Add TARGET_EXPAND_LIBRARY_BUILTIN.
+ * config/i386/i386.h: Provide LINK_GCC_MATH_SPEC.
+ * config/i386/i386.opt (msselibm): New target option.
+ * config/i386/i386.c (ix86_builtin_function_variants): New array.
+ (ix86_init_sse_abi_builtins): New function.
+ (ix86_expand_library_builtin): Likewise.
+ (TARGET_EXPAND_LIBRARY_BUILTIN): Define.
+ (override_options): Handle error conditions wrt -msselibm.
+ (ix86_builtins): Add function codes for SSE2 ABI builtins.
+ (ix86_init_builtins): Call ix86_init_sse_abi_builtins.
+ * doc/extend.texi (__builtin_sse2_*): Document new target specific
+ builtins.
+
+2006-01-31 Richard Guenther <rguenther@suse.de>
Paolo Bonzini <bonzini@gnu.org>
* doc/install.texi (--disable-libgcc-math): Document.
diff --git a/gcc/builtins.c b/gcc/builtins.c
index bb113dc..fd551da 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5560,6 +5560,14 @@ expand_builtin (tree exp, rtx target, rtx subtarget, enum machine_mode mode,
if (DECL_BUILT_IN_CLASS (fndecl) == BUILT_IN_MD)
return targetm.expand_builtin (exp, target, subtarget, mode, ignore);
+ else
+ {
+ /* Try expanding the builtin via the generic target hook. */
+ rtx tmp = targetm.expand_library_builtin (exp, target, subtarget,
+ mode, ignore);
+ if (tmp != NULL_RTX)
+ return tmp;
+ }
/* When not optimizing, generate calls to library functions for a certain
set of builtins. */
@@ -8913,6 +8921,18 @@ default_expand_builtin (tree exp ATTRIBUTE_UNUSED,
return NULL_RTX;
}
+/* Default target-specific library builtin expander that does nothing. */
+
+rtx
+default_expand_library_builtin (tree exp ATTRIBUTE_UNUSED,
+ rtx target ATTRIBUTE_UNUSED,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore ATTRIBUTE_UNUSED)
+{
+ return NULL_RTX;
+}
+
/* Returns true is EXP represents data that would potentially reside
in a readonly section. */
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index c9029f0..ed23c86 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -1050,6 +1050,9 @@ int ix86_section_threshold = 65536;
/* Prefix built by ASM_GENERATE_INTERNAL_LABEL. */
char internal_label_prefix[16];
int internal_label_prefix_len;
+
+/* Table for BUILT_IN_NORMAL to BUILT_IN_MD mapping. */
+static GTY(()) tree ix86_builtin_function_variants[(int) END_BUILTINS];
static bool ix86_handle_option (size_t, const char *, int);
static void output_pic_addr_const (FILE *, rtx, int);
@@ -1084,6 +1087,7 @@ static int ix86_issue_rate (void);
static int ix86_adjust_cost (rtx, rtx, rtx, int);
static int ia32_multipass_dfa_lookahead (void);
static void ix86_init_mmx_sse_builtins (void);
+static void ix86_init_sse_abi_builtins (void);
static rtx x86_this_parameter (tree);
static void x86_output_mi_thunk (FILE *, tree, HOST_WIDE_INT,
HOST_WIDE_INT, tree);
@@ -1140,6 +1144,7 @@ static bool ix86_pass_by_reference (CUMULATIVE_ARGS *, enum machine_mode,
tree, bool);
static void ix86_init_builtins (void);
static rtx ix86_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+static rtx ix86_expand_library_builtin (tree, rtx, rtx, enum machine_mode, int);
static const char *ix86_mangle_fundamental_type (tree);
static tree ix86_stack_protect_fail (void);
static rtx ix86_internal_arg_pointer (void);
@@ -1204,6 +1209,8 @@ static section *x86_64_elf_select_section (tree decl, int reloc,
#define TARGET_INIT_BUILTINS ix86_init_builtins
#undef TARGET_EXPAND_BUILTIN
#define TARGET_EXPAND_BUILTIN ix86_expand_builtin
+#undef TARGET_EXPAND_LIBRARY_BUILTIN
+#define TARGET_EXPAND_LIBRARY_BUILTIN ix86_expand_library_builtin
#undef TARGET_ASM_FUNCTION_EPILOGUE
#define TARGET_ASM_FUNCTION_EPILOGUE ix86_output_function_epilogue
@@ -1886,6 +1893,16 @@ override_options (void)
&& ! TARGET_SSE)
error ("-msseregparm used without SSE enabled");
+ /* Accept -msselibm only if at least SSE support is enabled. */
+ if (TARGET_SSELIBM
+ && ! TARGET_SSE2)
+ error ("-msselibm used without SSE2 enabled");
+
+ /* Ignore -msselibm on 64bit targets. */
+ if (TARGET_SSELIBM
+ && TARGET_64BIT)
+ error ("-msselibm used on a 64bit target");
+
ix86_fpmath = TARGET_FPMATH_DEFAULT;
if (ix86_fpmath_string != 0)
@@ -14235,6 +14252,28 @@ enum ix86_builtins
IX86_BUILTIN_VEC_SET_V8HI,
IX86_BUILTIN_VEC_SET_V4HI,
+ /* SSE2 ABI functions. */
+ IX86_BUILTIN_SSE2_ACOS,
+ IX86_BUILTIN_SSE2_ACOSF,
+ IX86_BUILTIN_SSE2_ASIN,
+ IX86_BUILTIN_SSE2_ASINF,
+ IX86_BUILTIN_SSE2_ATAN,
+ IX86_BUILTIN_SSE2_ATANF,
+ IX86_BUILTIN_SSE2_ATAN2,
+ IX86_BUILTIN_SSE2_ATAN2F,
+ IX86_BUILTIN_SSE2_COS,
+ IX86_BUILTIN_SSE2_COSF,
+ IX86_BUILTIN_SSE2_EXP,
+ IX86_BUILTIN_SSE2_EXPF,
+ IX86_BUILTIN_SSE2_LOG10,
+ IX86_BUILTIN_SSE2_LOG10F,
+ IX86_BUILTIN_SSE2_LOG,
+ IX86_BUILTIN_SSE2_LOGF,
+ IX86_BUILTIN_SSE2_SIN,
+ IX86_BUILTIN_SSE2_SINF,
+ IX86_BUILTIN_SSE2_TAN,
+ IX86_BUILTIN_SSE2_TANF,
+
IX86_BUILTIN_MAX
};
@@ -14616,6 +14655,8 @@ ix86_init_builtins (void)
{
if (TARGET_MMX)
ix86_init_mmx_sse_builtins ();
+ if (TARGET_SSE2)
+ ix86_init_sse_abi_builtins ();
}
/* Set up all the MMX/SSE builtins. This is not called if TARGET_MMX
@@ -15255,6 +15296,70 @@ ix86_init_mmx_sse_builtins (void)
def_builtin (MASK_SSE | MASK_3DNOW_A, "__builtin_ia32_vec_set_v4hi",
ftype, IX86_BUILTIN_VEC_SET_V4HI);
}
+#undef def_builtin
+
+/* Set up all the SSE ABI builtins that we may use to override
+ the normal builtins. */
+static void
+ix86_init_sse_abi_builtins (void)
+{
+ tree dbl, flt, dbl2, flt2;
+
+ /* Bail out in case the template definitions are not available. */
+ if (! built_in_decls [BUILT_IN_SIN]
+ || ! built_in_decls [BUILT_IN_SINF]
+ || ! built_in_decls [BUILT_IN_ATAN2]
+ || ! built_in_decls [BUILT_IN_ATAN2F])
+ return;
+
+ /* Build the function types as variants of the existing ones. */
+ dbl = build_variant_type_copy (TREE_TYPE (built_in_decls [BUILT_IN_SIN]));
+ TYPE_ATTRIBUTES (dbl)
+ = tree_cons (get_identifier ("sseregparm"),
+ NULL_TREE, TYPE_ATTRIBUTES (dbl));
+ flt = build_variant_type_copy (TREE_TYPE (built_in_decls [BUILT_IN_SINF]));
+ TYPE_ATTRIBUTES (flt)
+ = tree_cons (get_identifier ("sseregparm"),
+ NULL_TREE, TYPE_ATTRIBUTES (flt));
+ dbl2 = build_variant_type_copy (TREE_TYPE (built_in_decls [BUILT_IN_ATAN2]));
+ TYPE_ATTRIBUTES (dbl2)
+ = tree_cons (get_identifier ("sseregparm"),
+ NULL_TREE, TYPE_ATTRIBUTES (dbl2));
+ flt2 = build_variant_type_copy (TREE_TYPE (built_in_decls [BUILT_IN_ATAN2F]));
+ TYPE_ATTRIBUTES (flt2)
+ = tree_cons (get_identifier ("sseregparm"),
+ NULL_TREE, TYPE_ATTRIBUTES (flt2));
+
+#define def_builtin(capname, name, type) \
+ ix86_builtin_function_variants [BUILT_IN_ ## capname] \
+ = lang_hooks.builtin_function ("__builtin_sse2_" # name, type, \
+ IX86_BUILTIN_SSE2_ ## capname, \
+ BUILT_IN_NORMAL, \
+ "__libm_sse2_" # name, NULL_TREE)
+
+ def_builtin (ACOS, acos, dbl);
+ def_builtin (ACOSF, acosf, flt);
+ def_builtin (ASIN, asin, dbl);
+ def_builtin (ASINF, asinf, flt);
+ def_builtin (ATAN, atan, dbl);
+ def_builtin (ATANF, atanf, flt);
+ def_builtin (ATAN2, atan2, dbl2);
+ def_builtin (ATAN2F, atan2f, flt2);
+ def_builtin (COS, cos, dbl);
+ def_builtin (COSF, cosf, flt);
+ def_builtin (EXP, exp, dbl);
+ def_builtin (EXPF, expf, flt);
+ def_builtin (LOG10, log10, dbl);
+ def_builtin (LOG10F, log10f, flt);
+ def_builtin (LOG, log, dbl);
+ def_builtin (LOGF, logf, flt);
+ def_builtin (SIN, sin, dbl);
+ def_builtin (SINF, sinf, flt);
+ def_builtin (TAN, tan, dbl);
+ def_builtin (TANF, tanf, flt);
+
+#undef def_builtin
+}
/* Errors in the source file can cause expand_expr to return const0_rtx
where we expect a vector. To avoid crashing, use one of the vector
@@ -16089,6 +16194,39 @@ ix86_expand_builtin (tree exp, rtx target, rtx subtarget ATTRIBUTE_UNUSED,
gcc_unreachable ();
}
+/* Expand an expression EXP that calls a built-in library function,
+ with result going to TARGET if that's convenient
+ (and in mode MODE if that's convenient).
+ SUBTARGET may be used as the target for computing one of EXP's operands.
+ IGNORE is nonzero if the value is to be ignored. */
+
+static rtx
+ix86_expand_library_builtin (tree exp, rtx target,
+ rtx subtarget ATTRIBUTE_UNUSED,
+ enum machine_mode mode ATTRIBUTE_UNUSED,
+ int ignore)
+{
+ enum built_in_function fncode;
+ tree fndecl, newfn, call;
+
+ /* Try expanding builtin math functions to the SSE2 ABI variants. */
+ if (!TARGET_SSELIBM)
+ return NULL_RTX;
+
+ fncode = builtin_mathfn_code (exp);
+ if (!ix86_builtin_function_variants [(int)fncode])
+ return NULL_RTX;
+
+ fndecl = get_callee_fndecl (exp);
+ if (DECL_RTL_SET_P (fndecl))
+ return NULL_RTX;
+
+ /* Build the redirected call and expand it. */
+ newfn = ix86_builtin_function_variants [(int)fncode];
+ call = build_function_call_expr (newfn, TREE_OPERAND (exp, 1));
+ return expand_call (call, target, ignore);
+}
+
/* Store OPERAND to the memory after reload is completed. This means
that we can't easily use assign_stack_local. */
rtx
diff --git a/gcc/config/i386/i386.h b/gcc/config/i386/i386.h
index 628a5dd..307cc97 100644
--- a/gcc/config/i386/i386.h
+++ b/gcc/config/i386/i386.h
@@ -497,6 +497,8 @@ extern int x86_prefetch_sse;
#define EXTRA_SPECS \
{ "cc1_cpu", CC1_CPU_SPEC }, \
SUBTARGET_EXTRA_SPECS
+
+#define LINK_GCC_MATH_SPEC "%{msselibm:-lgcc-math}"
/* target machine storage layout */
diff --git a/gcc/config/i386/i386.opt b/gcc/config/i386/i386.opt
index 2a51fcb..9cd29b4 100644
--- a/gcc/config/i386/i386.opt
+++ b/gcc/config/i386/i386.opt
@@ -201,6 +201,10 @@ msseregparm
Target RejectNegative Mask(SSEREGPARM)
Use SSE register passing conventions for SF and DF mode
+msselibm
+Target Mask(SSELIBM)
+Use SSE2 ABI libgcc-math routines if using SSE math
+
msvr3-shlib
Target Report Mask(SVR3_SHLIB)
Uninitialized locals in .bss
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 9d5a8f6..a20349d 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -6804,6 +6804,35 @@ v2sf __builtin_ia32_pswapdsf (v2sf)
v2si __builtin_ia32_pswapdsi (v2si)
@end smallexample
+The following built-in functions are available when @option{-msse2}
+is used. All of them generate calls to an SSE2 ABI IEEE754 math intrinsic
+that is part of the name. Rather than using these directly you may
+want them automatically substituted for calls to the regular intrinsics
+using the @option{-msselibm}.
+
+@smallexample
+double __builtin_sse2_acos (double)
+float __builtin_sse2_acosf (float)
+double __builtin_sse2_asin (double)
+float __builtin_sse2_asinf (float)
+double __builtin_sse2_atan (double)
+float __builtin_sse2_atanf (float)
+double __builtin_sse2_atan2 (double, double)
+float __builtin_sse2_atan2f (float, float)
+double __builtin_sse2_cos (double)
+float __builtin_sse2_cosf (float)
+double __builtin_sse2_exp (double)
+float __builtin_sse2_expf (float)
+double __builtin_sse2_log10 (double)
+float __builtin_sse2_log10f (float)
+double __builtin_sse2_log (double)
+float __builtin_sse2_logf (float)
+double __builtin_sse2_sin (double)
+float __builtin_sse2_sinf (float)
+double __builtin_sse2_tan (double)
+float __builtin_sse2_tanf (float)
+@end smallexample
+
@node MIPS DSP Built-in Functions
@subsection MIPS DSP Built-in Functions
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index d8f69e8..8edff2a 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -528,7 +528,7 @@ Objective-C and Objective-C++ Dialects}.
-mno-fp-ret-in-387 -msoft-float -msvr3-shlib @gol
-mno-wide-multiply -mrtd -malign-double @gol
-mpreferred-stack-boundary=@var{num} @gol
--mmmx -msse -msse2 -msse3 -m3dnow @gol
+-mmmx -msse -msse2 -msse3 -m3dnow -msselibm @gol
-mthreads -mno-align-stringops -minline-all-stringops @gol
-mpush-args -maccumulate-outgoing-args -m128bit-long-double @gol
-m96bit-long-double -mregparm=@var{num} -msseregparm @gol
@@ -9437,6 +9437,12 @@ supported architecture, using the appropriate flags. In particular,
the file containing the CPU detection code should be compiled without
these options.
+@item -msselibm
+@opindex msselibm
+Use special versions of certain libm routines that come with an SSE
+ABI and an SSE implementation. Useful together with @option{-mfpmath=sse}
+to avoid moving values between SSE registers and the x87 FP stack.
+
@item -mpush-args
@itemx -mno-push-args
@opindex mpush-args
diff --git a/gcc/expr.h b/gcc/expr.h
index b7387cf..2be4100 100644
--- a/gcc/expr.h
+++ b/gcc/expr.h
@@ -338,6 +338,7 @@ extern rtx expand_builtin (tree, rtx, rtx, enum machine_mode, int);
extern tree std_build_builtin_va_list (void);
extern void std_expand_builtin_va_start (tree, rtx);
extern rtx default_expand_builtin (tree, rtx, rtx, enum machine_mode, int);
+extern rtx default_expand_library_builtin (tree, rtx, rtx, enum machine_mode, int);
extern void expand_builtin_setjmp_setup (rtx, rtx);
extern void expand_builtin_setjmp_receiver (rtx);
extern rtx expand_builtin_saveregs (void);
diff --git a/gcc/gcc.c b/gcc/gcc.c
index 0bd34ee..a2cefe7 100644
--- a/gcc/gcc.c
+++ b/gcc/gcc.c
@@ -680,6 +680,10 @@ proper position among the other output files. */
#endif
#endif
+#ifndef LINK_GCC_MATH_SPEC
+#define LINK_GCC_MATH_SPEC ""
+#endif
+
#ifndef LINK_PIE_SPEC
#ifdef HAVE_LD_PIE
#define LINK_PIE_SPEC "%{pie:-pie} "
@@ -702,7 +706,7 @@ proper position among the other output files. */
%{static:} %{L*} %(mfwrap) %{fopenmp:%:include(libgomp.spec)%(link_gomp)}\
%(link_libgcc) %o %(mflib)\
%{fprofile-arcs|fprofile-generate|coverage:-lgcov}\
- %{!nostdlib:%{!nodefaultlibs:%(link_ssp) %(link_gcc_c_sequence)}}\
+ %{!nostdlib:%{!nodefaultlibs:%(link_gcc_math) %(link_ssp) %(link_gcc_c_sequence)}}\
%{!A:%{!nostdlib:%{!nostartfiles:%E}}} %{T*} }}}}}}"
#endif
@@ -733,6 +737,7 @@ static const char *cc1_spec = CC1_SPEC;
static const char *cc1plus_spec = CC1PLUS_SPEC;
static const char *link_gcc_c_sequence_spec = LINK_GCC_C_SEQUENCE_SPEC;
static const char *link_ssp_spec = LINK_SSP_SPEC;
+static const char *link_gcc_math_spec = LINK_GCC_MATH_SPEC;
static const char *asm_spec = ASM_SPEC;
static const char *asm_final_spec = ASM_FINAL_SPEC;
static const char *link_spec = LINK_SPEC;
@@ -1540,6 +1545,7 @@ static struct spec_list static_specs[] =
INIT_STATIC_SPEC ("cc1plus", &cc1plus_spec),
INIT_STATIC_SPEC ("link_gcc_c_sequence", &link_gcc_c_sequence_spec),
INIT_STATIC_SPEC ("link_ssp", &link_ssp_spec),
+ INIT_STATIC_SPEC ("link_gcc_math", &link_gcc_math_spec),
INIT_STATIC_SPEC ("endfile", &endfile_spec),
INIT_STATIC_SPEC ("link", &link_spec),
INIT_STATIC_SPEC ("lib", &lib_spec),
diff --git a/gcc/target-def.h b/gcc/target-def.h
index 7599101..ffeec2e 100644
--- a/gcc/target-def.h
+++ b/gcc/target-def.h
@@ -320,6 +320,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
/* In builtins.c. */
#define TARGET_INIT_BUILTINS hook_void_void
#define TARGET_EXPAND_BUILTIN default_expand_builtin
+#define TARGET_EXPAND_LIBRARY_BUILTIN default_expand_library_builtin
#define TARGET_RESOLVE_OVERLOADED_BUILTIN NULL
#define TARGET_FOLD_BUILTIN hook_tree_tree_tree_bool_null
@@ -578,6 +579,7 @@ Foundation, 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
TARGET_ALIGN_ANON_BITFIELD, \
TARGET_INIT_BUILTINS, \
TARGET_EXPAND_BUILTIN, \
+ TARGET_EXPAND_LIBRARY_BUILTIN, \
TARGET_RESOLVE_OVERLOADED_BUILTIN, \
TARGET_FOLD_BUILTIN, \
TARGET_MANGLE_FUNDAMENTAL_TYPE, \
diff --git a/gcc/target.h b/gcc/target.h
index 36f2463..2ac0882 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -369,6 +369,10 @@ struct gcc_target
rtx (* expand_builtin) (tree exp, rtx target, rtx subtarget,
enum machine_mode mode, int ignore);
+ /* Expand a target-specific library builtin. */
+ rtx (* expand_library_builtin) (tree exp, rtx target, rtx subtarget,
+ enum machine_mode mode, int ignore);
+
/* Select a replacement for a target-specific builtin. This is done
*before* regular type checking, and so allows the target to implement
a crude form of function overloading. The result is a complete
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 5c8e59b..47f6623 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,3 +1,11 @@
+2006-01-31 Richard Guenther <rguenther@suse.de>
+
+ * gcc.target/i386/sselibm-1.c: New testcase.
+ * gcc.target/i386/sselibm-2.c: Likewise.
+ * gcc.target/i386/sselibm-3.c: Likewise.
+ * gcc.target/i386/sselibm-4.c: Likewise.
+ * gcc.target/i386/sselibm-5.c: Likewise.
+
2005-01-30 Erik Edelmann <eedelman@gcc.gnu.org>
PR fortran/24266
diff --git a/gcc/testsuite/gcc.target/i386/sselibm-1.c b/gcc/testsuite/gcc.target/i386/sselibm-1.c
new file mode 100644
index 0000000..1e9f0c6
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sselibm-1.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-msse2 -mfpmath=sse" } */
+/* { dg-require-effective-target ilp32 } */
+
+double sin(double);
+
+double foo(double x)
+{
+ return sin(x);
+}
+
+/* { dg-final { scan-assembler-not "__libm_sse2_sin" } } */
diff --git a/gcc/testsuite/gcc.target/i386/sselibm-2.c b/gcc/testsuite/gcc.target/i386/sselibm-2.c
new file mode 100644
index 0000000..8450262
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sselibm-2.c
@@ -0,0 +1,12 @@
+/* { dg-do compile } */
+/* { dg-options "-msse2 -mfpmath=sse -msselibm" } */
+/* { dg-require-effective-target ilp32 } */
+
+double sin(double);
+
+double foo(double x)
+{
+ return sin(x);
+}
+
+/* { dg-final { scan-assembler "__libm_sse2_sin" } } */
diff --git a/gcc/testsuite/gcc.target/i386/sselibm-3.c b/gcc/testsuite/gcc.target/i386/sselibm-3.c
new file mode 100644
index 0000000..76c1134
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sselibm-3.c
@@ -0,0 +1,19 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -msse2 -mfpmath=sse -msselibm" } */
+/* { dg-require-effective-target ilp32 } */
+
+double sin(double);
+double (*mysin)(double) = sin;
+
+double f1(double x)
+{
+ return sin(x);
+}
+
+double f2(double x)
+{
+ /* Verify we do not expand the following call to __libm_sse2_sin. */
+ return (*mysin)(x);
+}
+
+/* { dg-final { scan-assembler-times "__libm_sse2_sin" 1 } } */
diff --git a/gcc/testsuite/gcc.target/i386/sselibm-4.c b/gcc/testsuite/gcc.target/i386/sselibm-4.c
new file mode 100644
index 0000000..ad20bce
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sselibm-4.c
@@ -0,0 +1,39 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -msse2 -mfpmath=sse -msselibm" } */
+/* { dg-require-effective-target ilp32 } */
+
+extern double acos(double);
+extern double asin(double);
+extern double atan(double);
+extern double atan2(double, double);
+extern double cos(double);
+extern double exp(double);
+extern double log10(double);
+extern double log(double);
+extern double sin(double);
+extern double tan(double);
+
+extern float acosf(float);
+extern float asinf(float);
+extern float atanf(float);
+extern float atan2f(float, float);
+extern float cosf(float);
+extern float expf(float);
+extern float log10f(float);
+extern float logf(float);
+extern float sinf(float);
+extern float tanf(float);
+
+float foof(float x)
+{
+ return acosf(x) + asinf(x) + atanf(x) + atan2f(x, x) + cosf(x) + expf(x)
+ + log10f(x) + logf(x) + sinf(x) + tanf(x);
+}
+
+double foo(double x)
+{
+ return acos(x) + asin(x) + atan(x) + atan2(x, x) + cos(x) + exp(x)
+ + log10(x) + log(x) + sin(x) + tan(x);
+}
+
+/* { dg-final { scan-assembler-times "__libm_sse2" 20 } } */
diff --git a/gcc/testsuite/gcc.target/i386/sselibm-5.c b/gcc/testsuite/gcc.target/i386/sselibm-5.c
new file mode 100644
index 0000000..c749319
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/sselibm-5.c
@@ -0,0 +1,55 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -msse2 -mfpmath=sse -msselibm" } */
+/* { dg-require-effective-target ilp32 } */
+
+extern double acos(double);
+extern double asin(double);
+extern double atan(double);
+extern double atan2(double, double);
+extern double cos(double);
+extern double exp(double);
+extern double log10(double);
+extern double log(double);
+extern double sin(double);
+extern double tan(double);
+
+extern float acosf(float);
+extern float asinf(float);
+extern float atanf(float);
+extern float atan2f(float, float);
+extern float cosf(float);
+extern float expf(float);
+extern float log10f(float);
+extern float logf(float);
+extern float sinf(float);
+extern float tanf(float);
+
+float foof(float x)
+{
+ return __builtin_sse2_acosf(x)
+ + __builtin_sse2_asinf(x)
+ + __builtin_sse2_atanf(x)
+ + __builtin_sse2_atan2f(x, x)
+ + __builtin_sse2_cosf(x)
+ + __builtin_sse2_expf(x)
+ + __builtin_sse2_log10f(x)
+ + __builtin_sse2_logf(x)
+ + __builtin_sse2_sinf(x)
+ + __builtin_sse2_tanf(x);
+}
+
+double foo(double x)
+{
+ return __builtin_sse2_acos(x)
+ + __builtin_sse2_asin(x)
+ + __builtin_sse2_atan(x)
+ + __builtin_sse2_atan2(x, x)
+ + __builtin_sse2_cos(x)
+ + __builtin_sse2_exp(x)
+ + __builtin_sse2_log10(x)
+ + __builtin_sse2_log(x)
+ + __builtin_sse2_sin(x)
+ + __builtin_sse2_tan(x);
+}
+
+/* { dg-final { scan-assembler-times "__libm_sse2" 20 } } */