[Patch] MIPS: Add atomic memory operations for QI and HI modes.

David Daney ddaney@avtrex.com
Thu Apr 24 21:28:00 GMT 2008


Richard Sandiford wrote:
> Hi David,
> 
> David Daney <ddaney@avtrex.com> writes:
>> David Daney wrote:
>>> This patch adds support for QI and HI mode atomic memory operations to
>>> MIPS.  This is a minimal implementation of the QI and HI mode operations
>>> as it only implements sync_compare_and_swap for those modes.  A possible
>>> future enhancement would be to implement the full set of atomic insns
>>> for QI and HI modes, but this should be enough to get libstdc++ building
>>> again.
>>>
>>> The patch borrows from the sparc implementation.
>>>
>>> Currently testing on mipsel-linux with all languages,
>>>
>>> OK to commit if it tests good?
>> And it did:
>>
>> http://gcc.gnu.org/ml/gcc-testresults/2008-04/msg01887.html
>>
>> This gets us back to clean C++ and libstdc++ test results (except for 
>> pr31863.C, which times out occasionally when the system is heavily loaded).
> 
.
.
.
> 
> Finally, I thought it would be worth having a version of mips_emit_binary
> that creates a new register.  That should make it easier to see where a
> value is first initialised.

Thanks, that was bothering me too (but not enough to fix it).  Is there 
any reason not to use a new register each time we do an assignment?

See my questions below..

> 
> Here's a version of the patch with those nits picked.  I also added
> a few more comments.  (I'm sure some folk will think it's now very
> much over-commented...)
> 
> I won't have time to test this for a few days, as my machine is busy
> with other things.  But I tested that it produces the same code as
> your patch for the gcc.torture/compile/sync-1.c test for o32 and n32,
> and it makes that test work for n64.
> 

I will do a full bootstrap on mipsel-linux (should be done tomorrow).  I 
could test a multi-lib bootstrap on mips64-linux but on my O2 that takes 
about a week.



> +/* Expand a QI or HI mode compare_and_swap.  The operands are the same
> +   as for the generator function.  */
> +
> +void
> +mips_expand_compare_and_swap_12 (rtx result, rtx mem, rtx oldval, rtx newval)
> +{
> +  rtx orig_addr, memsi_addr, memsi, shift, shiftsi, unshifted_mask;
> +  rtx mask, inverted_mask, oldvalsi, old_shifted, newvalsi, new_shifted, res;
> +
> +  /* Compute the address of the containing SImode value.  */
> +  orig_addr = force_reg (Pmode, XEXP (mem, 0));
> +  memsi_addr = mips_force_binary (Pmode, AND, orig_addr,
> +				  force_reg (Pmode, GEN_INT (-4)));
> +
> +  /* Create a memory reference for it.  */
> +  memsi = gen_rtx_MEM (SImode, memsi_addr);
> +  set_mem_alias_set (memsi, ALIAS_SET_MEMORY_BARRIER);
> +  MEM_VOLATILE_P (memsi) = MEM_VOLATILE_P (mem);
> +
> +  /* Work out the byte offset of the QImode or HImode value,
> +     counting from the least significant byte.  */
> +  shift = mips_force_binary (Pmode, AND, orig_addr, GEN_INT (3));
> +  if (TARGET_BIG_ENDIAN)
> +    mips_emit_binary (XOR, shift, shift,
> +		      GEN_INT (GET_MODE (mem) == QImode ? 3 : 2));

Why not mips_force_binary here^^^?

> +
> +  /* Multiply by eight to convert the shift value from bytes to bits.  */
> +  mips_emit_binary (ASHIFT, shift, shift, GEN_INT (3));
> +

And here ^^^?

> +  /* Make the final shift an SImode value, so that it can be used in
> +     SImode operations.  */
> +  shiftsi = force_reg (SImode, gen_lowpart (SImode, shift));
> +
> +  /* Set MASK to an inclusive mask of the QImode or HImode value.  */
> +  unshifted_mask = GEN_INT (GET_MODE_MASK (GET_MODE (mem)));
> +  unshifted_mask = force_reg (SImode, unshifted_mask);
> +  mask = mips_force_binary (SImode, ASHIFT, unshifted_mask, shiftsi);
> +
> +  /* Compute the equivalent exclusive mask.  */
> +  inverted_mask = gen_reg_rtx (SImode);
> +  emit_insn (gen_rtx_SET (VOIDmode, inverted_mask,
> +			  gen_rtx_NOT (SImode, mask)));
> +
> +  /* Shift the old value into place.  */
> +  oldvalsi = force_reg (SImode, gen_lowpart (SImode, oldval));
> +  old_shifted = mips_force_binary (SImode, ASHIFT, oldvalsi, shiftsi);
> +
> +  /* Do the same for the new value.  */
> +  newvalsi = force_reg (SImode, gen_lowpart (SImode, newval));
> +  new_shifted = mips_force_binary (SImode, ASHIFT, newvalsi, shiftsi);
> +
> +  /* Do the SImode atomic access.  */
> +  res = gen_reg_rtx (SImode);
> +  emit_insn (gen_compare_and_swap_12 (res, memsi, mask, inverted_mask,
> +				      old_shifted, new_shifted));
> +
> +  /* Shift and convert the result.  */
> +  mips_emit_binary (AND, res, res, mask);

And here ^^^?

> +  mips_emit_binary (LSHIFTRT, res, res, shiftsi);

And here^^^?

> +  mips_emit_move (result, gen_lowpart (GET_MODE (result), res));
> +}
> +

I may bootstrap it changing those to mips_force_binary.

David Daney



More information about the Gcc-patches mailing list