summaryrefslogtreecommitdiff
path: root/gcc/config
diff options
context:
space:
mode:
authordje <dje@138bc75d-0d04-0410-961f-82ee72b054a4>2014-10-19 13:49:26 +0000
committerdje <dje@138bc75d-0d04-0410-961f-82ee72b054a4>2014-10-19 13:49:26 +0000
commitbfa8c6e840deb45e5d05b4644345a5062dec4468 (patch)
tree7a967801fb194a96aebe241cfc33ac718c2af1ae /gcc/config
parentdb86091a5c5109a00490526250c0d2be61fe9208 (diff)
downloadgcc-bfa8c6e840deb45e5d05b4644345a5062dec4468.tar.gz
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. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@216437 138bc75d-0d04-0410-961f-82ee72b054a4
Diffstat (limited to 'gcc/config')
-rw-r--r--gcc/config/rs6000/rs6000.c114
1 files changed, 114 insertions, 0 deletions
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;