This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [cxx-mem-model] compare_exchange implementation


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


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]