diff options
author | Adhemerval Zanella <azanella@linux.vnet.ibm.com> | 2014-10-19 13:49:26 +0000 |
---|---|---|
committer | David Edelsohn <dje@gcc.gnu.org> | 2014-10-19 09:49:26 -0400 |
commit | f4b0b1e3bb4dd4d89efdee99b5d032302a5f4717 (patch) | |
tree | 7a967801fb194a96aebe241cfc33ac718c2af1ae | |
parent | fad0fe1eda55c19395679cd9cd4180a1c1037f70 (diff) | |
download | gcc-f4b0b1e3bb4dd4d89efdee99b5d032302a5f4717.zip gcc-f4b0b1e3bb4dd4d89efdee99b5d032302a5f4717.tar.gz gcc-f4b0b1e3bb4dd4d89efdee99b5d032302a5f4717.tar.bz2 |
rs6000.c (rs6000_atomic_assign_expand_fenv): New function.
2014-10-19 Adhemerval Zanella <azanella@linux.vnet.ibm.com>
David Edelsohn <dje.gcc@gmail.com>
* 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 <dje.gcc@gmail.com>
From-SVN: r216437
-rw-r--r-- | gcc/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/config/rs6000/rs6000.c | 114 | ||||
-rw-r--r-- | gcc/testsuite/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/atomic/c11-atomic-exec-5.c | 8 |
4 files changed, 134 insertions, 4 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 896e77f..9a7f7d2 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2014-10-19 Adhemerval Zanella <azanella@linux.vnet.ibm.com> + David Edelsohn <dje.gcc@gmail.com> + + * 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 <manu@gcc.gnu.org> * doc/invoke.texi (Options to Request or Suppress Warnings): diff --git a/gcc/config/rs6000/rs6000.c b/gcc/config/rs6000/rs6000.c index c451032..2f14c2b 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 87ec5cb..88b321b 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,12 @@ +2014-10-19 Adhemerval Zanella <azanella@linux.vnet.ibm.com> + + * 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 <pault@gcc.gnu.org> 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 2b2b1be..7166042 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 (); |