gcc_assert (flag_inline_atomics);
- if (gimple_call_num_args (call) == 4)
+ if (gimple_call_num_args (call) == 5)
model = get_memmodel (gimple_call_arg (call, 3));
rtx mem = get_builtin_sync_mem (ptr, mode);
if (lhs == NULL_TREE)
{
- val = expand_simple_binop (mode, ASHIFT, const1_rtx,
- val, NULL_RTX, true, OPTAB_DIRECT);
+ rtx val2 = 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;
+ val2 = expand_simple_unop (mode, NOT, val2, NULL_RTX, true);
+ if (expand_atomic_fetch_op (const0_rtx, mem, val2, code, model, false))
+ return;
}
- rtx target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ rtx target;
+ if (lhs)
+ target = expand_expr (lhs, NULL_RTX, VOIDmode, EXPAND_WRITE);
+ else
+ target = gen_reg_rtx (mode);
enum insn_code icode = direct_optab_handler (optab, mode);
gcc_assert (icode != CODE_FOR_nothing);
create_output_operand (&ops[0], target, mode);
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 (!result)
+ {
+ bool is_atomic = gimple_call_num_args (call) == 5;
+ tree tcall = gimple_call_arg (call, 3 + is_atomic);
+ tree fndecl = gimple_call_addr_fndecl (tcall);
+ tree type = TREE_TYPE (TREE_TYPE (fndecl));
+ tree exp = build_call_nary (type, tcall, 2 + is_atomic, ptr,
+ make_tree (type, val),
+ is_atomic
+ ? gimple_call_arg (call, 3)
+ : integer_zero_node);
+ result = expand_builtin (exp, gen_reg_rtx (mode), NULL_RTX,
+ mode, !lhs);
+ }
+ if (!lhs)
+ return;
if (integer_onep (flag))
{
result = expand_simple_binop (mode, ASHIFTRT, result, bitval,
gcc_assert (flag_inline_atomics);
- if (gimple_call_num_args (call) == 4)
+ if (gimple_call_num_args (call) == 5)
model = get_memmodel (gimple_call_arg (call, 3));
rtx mem = get_builtin_sync_mem (ptr, mode);
rtx result = expand_atomic_fetch_op (gen_reg_rtx (mode), mem, op,
code, model, true);
+ if (!result)
+ {
+ bool is_atomic = gimple_call_num_args (call) == 5;
+ tree tcall = gimple_call_arg (call, 3 + is_atomic);
+ tree fndecl = gimple_call_addr_fndecl (tcall);
+ tree type = TREE_TYPE (TREE_TYPE (fndecl));
+ tree exp = build_call_nary (type, tcall,
+ 2 + is_atomic, ptr, arg,
+ is_atomic
+ ? gimple_call_arg (call, 3)
+ : integer_zero_node);
+ result = expand_builtin (exp, gen_reg_rtx (mode), NULL_RTX,
+ mode, !lhs);
+ }
+
if (lhs)
{
result = emit_store_flag_force (target, comp, result, const0_rtx, mode,
tree new_lhs = make_ssa_name (TREE_TYPE (lhs));
tree flag = build_int_cst (TREE_TYPE (lhs), use_bool);
if (has_model_arg)
- g = gimple_build_call_internal (fn, 4, gimple_call_arg (call, 0),
- bit, flag, gimple_call_arg (call, 2));
+ g = gimple_build_call_internal (fn, 5, gimple_call_arg (call, 0),
+ bit, flag, gimple_call_arg (call, 2),
+ gimple_call_fn (call));
else
- g = gimple_build_call_internal (fn, 3, gimple_call_arg (call, 0),
- bit, flag);
+ g = gimple_build_call_internal (fn, 4, gimple_call_arg (call, 0),
+ bit, flag, gimple_call_fn (call));
gimple_call_set_lhs (g, new_lhs);
gimple_set_location (g, gimple_location (call));
gimple_move_vops (g, call);
gimple *g;
tree flag = build_int_cst (TREE_TYPE (lhs), encoded);
if (has_model_arg)
- g = gimple_build_call_internal (fn, 4, flag,
+ g = gimple_build_call_internal (fn, 5, flag,
gimple_call_arg (call, 0),
gimple_call_arg (call, 1),
- gimple_call_arg (call, 2));
+ gimple_call_arg (call, 2),
+ gimple_call_fn (call));
else
- g = gimple_build_call_internal (fn, 3, flag,
+ g = gimple_build_call_internal (fn, 4, flag,
gimple_call_arg (call, 0),
- gimple_call_arg (call, 1));
+ gimple_call_arg (call, 1),
+ gimple_call_fn (call));
gimple_call_set_lhs (g, new_lhs);
gimple_set_location (g, gimple_location (call));
gimple_move_vops (g, call);