> ! weak = expand_expr (CALL_EXPR_ARG (exp, 3), NULL_RTX, ptr_mode,
> ! EXPAND_NORMAL);
> !
> ! if (weak != const0_rtx && weak != const1_rtx)
> ! {
> ! error ("strong/weak parameter must be 0 or 1 for
> %<__atomic_compare_exchange%>");
> ! return NULL_RTX;
> ! }
Really? Are you even allowed to do that, like unto the variable memory model
parameters?
> + /* Emit the compare_and_swap. */
> create_output_operand (&ops[0], target, QImode);
> create_output_operand (&ops[1], mem, mode);
> ! create_output_operand (&ops[2], current_val, mode);
> ! create_convert_operand_to (&ops[3], expected_val, mode, true);
> ! create_convert_operand_to (&ops[4], desired, mode, true);
> ! create_integer_operand (&ops[5], success);
> ! expand_insn (icode, 6, ops);
The mem operand must use create_fixed_operand, as with all of the other atomic
builtins.
I strongly suggest swapping op 1 and op2, so that all of the "real" outputs
come first.
I suggested on IRC that you examine the mode of the boolean output operand, and
not
hard-code QImode. Most targets will produce a word-sized boolean output that
need not
be zero-extended.
> ! emit_cmp_and_jump_insns (ops[0].value, const0_rtx, NE, const0_rtx,
> ! QImode, 1, true_label);
> !
> ! /* if not successful copy expected_val into *expected and issue the
> ! failure fence. */
> ! emit_move_insn (gen_rtx_MEM (mode, expected), current_val);
> ! expand_builtin_mem_thread_fence (failure);
> !
> ! /* If no success fence is required, we're done. Otherwise jump around
> the
> ! code for TRUE and emitthe fence. */
> ! if (true_label != done_label)
> ! {
> ! emit_jump_insn (gen_jump (done_label));
> !
> ! emit_label (true_label);
> ! if (success != MEMMODEL_RELAXED && success != MEMMODEL_RELEASE)
> ! expand_builtin_mem_thread_fence (success);
> ! }
Really? We can do better than this. In particular, by leaving it up to the
target.
In the x86 case, cmpxchg is a full barrier. Always. No need for any followup
barriers.
The ll/sc targets are going to generate code that looks like
start-barrier
restart:
ll curval, mem
mov t, 0
cmp curval, oldval
bne fail
mov t, newval
sc t, mem
beq t, restart // strong-version only
fail:
end-barrier
// outputs: t = 1/0 for success/failure
// curval = the current value of the memory, to be stored back into
expected
where the position of fail: before or after the end-barrier depends on the
relative
strength of the memory models. No one is going to want to insert an extra jump
around a barrier, especially for a not-expected failure path.
We should encode the two memory model parameters and the weak parameter into a
single
CONST_INT operand. Probably with some macros in optabs.h to extract those
parameters
in the targets.
r~