From: Adhemerval Zanella Date: Sun, 19 Oct 2014 13:49:26 +0000 (+0000) Subject: rs6000.c (rs6000_atomic_assign_expand_fenv): New function. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f4b0b1e3bb4dd4d89efdee99b5d032302a5f4717;p=gcc.git rs6000.c (rs6000_atomic_assign_expand_fenv): New function. 2014-10-19 Adhemerval Zanella David Edelsohn * config/rs6000/rs6000.c (rs6000_atomic_assign_expand_fenv): New function. (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New define. * gcc.dg/atomic/c11-atomic-exec-5.c (test_main_long_double_add_overflow): Define and run only for LDBL_MANT_DIG != 106. (test_main_complex_long_double_add_overflow): Likewise. (test_main_long_double_sub_overflow): Likewise. (test_main_complex_long_double_sub_overflow): Likewise. Co-Authored-By: David Edelsohn From-SVN: r216437 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 896e77f7ecf..9a7f7d2800c 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2014-10-19 Adhemerval Zanella + David Edelsohn + + * config/rs6000/rs6000.c (rs6000_atomic_assign_expand_fenv): New + function. + (TARGET_ATOMIC_ASSIGN_EXPAND_FENV): New define. + 2014-10-18 Manuel López-Ibáñez * doc/invoke.texi (Options to Request or Suppress Warnings): diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index c4510323def..2f14c2b6c3e 100644 --- a/gcc/config/rs6000/rs6000.c +++ b/gcc/config/rs6000/rs6000.c @@ -1647,6 +1647,9 @@ static const struct attribute_spec rs6000_attribute_table[] = #undef TARGET_CAN_USE_DOLOOP_P #define TARGET_CAN_USE_DOLOOP_P can_use_doloop_if_innermost + +#undef TARGET_ATOMIC_ASSIGN_EXPAND_FENV +#define TARGET_ATOMIC_ASSIGN_EXPAND_FENV rs6000_atomic_assign_expand_fenv /* Processor table. */ @@ -34575,6 +34578,117 @@ make_pass_analyze_swaps (gcc::context *ctxt) { return new pass_analyze_swaps (ctxt); } + +/* Implement TARGET_ATOMIC_ASSIGN_EXPAND_FENV hook. */ + +static void +rs6000_atomic_assign_expand_fenv (tree *hold, tree *clear, tree *update) +{ + if (!TARGET_HARD_FLOAT || !TARGET_FPRS) + return; + + tree mffs = rs6000_builtin_decls[RS6000_BUILTIN_MFFS]; + tree mtfsf = rs6000_builtin_decls[RS6000_BUILTIN_MTFSF]; + tree call_mffs = build_call_expr (mffs, 0); + + /* Generates the equivalent of feholdexcept (&fenv_var) + + *fenv_var = __builtin_mffs (); + double fenv_hold; + *(uint64_t*)&fenv_hold = *(uint64_t*)fenv_var & 0xffffffff00000007LL; + __builtin_mtfsf (0xff, fenv_hold); */ + + /* Mask to clear everything except for the rounding modes and non-IEEE + arithmetic flag. */ + const unsigned HOST_WIDE_INT hold_exception_mask = + HOST_WIDE_INT_C (0xffffffff00000007); + + tree fenv_var = create_tmp_var (double_type_node, NULL); + + tree hold_mffs = build2 (MODIFY_EXPR, void_type_node, fenv_var, call_mffs); + + tree fenv_llu = build1 (VIEW_CONVERT_EXPR, uint64_type_node, fenv_var); + tree fenv_llu_and = build2 (BIT_AND_EXPR, uint64_type_node, fenv_llu, + build_int_cst (uint64_type_node, + hold_exception_mask)); + + tree fenv_hold_mtfsf = build1 (VIEW_CONVERT_EXPR, double_type_node, + fenv_llu_and); + + tree hold_mtfsf = build_call_expr (mtfsf, 2, + build_int_cst (unsigned_type_node, 0xff), + fenv_hold_mtfsf); + + *hold = build2 (COMPOUND_EXPR, void_type_node, hold_mffs, hold_mtfsf); + + /* Generates the equivalent of feclearexcept (FE_ALL_EXCEPT): + + double fenv_clear = __builtin_mffs (); + *(uint64_t)&fenv_clear &= 0xffffffff00000000LL; + __builtin_mtfsf (0xff, fenv_clear); */ + + /* Mask to clear everything except for the rounding modes and non-IEEE + arithmetic flag. */ + const unsigned HOST_WIDE_INT clear_exception_mask = + HOST_WIDE_INT_C (0xffffffff00000000); + + tree fenv_clear = create_tmp_var (double_type_node, NULL); + + tree clear_mffs = build2 (MODIFY_EXPR, void_type_node, fenv_clear, call_mffs); + + tree fenv_clean_llu = build1 (VIEW_CONVERT_EXPR, uint64_type_node, fenv_clear); + tree fenv_clear_llu_and = build2 (BIT_AND_EXPR, uint64_type_node, + fenv_clean_llu, + build_int_cst (uint64_type_node, + clear_exception_mask)); + + tree fenv_clear_mtfsf = build1 (VIEW_CONVERT_EXPR, double_type_node, + fenv_clear_llu_and); + + tree clear_mtfsf = build_call_expr (mtfsf, 2, + build_int_cst (unsigned_type_node, 0xff), + fenv_clear_mtfsf); + + *clear = build2 (COMPOUND_EXPR, void_type_node, clear_mffs, clear_mtfsf); + + /* Generates the equivalent of feupdateenv (&fenv_var) + + double old_fenv = __builtin_mffs (); + double fenv_update; + *(uint64_t*)&fenv_update = (*(uint64_t*)&old & 0xffffffff1fffff00LL) | + (*(uint64_t*)fenv_var 0x1ff80fff); + __builtin_mtfsf (0xff, fenv_update); */ + + const unsigned HOST_WIDE_INT update_exception_mask = + HOST_WIDE_INT_C (0xffffffff1fffff00); + const unsigned HOST_WIDE_INT new_exception_mask = + HOST_WIDE_INT_C (0x1ff80fff); + + tree old_fenv = create_tmp_var (double_type_node, NULL); + tree update_mffs = build2 (MODIFY_EXPR, void_type_node, old_fenv, call_mffs); + + tree old_llu = build1 (VIEW_CONVERT_EXPR, uint64_type_node, old_fenv); + tree old_llu_and = build2 (BIT_AND_EXPR, uint64_type_node, old_llu, + build_int_cst (uint64_type_node, + update_exception_mask)); + + tree new_llu_and = build2 (BIT_AND_EXPR, uint64_type_node, fenv_llu, + build_int_cst (uint64_type_node, + new_exception_mask)); + + tree new_llu_mask = build2 (BIT_IOR_EXPR, uint64_type_node, + old_llu_and, new_llu_and); + + tree fenv_update_mtfsf = build1 (VIEW_CONVERT_EXPR, double_type_node, + new_llu_mask); + + tree update_mtfsf = build_call_expr (mtfsf, 2, + build_int_cst (unsigned_type_node, 0xff), + fenv_update_mtfsf); + + *update = build2 (COMPOUND_EXPR, void_type_node, update_mffs, update_mtfsf); +} + struct gcc_target targetm = TARGET_INITIALIZER; diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index 87ec5cb32ae..88b321b07c9 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2014-10-19 Adhemerval Zanella + + * gcc.dg/atomic/c11-atomic-exec-5.c + (test_main_long_double_add_overflow): Define and run only for + LDBL_MANT_DIG != 106. + (test_main_complex_long_double_add_overflow): Likewise. + (test_main_long_double_sub_overflow): Likewise. + (test_main_complex_long_double_sub_overflow): Likewise. + 2014-10-18 Paul Thomas PR fortran/63553 diff --git a/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c b/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c index 2b2b1be4af7..7166042ba7f 100644 --- a/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c +++ b/gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c @@ -507,23 +507,23 @@ main (void) 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_overflow (); 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 (); +#endif 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_overflow (); 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 (); +#endif ret |= test_main_long_double_mul_invalid (); ret |= test_main_long_double_mul_overflow (); ret |= test_main_long_double_mul_overflow_float ();