aboutsummaryrefslogtreecommitdiff
path: root/gcc/builtins.c
diff options
context:
space:
mode:
authorJakub Jelinek <jakub@redhat.com>2016-05-03 13:37:25 +0200
committerJakub Jelinek <jakub@gcc.gnu.org>2016-05-03 13:37:25 +0200
commitadedd5c173388ae505470df152b9cb3947339566 (patch)
tree858576e93abb78b087773e895b143546903f49f2 /gcc/builtins.c
parent50891606a95368edd688fa9dc73003b1dfd68983 (diff)
downloadgcc-adedd5c173388ae505470df152b9cb3947339566.zip
gcc-adedd5c173388ae505470df152b9cb3947339566.tar.gz
gcc-adedd5c173388ae505470df152b9cb3947339566.tar.bz2
re PR target/49244 (__sync or __atomic builtins will not emit 'lock bts/btr/btc')
PR target/49244 * tree-ssa-ccp.c: Include stor-layout.h and optabs-query.h. (optimize_atomic_bit_test_and): New function. (pass_fold_builtins::execute): Use it. * optabs.def (atomic_bit_test_and_set_optab, atomic_bit_test_and_complement_optab, atomic_bit_test_and_reset_optab): New optabs. * internal-fn.def (ATOMIC_BIT_TEST_AND_SET, ATOMIC_BIT_TEST_AND_COMPLEMENT, ATOMIC_BIT_TEST_AND_RESET): New ifns. * builtins.h (expand_ifn_atomic_bit_test_and): New prototype. * builtins.c (expand_ifn_atomic_bit_test_and): New function. * internal-fn.c (expand_ATOMIC_BIT_TEST_AND_SET, expand_ATOMIC_BIT_TEST_AND_COMPLEMENT, expand_ATOMIC_BIT_TEST_AND_RESET): New functions. * doc/md.texi (atomic_bit_test_and_set@var{mode}, atomic_bit_test_and_complement@var{mode}, atomic_bit_test_and_reset@var{mode}): Document. * config/i386/sync.md (atomic_bit_test_and_set<mode>, atomic_bit_test_and_complement<mode>, atomic_bit_test_and_reset<mode>): New expanders. (atomic_bit_test_and_set<mode>_1, atomic_bit_test_and_complement<mode>_1, atomic_bit_test_and_reset<mode>_1): New insns. * gcc.target/i386/pr49244-1.c: New test. * gcc.target/i386/pr49244-2.c: New test. From-SVN: r235813
Diffstat (limited to 'gcc/builtins.c')
-rw-r--r--gcc/builtins.c84
1 files changed, 84 insertions, 0 deletions
diff --git a/gcc/builtins.c b/gcc/builtins.c
index 3d89baf..7d87619 100644
--- a/gcc/builtins.c
+++ b/gcc/builtins.c
@@ -5310,6 +5310,90 @@ expand_builtin_atomic_fetch_op (machine_mode mode, tree exp, rtx target,
return ret;
}
+/* Expand IFN_ATOMIC_BIT_TEST_AND_* internal function. */
+
+void
+expand_ifn_atomic_bit_test_and (gcall *call)
+{
+ tree ptr = gimple_call_arg (call, 0);
+ tree bit = gimple_call_arg (call, 1);
+ tree flag = gimple_call_arg (call, 2);
+ tree lhs = gimple_call_lhs (call);
+ enum memmodel model = MEMMODEL_SYNC_SEQ_CST;
+ machine_mode mode = TYPE_MODE (TREE_TYPE (flag));
+ enum rtx_code code;
+ optab optab;
+ struct expand_operand ops[5];
+
+ gcc_assert (flag_inline_atomics);
+
+ if (gimple_call_num_args (call) == 4)
+ model = get_memmodel (gimple_call_arg (call, 3));
+
+ rtx mem = get_builtin_sync_mem (ptr, mode);
+ rtx val = expand_expr_force_mode (bit, mode);
+
+ switch (gimple_call_internal_fn (call))
+ {
+ case IFN_ATOMIC_BIT_TEST_AND_SET:
+ code = IOR;
+ optab = atomic_bit_test_and_set_optab;
+ break;
+ case IFN_ATOMIC_BIT_TEST_AND_COMPLEMENT:
+ code = XOR;
+ optab = atomic_bit_test_and_complement_optab;
+ break;
+ case IFN_ATOMIC_BIT_TEST_AND_RESET:
+ code = AND;
+ optab = atomic_bit_test_and_reset_optab;
+ break;
+ default:
+ gcc_unreachable ();
+ }
+
+ if (lhs == NULL_TREE)
+ {
+ val = expand_simple_binop (mode, ASHIFT, const1_rtx,
+ val, NULL_RTX, true, OPTAB_DIRECT);
+ if (code == AND)
+ val = expand_simple_unop (mode, NOT, val, NULL_RTX, true);
+ expand_atomic_fetch_op (const0_rtx, mem, val, code, model, false);
+ return;
+ }
+
+ rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ enum insn_code icode = direct_optab_handler (optab, mode);
+ gcc_assert (icode != CODE_FOR_nothing);
+ create_output_operand (&ops[0], target, mode);
+ create_fixed_operand (&ops[1], mem);
+ create_convert_operand_to (&ops[2], val, mode, true);
+ create_integer_operand (&ops[3], model);
+ create_integer_operand (&ops[4], integer_onep (flag));
+ if (maybe_expand_insn (icode, 5, ops))
+ return;
+
+ rtx bitval = val;
+ val = expand_simple_binop (mode, ASHIFT, const1_rtx,
+ val, NULL_RTX, true, OPTAB_DIRECT);
+ rtx maskval = val;
+ if (code == AND)
+ val = expand_simple_unop (mode, NOT, val, NULL_RTX, true);
+ rtx result = expand_atomic_fetch_op (gen_reg_rtx (mode), mem, val,
+ code, model, false);
+ if (integer_onep (flag))
+ {
+ result = expand_simple_binop (mode, ASHIFTRT, result, bitval,
+ NULL_RTX, true, OPTAB_DIRECT);
+ result = expand_simple_binop (mode, AND, result, const1_rtx, target,
+ true, OPTAB_DIRECT);
+ }
+ else
+ result = expand_simple_binop (mode, AND, result, maskval, target, true,
+ OPTAB_DIRECT);
+ if (result != target)
+ emit_move_insn (target, result);
+}
+
/* Expand an atomic clear operation.
void _atomic_clear (BOOL *obj, enum memmodel)
EXP is the call expression. */