===================================================================
@@ -531,7 +531,8 @@ gfc_builtin_function (tree decl)
return decl;
}
-/* So far we need just these 4 attribute types. */
+/* So far we need just these 5 attribute types. */
+#define ATTR_LEAF_LIST (ECF_LEAF)
#define ATTR_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF)
#define ATTR_NOTHROW_LEAF_MALLOC_LIST (ECF_NOTHROW | ECF_LEAF | ECF_MALLOC)
#define ATTR_CONST_NOTHROW_LEAF_LIST (ECF_NOTHROW | ECF_LEAF | ECF_CONST)
===================================================================
@@ -11351,8 +11351,16 @@ build_atomic_assign (location_t loc, tree lhs, enu
add_stmt (func_call);
params->truncate (0);
- /* TODO if (!integral) issue feholdexcept (&fenv); */
+ /* Create the expressions for floating-point environment
+ manipulation, if required. */
+ bool need_fenv = FLOAT_TYPE_P (lhs_type) || FLOAT_TYPE_P (rhs_type);
+ tree hold_call = NULL_TREE, clear_call = NULL_TREE, update_call = NULL_TREE;
+ if (need_fenv)
+ targetm.atomic_assign_expand_fenv (&hold_call, &clear_call, &update_call);
+ if (hold_call)
+ add_stmt (hold_call);
+
/* loop: */
add_stmt (loop_label);
@@ -11386,7 +11394,8 @@ build_atomic_assign (location_t loc, tree lhs, enu
SET_EXPR_LOCATION (stmt, loc);
add_stmt (stmt);
- /* TODO if (!integral) issue feclearexcept (FE_ALL_EXCEPT); */
+ if (clear_call)
+ add_stmt (clear_call);
/* goto loop; */
goto_stmt = build1 (GOTO_EXPR, void_type_node, loop_decl);
@@ -11396,7 +11405,8 @@ build_atomic_assign (location_t loc, tree lhs, enu
/* done: */
add_stmt (done_label);
- /* TODO If (!integral) issue feupdateenv (&fenv) */
+ if (update_call)
+ add_stmt (update_call);
/* Finish the compound statement. */
compound_stmt = c_end_compound_stmt (loc, compound_stmt, false);
===================================================================
@@ -11357,3 +11357,7 @@ The default value of this hook is based on target'
@deftypefn {Target Hook} {unsigned int} TARGET_ATOMIC_ALIGN_FOR_MODE (enum machine_mode @var{mode})
If defined, this function returns an appropriate alignment in bits for an atomic object of machine_mode @var{mode}. If 0 is returned then the default alignment for the specified mode is used.
@end deftypefn
+
+@deftypefn {Target Hook} void TARGET_ATOMIC_ASSIGN_EXPAND_FENV (tree *@var{hold}, tree *@var{clear}, tree *@var{update})
+ISO C11 requires atomic compound assignments that may raise floating-point exceptions to raise exceptions corresponding to the arithmetic operation whose result was successfully stored in a compare-and-exchange sequence. This requires code equivalent to calls to @code{feholdexcept}, @code{feclearexcept} and @code{feupdateenv} to be generated at appropriate points in the compare-and-exchange sequence. This hook should set @code{*@var{hold}} to an expression equivalent to the call to @code{feholdexcept}, @code{*@var{clear}} to an expression equivalent to the call to @code{feclearexcept} and @code{*@var{update}} to an expression equivalent to the call to @code{feupdateenv}. The three expressions are @code{NULL_TREE} on entry to the hook and may be left as @code{NULL_TREE} if no code is required in a particular place. The default implementation leaves all three expressions as @code{NULL_TREE}. The @code{__atomic_feraiseexcept} function from @code{libatomic} may be of use as part of the code generated in @code{*@var{update}}.
+@end deftypefn
===================================================================
@@ -8390,3 +8390,5 @@ and the associated definitions of those functions.
@hook TARGET_HAS_IFUNC_P
@hook TARGET_ATOMIC_ALIGN_FOR_MODE
+
+@hook TARGET_ATOMIC_ASSIGN_EXPAND_FENV
===================================================================
@@ -5135,6 +5135,25 @@ DEFHOOK
unsigned int, (enum machine_mode mode),
hook_uint_mode_0)
+DEFHOOK
+(atomic_assign_expand_fenv,
+"ISO C11 requires atomic compound assignments that may raise floating-point\
+ exceptions to raise exceptions corresponding to the arithmetic operation\
+ whose result was successfully stored in a compare-and-exchange sequence. \
+ This requires code equivalent to calls to @code{feholdexcept},\
+ @code{feclearexcept} and @code{feupdateenv} to be generated at\
+ appropriate points in the compare-and-exchange sequence. This hook should\
+ set @code{*@var{hold}} to an expression equivalent to the call to\
+ @code{feholdexcept}, @code{*@var{clear}} to an expression equivalent to\
+ the call to @code{feclearexcept} and @code{*@var{update}} to an expression\
+ equivalent to the call to @code{feupdateenv}. The three expressions are\
+ @code{NULL_TREE} on entry to the hook and may be left as @code{NULL_TREE}\
+ if no code is required in a particular place. The default implementation\
+ leaves all three expressions as @code{NULL_TREE}. The\
+ @code{__atomic_feraiseexcept} function from @code{libatomic} may be of use\
+ as part of the code generated in @code{*@var{update}}.",
+ void, (tree *hold, tree *clear, tree *update),
+ default_atomic_assign_expand_fenv)
/* Leave the boolean fields at the end. */
===================================================================
@@ -600,3 +600,9 @@ DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_SIGNAL_FENCE,
"__atomic_signal_fence",
BT_FN_VOID_INT, ATTR_NOTHROW_LEAF_LIST)
+/* This one is actually a function in libatomic and not expected to be
+ inlined, declared here for convenience of targets generating calls
+ to it. */
+DEF_SYNC_BUILTIN (BUILT_IN_ATOMIC_FERAISEEXCEPT,
+ "__atomic_feraiseexcept",
+ BT_FN_VOID_INT, ATTR_LEAF_LIST)
===================================================================
@@ -1567,4 +1567,11 @@ default_canonicalize_comparison (int *, rtx *, rtx
{
}
+/* Default implementation of TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */
+
+void
+default_atomic_assign_expand_fenv (tree *, tree *, tree *)
+{
+}
+
#include "gt-targhooks.h"
===================================================================
@@ -202,3 +202,4 @@ extern void default_asm_output_ident_directive (co
extern enum machine_mode default_cstore_mode (enum insn_code);
extern bool default_member_type_forces_blk (const_tree, enum machine_mode);
+extern void default_atomic_assign_expand_fenv (tree *, tree *, tree *);
===================================================================
@@ -42806,6 +42806,76 @@ ix86_memmodel_check (unsigned HOST_WIDE_INT val)
return val;
}
+/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV. */
+
+static void
+ix86_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update)
+{
+ if (!TARGET_80387 && !TARGET_SSE_MATH)
+ return;
+ tree exceptions_var = create_tmp_var (integer_type_node, NULL);
+ if (TARGET_80387)
+ {
+ /* TODO */
+ }
+ if (TARGET_SSE_MATH)
+ {
+ tree mxcsr_orig_var = create_tmp_var (unsigned_type_node, NULL);
+ tree mxcsr_mod_var = create_tmp_var (unsigned_type_node, NULL);
+ tree stmxcsr = ix86_builtins[IX86_BUILTIN_STMXCSR];
+ tree ldmxcsr = ix86_builtins[IX86_BUILTIN_LDMXCSR];
+ tree stmxcsr_hold_call = build_call_expr (stmxcsr, 0);
+ tree hold_assign_orig = build2 (MODIFY_EXPR, unsigned_type_node,
+ mxcsr_orig_var, stmxcsr_hold_call);
+ tree hold_mod_val = build2 (BIT_IOR_EXPR, unsigned_type_node,
+ mxcsr_orig_var,
+ build_int_cst (unsigned_type_node, 0x1f80));
+ hold_mod_val = build2 (BIT_AND_EXPR, unsigned_type_node, hold_mod_val,
+ build_int_cst (unsigned_type_node, 0xffffffc0));
+ tree hold_assign_mod = build2 (MODIFY_EXPR, unsigned_type_node,
+ mxcsr_mod_var, hold_mod_val);
+ tree ldmxcsr_hold_call = build_call_expr (ldmxcsr, 1, mxcsr_mod_var);
+ tree hold_all = build2 (COMPOUND_EXPR, unsigned_type_node,
+ hold_assign_orig, hold_assign_mod);
+ hold_all = build2 (COMPOUND_EXPR, void_type_node, hold_all,
+ ldmxcsr_hold_call);
+ if (*hold)
+ *hold = build2 (COMPOUND_EXPR, void_type_node, *hold, hold_all);
+ else
+ *hold = hold_all;
+ tree ldmxcsr_clear_call = build_call_expr (ldmxcsr, 1, mxcsr_mod_var);
+ if (*clear)
+ *clear = build2 (COMPOUND_EXPR, void_type_node, *clear,
+ ldmxcsr_clear_call);
+ else
+ *clear = ldmxcsr_clear_call;
+ tree stxmcsr_update_call = build_call_expr (stmxcsr, 0);
+ tree exceptions_sse = fold_convert (integer_type_node,
+ stxmcsr_update_call);
+ if (*update)
+ {
+ tree exceptions_mod = build2 (BIT_IOR_EXPR, integer_type_node,
+ exceptions_var, exceptions_sse);
+ tree exceptions_assign = build2 (MODIFY_EXPR, integer_type_node,
+ exceptions_var, exceptions_mod);
+ *update = build2 (COMPOUND_EXPR, integer_type_node, *update,
+ exceptions_assign);
+ }
+ else
+ *update = build2 (MODIFY_EXPR, integer_type_node,
+ exceptions_var, exceptions_sse);
+ tree ldmxcsr_update_call = build_call_expr (ldmxcsr, 1, mxcsr_orig_var);
+ *update = build2 (COMPOUND_EXPR, void_type_node, *update,
+ ldmxcsr_update_call);
+ }
+ tree atomic_feraiseexcept
+ = builtin_decl_implicit (BUILT_IN_ATOMIC_FERAISEEXCEPT);
+ tree atomic_feraiseexcept_call = build_call_expr (atomic_feraiseexcept,
+ 1, exceptions_var);
+ *update = build2 (COMPOUND_EXPR, void_type_node, *update,
+ atomic_feraiseexcept_call);
+}
+
/* Initialize the GCC target structure. */
#undef TARGET_RETURN_IN_MEMORY
#define TARGET_RETURN_IN_MEMORY ix86_return_in_memory
@@ -42913,6 +42983,9 @@ ix86_memmodel_check (unsigned HOST_WIDE_INT val)
#undef TARGET_MEMMODEL_CHECK
#define TARGET_MEMMODEL_CHECK ix86_memmodel_check
+#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV
+#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV ix86_atomic_assign_expand_fenv
+
#ifdef HAVE_AS_TLS
#undef TARGET_HAVE_TLS
#define TARGET_HAVE_TLS true
===================================================================
@@ -0,0 +1,208 @@
+/* Test for _Atomic in C11. Test that compare-and-exchange is
+ operating properly when operations on the same variable are carried
+ out in two threads. */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors -pthread -D_POSIX_C_SOURCE=200809L" } */
+/* { dg-require-effective-target pthread } */
+
+#include <stdint.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define ITER_COUNT 10000
+
+static volatile _Atomic bool thread_ready;
+
+/* Generate test code (with NAME used to name functions and variables)
+ for atomic compound assignments to a variable of type LHSTYPE. The
+ variable is initialized to INIT, then PRE var POST is executed
+ ITER_COUNT times in each of two threads, and the final result
+ should be FINAL. A function test_main_##NAME is generated that
+ returns nonzero on failure, zero on success. */
+
+#define TEST_FUNCS(NAME, LHSTYPE, PRE, POST, INIT, FINAL) \
+ \
+static volatile _Atomic LHSTYPE var_##NAME = (INIT); \
+ \
+static void * \
+test_thread_##NAME (void *arg) \
+{ \
+ thread_ready = true; \
+ for (int i = 0; i < ITER_COUNT; i++) \
+ PRE var_##NAME POST; \
+ return NULL; \
+} \
+ \
+static int \
+test_main_##NAME (void) \
+{ \
+ thread_ready = false; \
+ pthread_t thread_id; \
+ int pret = pthread_create (&thread_id, NULL, test_thread_##NAME, \
+ NULL); \
+ if (pret != 0) \
+ { \
+ printf ("pthread_create failed: %d\n", pret); \
+ return 1; \
+ } \
+ while (!thread_ready) \
+ ; \
+ for (int i = 0; i < ITER_COUNT; i++) \
+ PRE var_##NAME POST; \
+ pthread_join (thread_id, NULL); \
+ if (var_##NAME != (FINAL)) \
+ { \
+ printf (#NAME " failed\n"); \
+ return 1; \
+ } \
+ else \
+ { \
+ printf (#NAME " passed\n"); \
+ return 0; \
+ } \
+}
+
+TEST_FUNCS (uint8_add, uint8_t, , += 1, 0, (uint8_t) 20000)
+TEST_FUNCS (uint8_add_3, uint8_t, , += 3, 0, (uint8_t) 60000)
+TEST_FUNCS (uint16_add, uint16_t, , += 1, 0, (uint16_t) 20000)
+TEST_FUNCS (uint16_add_3, uint16_t, , += 3, 0, (uint16_t) 60000)
+TEST_FUNCS (uint32_add, uint32_t, , += 1, 0, (uint32_t) 20000)
+TEST_FUNCS (uint32_add_3, uint32_t, , += 3, 0, (uint32_t) 60000)
+TEST_FUNCS (uint64_add, uint64_t, , += 1, 0, (uint64_t) 20000)
+TEST_FUNCS (uint64_add_3, uint64_t, , += 3, 0, (uint64_t) 60000)
+TEST_FUNCS (uint64_add_neg, uint64_t, , += 1, -10000, (uint64_t) 10000)
+TEST_FUNCS (float_add, float, , += 1, 0, 20000)
+TEST_FUNCS (double_add, double, , += 1, 0, 20000)
+TEST_FUNCS (long_double_add, long double, , += 1, 0, 20000)
+TEST_FUNCS (complex_float_add, _Complex float, , += 1, 0, 20000)
+TEST_FUNCS (complex_double_add, _Complex double, , += 1, 0, 20000)
+TEST_FUNCS (complex_long_double_add, _Complex long double, , += 1, 0, 20000)
+TEST_FUNCS (uint8_postinc, uint8_t, , ++, 0, (uint8_t) 20000)
+TEST_FUNCS (uint16_postinc, uint16_t, , ++, 0, (uint16_t) 20000)
+TEST_FUNCS (uint32_postinc, uint32_t, , ++, 0, (uint32_t) 20000)
+TEST_FUNCS (uint64_postinc, uint64_t, , ++, 0, (uint64_t) 20000)
+TEST_FUNCS (uint64_postinc_neg, uint64_t, , ++, -10000, (uint64_t) 10000)
+TEST_FUNCS (float_postinc, float, , ++, 0, 20000)
+TEST_FUNCS (double_postinc, double, , ++, 0, 20000)
+TEST_FUNCS (long_double_postinc, long double, , ++, 0, 20000)
+TEST_FUNCS (uint8_preinc, uint8_t, ++, , 0, (uint8_t) 20000)
+TEST_FUNCS (uint16_preinc, uint16_t, ++, , 0, (uint16_t) 20000)
+TEST_FUNCS (uint32_preinc, uint32_t, ++, , 0, (uint32_t) 20000)
+TEST_FUNCS (uint64_preinc, uint64_t, ++, , 0, (uint64_t) 20000)
+TEST_FUNCS (uint64_preinc_neg, uint64_t, ++, , -10000, (uint64_t) 10000)
+TEST_FUNCS (float_preinc, float, ++, , 0, 20000)
+TEST_FUNCS (double_preinc, double, ++, , 0, 20000)
+TEST_FUNCS (long_double_preinc, long double, ++, , 0, 20000)
+TEST_FUNCS (uint8_sub, uint8_t, , -= 1, 0, (uint8_t) -20000)
+TEST_FUNCS (uint8_sub_3, uint8_t, , -= 3, 0, (uint8_t) -60000)
+TEST_FUNCS (uint16_sub, uint16_t, , -= 1, 0, (uint16_t) -20000)
+TEST_FUNCS (uint16_sub_3, uint16_t, , -= 3, 0, (uint16_t) -60000)
+TEST_FUNCS (uint32_sub, uint32_t, , -= 1, 0, (uint32_t) -20000)
+TEST_FUNCS (uint32_sub_3, uint32_t, , -= 3, 0, (uint32_t) -60000)
+TEST_FUNCS (uint64_sub, uint64_t, , -= 1, 0, (uint64_t) -20000)
+TEST_FUNCS (uint64_sub_3, uint64_t, , -= 3, 0, (uint64_t) -60000)
+TEST_FUNCS (uint64_sub_neg, uint64_t, , -= 1, 10000, (uint64_t) -10000)
+TEST_FUNCS (float_sub, float, , -= 1, 0, -20000)
+TEST_FUNCS (double_sub, double, , -= 1, 0, -20000)
+TEST_FUNCS (long_double_sub, long double, , -= 1, 0, -20000)
+TEST_FUNCS (complex_float_sub, _Complex float, , -= 1, 0, -20000)
+TEST_FUNCS (complex_double_sub, _Complex double, , -= 1, 0, -20000)
+TEST_FUNCS (complex_long_double_sub, _Complex long double, , -= 1, 0, -20000)
+TEST_FUNCS (uint8_postdec, uint8_t, , --, 0, (uint8_t) -20000)
+TEST_FUNCS (uint16_postdec, uint16_t, , --, 0, (uint16_t) -20000)
+TEST_FUNCS (uint32_postdec, uint32_t, , --, 0, (uint32_t) -20000)
+TEST_FUNCS (uint64_postdec, uint64_t, , --, 0, (uint64_t) -20000)
+TEST_FUNCS (uint64_postdec_neg, uint64_t, , --, 10000, (uint64_t) -10000)
+TEST_FUNCS (float_postdec, float, , --, 0, -20000)
+TEST_FUNCS (double_postdec, double, , --, 0, -20000)
+TEST_FUNCS (long_double_postdec, long double, , --, 0, -20000)
+TEST_FUNCS (uint8_predec, uint8_t, --, , 0, (uint8_t) -20000)
+TEST_FUNCS (uint16_predec, uint16_t, --, , 0, (uint16_t) -20000)
+TEST_FUNCS (uint32_predec, uint32_t, --, , 0, (uint32_t) -20000)
+TEST_FUNCS (uint64_predec, uint64_t, --, , 0, (uint64_t) -20000)
+TEST_FUNCS (uint64_predec_neg, uint64_t, --, , 10000, (uint64_t) -10000)
+TEST_FUNCS (float_predec, float, --, , 0, -20000)
+TEST_FUNCS (double_predec, double, --, , 0, -20000)
+TEST_FUNCS (long_double_predec, long double, --, , 0, -20000)
+TEST_FUNCS (uint8_mul, uint8_t, , *= 3, 1, (uint8_t) 0x81)
+TEST_FUNCS (uint16_mul, uint16_t, , *= 3, 1, (uint16_t) 0x9681)
+TEST_FUNCS (uint32_mul, uint32_t, , *= 3, 1, (uint32_t) 0x62b49681U)
+TEST_FUNCS (uint64_mul, uint64_t, , *= 3, 1, (uint64_t) 0xcd926beb62b49681ULL)
+
+int
+main (void)
+{
+ int ret = 0;
+ ret |= test_main_uint8_add ();
+ ret |= test_main_uint8_add_3 ();
+ ret |= test_main_uint16_add ();
+ ret |= test_main_uint16_add_3 ();
+ ret |= test_main_uint32_add ();
+ ret |= test_main_uint32_add_3 ();
+ ret |= test_main_uint64_add ();
+ ret |= test_main_uint64_add_3 ();
+ ret |= test_main_uint64_add_neg ();
+ ret |= test_main_float_add ();
+ ret |= test_main_double_add ();
+ ret |= test_main_long_double_add ();
+ ret |= test_main_complex_float_add ();
+ ret |= test_main_complex_double_add ();
+ ret |= test_main_complex_long_double_add ();
+ ret |= test_main_uint8_postinc ();
+ ret |= test_main_uint16_postinc ();
+ ret |= test_main_uint32_postinc ();
+ ret |= test_main_uint64_postinc ();
+ ret |= test_main_uint64_postinc_neg ();
+ ret |= test_main_float_postinc ();
+ ret |= test_main_double_postinc ();
+ ret |= test_main_long_double_postinc ();
+ ret |= test_main_uint8_preinc ();
+ ret |= test_main_uint16_preinc ();
+ ret |= test_main_uint32_preinc ();
+ ret |= test_main_uint64_preinc ();
+ ret |= test_main_uint64_preinc_neg ();
+ ret |= test_main_float_preinc ();
+ ret |= test_main_double_preinc ();
+ ret |= test_main_long_double_preinc ();
+ ret |= test_main_uint8_sub ();
+ ret |= test_main_uint8_sub_3 ();
+ ret |= test_main_uint16_sub ();
+ ret |= test_main_uint16_sub_3 ();
+ ret |= test_main_uint32_sub ();
+ ret |= test_main_uint32_sub_3 ();
+ ret |= test_main_uint64_sub ();
+ ret |= test_main_uint64_sub_3 ();
+ ret |= test_main_uint64_sub_neg ();
+ ret |= test_main_float_sub ();
+ ret |= test_main_double_sub ();
+ ret |= test_main_long_double_sub ();
+ ret |= test_main_complex_float_sub ();
+ ret |= test_main_complex_double_sub ();
+ ret |= test_main_complex_long_double_sub ();
+ ret |= test_main_uint8_postdec ();
+ ret |= test_main_uint16_postdec ();
+ ret |= test_main_uint32_postdec ();
+ ret |= test_main_uint64_postdec ();
+ ret |= test_main_uint64_postdec_neg ();
+ ret |= test_main_float_postdec ();
+ ret |= test_main_double_postdec ();
+ ret |= test_main_long_double_postdec ();
+ ret |= test_main_uint8_predec ();
+ ret |= test_main_uint16_predec ();
+ ret |= test_main_uint32_predec ();
+ ret |= test_main_uint64_predec ();
+ ret |= test_main_uint64_predec_neg ();
+ ret |= test_main_float_predec ();
+ ret |= test_main_double_predec ();
+ ret |= test_main_long_double_predec ();
+ ret |= test_main_uint8_mul ();
+ ret |= test_main_uint16_mul ();
+ ret |= test_main_uint32_mul ();
+ ret |= test_main_uint64_mul ();
+ if (ret)
+ abort ();
+ else
+ exit (0);
+}
===================================================================
@@ -0,0 +1,540 @@
+/* Test for _Atomic in C11. Test floating-point exceptions for
+ compound assignment are consistent with result (so that if multiple
+ iterations of the compare-and-exchange loop are needed, exceptions
+ get properly cleared). */
+/* { dg-do run } */
+/* { dg-options "-std=c11 -pedantic-errors -pthread -D_POSIX_C_SOURCE=200809L" } */
+/* { dg-require-effective-target pthread } */
+
+#include <fenv.h>
+#include <float.h>
+#include <pthread.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define TEST_ALL_EXCEPT (FE_DIVBYZERO \
+ | FE_INEXACT \
+ | FE_INVALID \
+ | FE_OVERFLOW \
+ | FE_UNDERFLOW)
+
+#define ITER_COUNT 10000
+
+static volatile _Atomic bool thread_ready, thread_stop;
+
+/* Generate test code (with NAME used to name functions and variables)
+ for atomic compound assignments to a variable of type LHSTYPE. One
+ thread repeatedly stores the values INIT1 and INIT2 in a variable,
+ while the other repeatedly executes PRE var POST having set
+ floating-point exceptions to BEXC. If the value of the assignment
+ operation satisfies VALTEST1 (var), the floating-point exceptions
+ should be BEXC | EXC1; otherwise, they should be BEXC | EXC2. A
+ function test_main_##NAME is generated that returns nonzero on
+ failure, zero on success. */
+
+#define TEST_FUNCS(NAME, LHSTYPE, PRE, POST, BEXC, \
+ INIT1, VALTEST1, EXC1, INIT2, EXC2) \
+ \
+static volatile _Atomic LHSTYPE var_##NAME; \
+ \
+static void * \
+test_thread_##NAME (void *arg) \
+{ \
+ thread_ready = true; \
+ while (!thread_stop) \
+ { \
+ var_##NAME = (INIT1); \
+ var_##NAME = (INIT2); \
+ } \
+ return NULL; \
+} \
+ \
+static int \
+test_main_##NAME (void) \
+{ \
+ thread_stop = false; \
+ thread_ready = false; \
+ var_##NAME = (INIT1); \
+ pthread_t thread_id; \
+ int pret = pthread_create (&thread_id, NULL, test_thread_##NAME, \
+ NULL); \
+ if (pret != 0) \
+ { \
+ printf ("pthread_create failed: %d\n", pret); \
+ return 1; \
+ } \
+ int num_1_pass = 0, num_1_fail = 0, num_2_pass = 0, num_2_fail = 0; \
+ while (!thread_ready) \
+ ; \
+ for (int i = 0; i < ITER_COUNT; i++) \
+ { \
+ feclearexcept (FE_ALL_EXCEPT); \
+ feraiseexcept (BEXC); \
+ LHSTYPE r = (PRE var_##NAME POST); \
+ int rexc = fetestexcept (TEST_ALL_EXCEPT); \
+ if (VALTEST1 (r)) \
+ { \
+ if (rexc == ((BEXC) | (EXC1))) \
+ num_1_pass++; \
+ else \
+ num_1_fail++; \
+ var_##NAME = (INIT2); \
+ } \
+ else \
+ { \
+ if (rexc == ((BEXC) | (EXC2))) \
+ num_2_pass++; \
+ else \
+ num_2_fail++; \
+ var_##NAME = (INIT1); \
+ } \
+ } \
+ thread_stop = true; \
+ pthread_join (thread_id, NULL); \
+ printf (#NAME " (a) %d pass, %d fail; (b) %d pass, %d fail\n", \
+ num_1_pass, num_1_fail, num_2_pass, num_2_fail); \
+ return num_1_fail || num_2_fail; \
+}
+
+TEST_FUNCS (float_add_invalid, float, , += __builtin_inff (), 0,
+ 0, __builtin_isinf, 0,
+ -__builtin_inff (), FE_INVALID)
+TEST_FUNCS (float_add_invalid_prev, float, , += __builtin_inff (),
+ FE_DIVBYZERO | FE_INEXACT | FE_OVERFLOW | FE_UNDERFLOW,
+ 0, __builtin_isinf, 0,
+ -__builtin_inff (), FE_INVALID)
+TEST_FUNCS (float_add_overflow, float, , += FLT_MAX, 0,
+ FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_add_overflow_prev, float, , += FLT_MAX, FE_INVALID,
+ FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_add_overflow_double, float, , += (double) FLT_MAX, 0,
+ FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_add_overflow_long_double, float, , += (long double) FLT_MAX, 0,
+ FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+#define NOT_FLT_EPSILON_2(X) ((X) != FLT_EPSILON / 2)
+TEST_FUNCS (float_add_inexact, float, , += FLT_EPSILON / 2, 0,
+ 1.0f, NOT_FLT_EPSILON_2, FE_INEXACT,
+ 0, 0)
+#define NOT_0(X) ((X) != 0)
+TEST_FUNCS (float_add_inexact_int, float, , += 1, 0,
+ FLT_EPSILON / 2, NOT_0, FE_INEXACT,
+ -1, 0)
+TEST_FUNCS (float_preinc_inexact, float, ++, , 0,
+ FLT_EPSILON / 2, NOT_0, FE_INEXACT,
+ -1, 0)
+#define NOT_MINUS_1(X) ((X) != -1)
+TEST_FUNCS (float_postinc_inexact, float, , ++, 0,
+ FLT_EPSILON / 2, NOT_MINUS_1, FE_INEXACT,
+ -1, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS (long_add_float_inexact, long, , += 2 / FLT_EPSILON, 0,
+ 1, NOT_0, FE_INEXACT,
+ -2 / FLT_EPSILON, 0)
+#endif
+#define REAL_ISINF(X) (__builtin_isinf (__real__ (X)))
+TEST_FUNCS (complex_float_add_overflow, _Complex float, , += FLT_MAX, 0,
+ FLT_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_sub_invalid, float, , -= __builtin_inff (), 0,
+ 0, __builtin_isinf, 0,
+ __builtin_inff (), FE_INVALID)
+TEST_FUNCS (float_sub_overflow, float, , -= FLT_MAX, 0,
+ -FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+#define NOT_MINUS_FLT_EPSILON_2(X) ((X) != -FLT_EPSILON / 2)
+TEST_FUNCS (float_sub_inexact, float, , -= FLT_EPSILON / 2, 0,
+ -1.0f, NOT_MINUS_FLT_EPSILON_2, FE_INEXACT,
+ 0, 0)
+#define NOT_0(X) ((X) != 0)
+TEST_FUNCS (float_sub_inexact_int, float, , -= 1, 0,
+ -FLT_EPSILON / 2, NOT_0, FE_INEXACT,
+ 1, 0)
+TEST_FUNCS (float_predec_inexact, float, --, , 0,
+ -FLT_EPSILON / 2, NOT_0, FE_INEXACT,
+ 1, 0)
+#define NOT_1(X) ((X) != 1)
+TEST_FUNCS (float_postdec_inexact, float, , --, 0,
+ -FLT_EPSILON / 2, NOT_1, FE_INEXACT,
+ 1, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS (long_sub_float_inexact, long, , -= 2 / FLT_EPSILON, 0,
+ -1, NOT_0, FE_INEXACT,
+ 2 / FLT_EPSILON, 0)
+#endif
+TEST_FUNCS (complex_float_sub_overflow, _Complex float, , -= FLT_MAX, 0,
+ -FLT_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_mul_invalid, float, , *= __builtin_inff (), 0,
+ __builtin_inff (), __builtin_isinf, 0,
+ 0, FE_INVALID)
+TEST_FUNCS (float_mul_overflow, float, , *= FLT_MAX, 0,
+ FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+#define IS_0(X) ((X) == 0)
+TEST_FUNCS (float_mul_underflow, float, , *= FLT_MIN, 0,
+ FLT_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+ 1, 0)
+TEST_FUNCS (float_mul_inexact, float, , *= 1 + FLT_EPSILON, 0,
+ 1 + FLT_EPSILON, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_mul_inexact_int, float, , *= 3, 0,
+ 1 + FLT_EPSILON, NOT_0, FE_INEXACT,
+ 0, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS(long_mul_float_inexact, long, , *= 3.0f, 0,
+ 1 + 1 / FLT_EPSILON, NOT_0, FE_INEXACT,
+ 0, 0)
+#endif
+TEST_FUNCS (complex_float_mul_overflow, _Complex float, , *= FLT_MAX, 0,
+ FLT_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_div_invalid_divbyzero, float, , /= 0.0f, 0,
+ 1, __builtin_isinf, FE_DIVBYZERO,
+ 0, FE_INVALID)
+TEST_FUNCS (float_div_overflow, float, , /= FLT_MIN, 0,
+ FLT_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_div_underflow, float, , /= FLT_MAX, 0,
+ FLT_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+ FLT_MAX, 0)
+TEST_FUNCS (float_div_inexact, float, , /= 3.0f, 0,
+ 1, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (float_div_inexact_int, float, , /= 3, 0,
+ 1, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (int_div_float_inexact, int, , /= 3.0f, 0,
+ 4, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (complex_float_div_overflow, _Complex float, , /= FLT_MIN, 0,
+ FLT_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+
+TEST_FUNCS (double_add_invalid, double, , += __builtin_inf (), 0,
+ 0, __builtin_isinf, 0,
+ -__builtin_inf (), FE_INVALID)
+TEST_FUNCS (double_add_overflow, double, , += DBL_MAX, 0,
+ DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_add_overflow_long_double, double, , += (long double) DBL_MAX, 0,
+ DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+#define NOT_DBL_EPSILON_2(X) ((X) != DBL_EPSILON / 2)
+TEST_FUNCS (double_add_inexact, double, , += DBL_EPSILON / 2, 0,
+ 1.0, NOT_DBL_EPSILON_2, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_add_inexact_int, double, , += 1, 0,
+ DBL_EPSILON / 2, NOT_0, FE_INEXACT,
+ -1, 0)
+TEST_FUNCS (double_preinc_inexact, double, ++, , 0,
+ DBL_EPSILON / 2, NOT_0, FE_INEXACT,
+ -1, 0)
+TEST_FUNCS (double_postinc_inexact, double, , ++, 0,
+ DBL_EPSILON / 2, NOT_MINUS_1, FE_INEXACT,
+ -1, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS (long_long_add_double_inexact, long long, , += 2 / DBL_EPSILON, 0,
+ 1, NOT_0, FE_INEXACT,
+ -2 / DBL_EPSILON, 0)
+#endif
+TEST_FUNCS (complex_double_add_overflow, _Complex double, , += DBL_MAX, 0,
+ DBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_sub_invalid, double, , -= __builtin_inf (), 0,
+ 0, __builtin_isinf, 0,
+ __builtin_inf (), FE_INVALID)
+TEST_FUNCS (double_sub_overflow, double, , -= DBL_MAX, 0,
+ -DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+#define NOT_MINUS_DBL_EPSILON_2(X) ((X) != -DBL_EPSILON / 2)
+TEST_FUNCS (double_sub_inexact, double, , -= DBL_EPSILON / 2, 0,
+ -1.0, NOT_MINUS_DBL_EPSILON_2, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_sub_inexact_int, double, , -= 1, 0,
+ -DBL_EPSILON / 2, NOT_0, FE_INEXACT,
+ 1, 0)
+TEST_FUNCS (double_predec_inexact, double, --, , 0,
+ -DBL_EPSILON / 2, NOT_0, FE_INEXACT,
+ 1, 0)
+TEST_FUNCS (double_postdec_inexact, double, , --, 0,
+ -DBL_EPSILON / 2, NOT_1, FE_INEXACT,
+ 1, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS (long_long_sub_double_inexact, long long, , -= 2 / DBL_EPSILON, 0,
+ -1, NOT_0, FE_INEXACT,
+ 2 / DBL_EPSILON, 0)
+#endif
+TEST_FUNCS (complex_double_sub_overflow, _Complex double, , -= DBL_MAX, 0,
+ -DBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_mul_invalid, double, , *= __builtin_inf (), 0,
+ __builtin_inf (), __builtin_isinf, 0,
+ 0, FE_INVALID)
+TEST_FUNCS (double_mul_overflow, double, , *= DBL_MAX, 0,
+ DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_mul_overflow_float, double, , *= FLT_MAX, 0,
+ DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_mul_underflow, double, , *= DBL_MIN, 0,
+ DBL_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+ 1, 0)
+TEST_FUNCS (double_mul_inexact, double, , *= 1 + DBL_EPSILON, 0,
+ 1 + DBL_EPSILON, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_mul_inexact_int, double, , *= 3, 0,
+ 1 + DBL_EPSILON, NOT_0, FE_INEXACT,
+ 0, 0)
+#if FLT_EVAL_METHOD == 0
+TEST_FUNCS(long_long_mul_double_inexact, long long, , *= 3.0, 0,
+ 1 + 1 / DBL_EPSILON, NOT_0, FE_INEXACT,
+ 0, 0)
+#endif
+TEST_FUNCS (complex_double_mul_overflow, _Complex double, , *= DBL_MAX, 0,
+ DBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_div_invalid_divbyzero, double, , /= 0.0, 0,
+ 1, __builtin_isinf, FE_DIVBYZERO,
+ 0, FE_INVALID)
+TEST_FUNCS (double_div_overflow, double, , /= DBL_MIN, 0,
+ DBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_div_underflow, double, , /= DBL_MAX, 0,
+ DBL_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+ DBL_MAX, 0)
+TEST_FUNCS (double_div_inexact, double, , /= 3.0, 0,
+ 1, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (double_div_inexact_int, double, , /= 3, 0,
+ 1, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (int_div_double_inexact, int, , /= 3.0, 0,
+ 4, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (complex_double_div_overflow, _Complex double, , /= DBL_MIN, 0,
+ DBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+
+TEST_FUNCS (long_double_add_invalid, long double, , += __builtin_infl (), 0,
+ 0, __builtin_isinf, 0,
+ -__builtin_infl (), FE_INVALID)
+TEST_FUNCS (long_double_add_overflow, long double, , += LDBL_MAX, 0,
+ LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+#define NOT_LDBL_EPSILON_2(X) ((X) != LDBL_EPSILON / 2)
+#if LDBL_MANT_DIG != 106
+TEST_FUNCS (long_double_add_inexact, long double, , += LDBL_EPSILON / 2, 0,
+ 1.0L, NOT_LDBL_EPSILON_2, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_add_inexact_int, long double, , += 1, 0,
+ LDBL_EPSILON / 2, NOT_0, FE_INEXACT,
+ -1, 0)
+TEST_FUNCS (long_double_preinc_inexact, long double, ++, , 0,
+ LDBL_EPSILON / 2, NOT_0, FE_INEXACT,
+ -1, 0)
+TEST_FUNCS (long_double_postinc_inexact, long double, , ++, 0,
+ LDBL_EPSILON / 2, NOT_MINUS_1, FE_INEXACT,
+ -1, 0)
+#endif
+TEST_FUNCS (complex_long_double_add_overflow, _Complex long double, , += LDBL_MAX, 0,
+ LDBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_sub_invalid, long double, , -= __builtin_infl (), 0,
+ 0, __builtin_isinf, 0,
+ __builtin_infl (), FE_INVALID)
+TEST_FUNCS (long_double_sub_overflow, long double, , -= LDBL_MAX, 0,
+ -LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+#define NOT_MINUS_LDBL_EPSILON_2(X) ((X) != -LDBL_EPSILON / 2)
+#if LDBL_MANT_DIG != 106
+TEST_FUNCS (long_double_sub_inexact, long double, , -= LDBL_EPSILON / 2, 0,
+ -1.0L, NOT_MINUS_LDBL_EPSILON_2, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_sub_inexact_int, long double, , -= 1, 0,
+ -LDBL_EPSILON / 2, NOT_0, FE_INEXACT,
+ 1, 0)
+TEST_FUNCS (long_double_predec_inexact, long double, --, , 0,
+ -LDBL_EPSILON / 2, NOT_0, FE_INEXACT,
+ 1, 0)
+TEST_FUNCS (long_double_postdec_inexact, long double, , --, 0,
+ -LDBL_EPSILON / 2, NOT_1, FE_INEXACT,
+ 1, 0)
+#endif
+TEST_FUNCS (complex_long_double_sub_overflow, _Complex long double, , -= LDBL_MAX, 0,
+ -LDBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_mul_invalid, long double, , *= __builtin_infl (), 0,
+ __builtin_infl (), __builtin_isinf, 0,
+ 0, FE_INVALID)
+TEST_FUNCS (long_double_mul_overflow, long double, , *= LDBL_MAX, 0,
+ LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_mul_overflow_float, long double, , *= FLT_MAX, 0,
+ LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_mul_overflow_double, long double, , *= DBL_MAX, 0,
+ LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_mul_underflow, long double, , *= LDBL_MIN, 0,
+ LDBL_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+ 1, 0)
+#if LDBL_MANT_DIG != 106
+TEST_FUNCS (long_double_mul_inexact, long double, , *= 1 + LDBL_EPSILON, 0,
+ 1 + LDBL_EPSILON, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_mul_inexact_int, long double, , *= 3, 0,
+ 1 + LDBL_EPSILON, NOT_0, FE_INEXACT,
+ 0, 0)
+#endif
+TEST_FUNCS (complex_long_double_mul_overflow, _Complex long double, , *= LDBL_MAX, 0,
+ LDBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_div_invalid_divbyzero, long double, , /= 0.0L, 0,
+ 1, __builtin_isinf, FE_DIVBYZERO,
+ 0, FE_INVALID)
+TEST_FUNCS (long_double_div_overflow, long double, , /= LDBL_MIN, 0,
+ LDBL_MAX, __builtin_isinf, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_div_underflow, long double, , /= LDBL_MAX, 0,
+ LDBL_MIN, IS_0, FE_UNDERFLOW | FE_INEXACT,
+ LDBL_MAX, 0)
+TEST_FUNCS (long_double_div_inexact, long double, , /= 3.0L, 0,
+ 1, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (long_double_div_inexact_int, long double, , /= 3, 0,
+ 1, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (int_div_long_double_inexact, int, , /= 3.0L, 0,
+ 4, NOT_0, FE_INEXACT,
+ 0, 0)
+TEST_FUNCS (complex_long_double_div_overflow, _Complex long double, , /= LDBL_MIN, 0,
+ LDBL_MAX, REAL_ISINF, FE_OVERFLOW | FE_INEXACT,
+ 0, 0)
+
+int
+main (void)
+{
+ int ret = 0;
+ ret |= test_main_float_add_invalid ();
+ ret |= test_main_float_add_invalid_prev ();
+ ret |= test_main_float_add_overflow ();
+ ret |= test_main_float_add_overflow_prev ();
+ ret |= test_main_float_add_overflow_double ();
+ ret |= test_main_float_add_overflow_long_double ();
+ ret |= test_main_float_add_inexact ();
+ ret |= test_main_float_add_inexact_int ();
+ ret |= test_main_float_preinc_inexact ();
+ ret |= test_main_float_postinc_inexact ();
+#if FLT_EVAL_METHOD == 0
+ ret |= test_main_long_add_float_inexact ();
+#endif
+ ret |= test_main_complex_float_add_overflow ();
+ ret |= test_main_float_sub_invalid ();
+ ret |= test_main_float_sub_overflow ();
+ ret |= test_main_float_sub_inexact ();
+ ret |= test_main_float_sub_inexact_int ();
+ ret |= test_main_float_predec_inexact ();
+ ret |= test_main_float_postdec_inexact ();
+#if FLT_EVAL_METHOD == 0
+ ret |= test_main_long_sub_float_inexact ();
+#endif
+ ret |= test_main_complex_float_sub_overflow ();
+ ret |= test_main_float_mul_invalid ();
+ ret |= test_main_float_mul_overflow ();
+ ret |= test_main_float_mul_underflow ();
+ ret |= test_main_float_mul_inexact ();
+ ret |= test_main_float_mul_inexact_int ();
+#if FLT_EVAL_METHOD == 0
+ ret |= test_main_long_mul_float_inexact ();
+#endif
+ ret |= test_main_complex_float_mul_overflow ();
+ ret |= test_main_float_div_invalid_divbyzero ();
+ ret |= test_main_float_div_overflow ();
+ ret |= test_main_float_div_underflow ();
+ ret |= test_main_float_div_inexact ();
+ ret |= test_main_float_div_inexact_int ();
+ ret |= test_main_int_div_float_inexact ();
+ ret |= test_main_complex_float_div_overflow ();
+ ret |= test_main_double_add_invalid ();
+ ret |= test_main_double_add_overflow ();
+ ret |= test_main_double_add_overflow_long_double ();
+ ret |= test_main_double_add_inexact ();
+ ret |= test_main_double_add_inexact_int ();
+ ret |= test_main_double_preinc_inexact ();
+ ret |= test_main_double_postinc_inexact ();
+#if FLT_EVAL_METHOD == 0
+ ret |= test_main_long_long_add_double_inexact ();
+#endif
+ ret |= test_main_complex_double_add_overflow ();
+ ret |= test_main_double_sub_invalid ();
+ ret |= test_main_double_sub_overflow ();
+ ret |= test_main_double_sub_inexact ();
+ ret |= test_main_double_sub_inexact_int ();
+ ret |= test_main_double_predec_inexact ();
+ ret |= test_main_double_postdec_inexact ();
+#if FLT_EVAL_METHOD == 0
+ ret |= test_main_long_long_sub_double_inexact ();
+#endif
+ ret |= test_main_complex_double_sub_overflow ();
+ ret |= test_main_double_mul_invalid ();
+ ret |= test_main_double_mul_overflow ();
+ ret |= test_main_double_mul_overflow_float ();
+ ret |= test_main_double_mul_underflow ();
+ ret |= test_main_double_mul_inexact ();
+ ret |= test_main_double_mul_inexact_int ();
+#if FLT_EVAL_METHOD == 0
+ ret |= test_main_long_long_mul_double_inexact ();
+#endif
+ ret |= test_main_complex_double_mul_overflow ();
+ ret |= test_main_double_div_invalid_divbyzero ();
+ ret |= test_main_double_div_overflow ();
+ ret |= test_main_double_div_underflow ();
+ ret |= test_main_double_div_inexact ();
+ ret |= test_main_double_div_inexact_int ();
+ ret |= test_main_int_div_double_inexact ();
+ ret |= test_main_complex_double_div_overflow ();
+ ret |= test_main_long_double_add_invalid ();
+ ret |= test_main_long_double_add_overflow ();
+#if LDBL_MANT_DIG != 106
+ ret |= test_main_long_double_add_inexact ();
+ ret |= test_main_long_double_add_inexact_int ();
+ ret |= test_main_long_double_preinc_inexact ();
+ ret |= test_main_long_double_postinc_inexact ();
+#endif
+ ret |= test_main_complex_long_double_add_overflow ();
+ ret |= test_main_long_double_sub_invalid ();
+ ret |= test_main_long_double_sub_overflow ();
+#if LDBL_MANT_DIG != 106
+ ret |= test_main_long_double_sub_inexact ();
+ ret |= test_main_long_double_sub_inexact_int ();
+ ret |= test_main_long_double_predec_inexact ();
+ ret |= test_main_long_double_postdec_inexact ();
+#endif
+ ret |= test_main_complex_long_double_sub_overflow ();
+ ret |= test_main_long_double_mul_invalid ();
+ ret |= test_main_long_double_mul_overflow ();
+ ret |= test_main_long_double_mul_overflow_float ();
+ ret |= test_main_long_double_mul_overflow_double ();
+ ret |= test_main_long_double_mul_underflow ();
+#if LDBL_MANT_DIG != 106
+ ret |= test_main_long_double_mul_inexact ();
+ ret |= test_main_long_double_mul_inexact_int ();
+#endif
+ ret |= test_main_complex_long_double_mul_overflow ();
+ ret |= test_main_long_double_div_invalid_divbyzero ();
+ ret |= test_main_long_double_div_overflow ();
+ ret |= test_main_long_double_div_underflow ();
+ ret |= test_main_long_double_div_inexact ();
+ ret |= test_main_long_double_div_inexact_int ();
+ ret |= test_main_int_div_long_double_inexact ();
+ ret |= test_main_complex_long_double_div_overflow ();
+ if (ret != 0)
+ abort ();
+ else
+ exit (0);
+}
===================================================================
@@ -148,7 +148,7 @@ AC_SUBST(enable_static)
AM_MAINTAINER_MODE
# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=1:0:0
+libtool_VERSION=2:0:1
AC_SUBST(libtool_VERSION)
# Get target configury.
@@ -165,6 +165,7 @@ CFLAGS="$save_CFLAGS -fno-sync-libcalls $XCFLAGS"
AC_STDC_HEADERS
ACX_HEADER_STRING
GCC_HEADER_STDINT(gstdint.h)
+AC_CHECK_HEADERS([fenv.h])
# Check for common type sizes
LIBAT_FORALL_MODES([LIBAT_HAVE_INT_MODE])
===================================================================
@@ -105,6 +105,9 @@
/* Define to 1 if you have the <dlfcn.h> header file. */
#undef HAVE_DLFCN_H
+/* Define to 1 if you have the <fenv.h> header file. */
+#undef HAVE_FENV_H
+
/* Define to 1 if the target supports __attribute__((ifunc(...))). */
#undef HAVE_IFUNC
===================================================================
@@ -67,7 +67,8 @@ endif
libatomic_version_info = -version-info $(libtool_VERSION)
libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script)
-libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c
+libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c \
+ fenv.c
SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas
SIZES = @SIZES@
===================================================================
@@ -95,3 +95,7 @@ LIBATOMIC_1.0 {
local:
*;
};
+LIBATOMIC_1.1 {
+ global:
+ __atomic_feraiseexcept;
+} LIBATOMIC_1.0;
===================================================================
@@ -0,0 +1,72 @@
+/* Copyright (C) 2012-2013 Free Software Foundation, Inc.
+
+ This file is part of the GNU Atomic Library (libatomic).
+
+ Libatomic is free software; you can redistribute it and/or modify it
+ under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 3 of the License, or
+ (at your option) any later version.
+
+ Libatomic is distributed in the hope that it will be useful, but WITHOUT ANY
+ WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
+ FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ more details.
+
+ Under Section 7 of GPL version 3, you are granted additional
+ permissions described in the GCC Runtime Library Exception, version
+ 3.1, as published by the Free Software Foundation.
+
+ You should have received a copy of the GNU General Public License and
+ a copy of the GCC Runtime Library Exception along with this program;
+ see the files COPYING3 and COPYING.RUNTIME respectively. If not, see
+ <http://www.gnu.org/licenses/>. */
+
+#include "libatomic_i.h"
+
+#ifdef HAVE_FENV_H
+# include <fenv.h>
+#endif
+
+/* Raise the supported floating-point exceptions from EXCEPTS. Other
+ bits in EXCEPTS are ignored. */
+
+void
+__atomic_feraiseexcept (int excepts __attribute__ ((unused)))
+{
+ volatile float r __attribute__ ((unused));
+#ifdef FE_INVALID
+ if (excepts & FE_INVALID)
+ {
+ volatile float zero = 0.0f;
+ r = zero / zero;
+ }
+#endif
+#ifdef FE_DIVBYZERO
+ if (excepts & FE_DIVBYZERO)
+ {
+ volatile float zero = 0.0f;
+ r = 1.0f / zero;
+ }
+#endif
+#ifdef FE_OVERFLOW
+ if (excepts & FE_OVERFLOW)
+ {
+ volatile float max = __FLT_MAX__;
+ r = max * max;
+ }
+#endif
+#ifdef FE_UNDERFLOW
+ if (excepts & FE_UNDERFLOW)
+ {
+ volatile float min = __FLT_MIN__;
+ r = min * min;
+ }
+#endif
+#ifdef FE_INEXACT
+ if (excepts & FE_INEXACT)
+ {
+ volatile float three = 3.0f;
+ r = 1.0f / three;
+ }
+#endif
+}
===================================================================
@@ -2000,6 +2000,93 @@ rm -f conftest.val
return $ac_retval
} # ac_fn_c_compute_int
+
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
+{
+ as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+ if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+else
+ # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+ ac_header_compiler=yes
+else
+ ac_header_compiler=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
+
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h. */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+ ac_header_preproc=yes
+else
+ ac_header_preproc=no
+fi
+rm -f conftest.err conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
+
+# So? What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+ yes:no: )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+ no:yes:* )
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2: check for missing prerequisite headers?" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2: section \"Present But Cannot Be Compiled\"" >&2;}
+ { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+ ;;
+esac
+ { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if { as_var=$3; eval "test \"\${$as_var+set}\" = set"; }; then :
+ $as_echo_n "(cached) " >&6
+else
+ eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+ { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+fi
+ eval $as_lineno_stack; test "x$as_lineno_stack" = x && { as_lineno=; unset as_lineno;}
+
+} # ac_fn_c_check_header_mongrel
cat >config.log <<_ACEOF
This file contains any messages produced by compilers while
running configure, to aid debugging if configure makes a mistake.
@@ -11019,7 +11106,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11022 "configure"
+#line 11109 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11125,7 +11212,7 @@ else
lt_dlunknown=0; lt_dlno_uscore=1; lt_dlneed_uscore=2
lt_status=$lt_dlunknown
cat > conftest.$ac_ext <<_LT_EOF
-#line 11128 "configure"
+#line 11215 "configure"
#include "confdefs.h"
#if HAVE_DLFCN_H
@@ -11389,7 +11476,7 @@ fi
# For libtool versioning info, format is CURRENT:REVISION:AGE
-libtool_VERSION=1:0:0
+libtool_VERSION=2:0:1
# Get target configury.
@@ -11953,7 +12040,19 @@ ac_config_commands="$ac_config_commands gstdint.h"
+for ac_header in fenv.h
+do :
+ ac_fn_c_check_header_mongrel "$LINENO" "fenv.h" "ac_cv_header_fenv_h" "$ac_includes_default"
+if test "x$ac_cv_header_fenv_h" = x""yes; then :
+ cat >>confdefs.h <<_ACEOF
+#define HAVE_FENV_H 1
+_ACEOF
+fi
+
+done
+
+
# Check for common type sizes
{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for 1 byte integer" >&5
===================================================================
@@ -90,14 +90,14 @@ am__base_list = \
am__installdirs = "$(DESTDIR)$(toolexeclibdir)"
LTLIBRARIES = $(noinst_LTLIBRARIES) $(toolexeclib_LTLIBRARIES)
am_libatomic_la_OBJECTS = gload.lo gstore.lo gcas.lo gexch.lo \
- glfree.lo lock.lo init.lo
+ glfree.lo lock.lo init.lo fenv.lo
libatomic_la_OBJECTS = $(am_libatomic_la_OBJECTS)
libatomic_la_LINK = $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \
$(libatomic_la_LDFLAGS) $(LDFLAGS) -o $@
libatomic_convenience_la_DEPENDENCIES = $(libatomic_la_LIBADD)
am__objects_1 = gload.lo gstore.lo gcas.lo gexch.lo glfree.lo lock.lo \
- init.lo
+ init.lo fenv.lo
am_libatomic_convenience_la_OBJECTS = $(am__objects_1)
libatomic_convenience_la_OBJECTS = \
$(am_libatomic_convenience_la_OBJECTS)
@@ -286,7 +286,9 @@ noinst_LTLIBRARIES = libatomic_convenience.la
@LIBAT_BUILD_VERSIONED_SHLIB_SUN_TRUE@@LIBAT_BUILD_VERSIONED_SHLIB_TRUE@libatomic_version_dep = libatomic.map-sun
libatomic_version_info = -version-info $(libtool_VERSION)
libatomic_la_LDFLAGS = $(libatomic_version_info) $(libatomic_version_script)
-libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c
+libatomic_la_SOURCES = gload.c gstore.c gcas.c gexch.c glfree.c lock.c init.c \
+ fenv.c
+
SIZEOBJS = load store cas exch fadd fsub fand fior fxor fnand tas
EXTRA_libatomic_la_SOURCES = $(addsuffix _n.c,$(SIZEOBJS))
libatomic_la_DEPENDENCIES = $(libatomic_la_LIBADD) $(libatomic_version_dep)
@@ -425,6 +427,7 @@ mostlyclean-compile:
distclean-compile:
-rm -f *.tab.c
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/fenv.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gcas.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gexch.Plo@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/glfree.Plo@am__quote@