> !   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~

Reply via email to