[PATCH] Atomic swap and test-and-set

Bruce Evans brde at optusnet.com.au
Wed Jul 31 20:42:34 UTC 2013


On Wed, 31 Jul 2013, Konstantin Belousov wrote:

> On Tue, Jul 30, 2013 at 03:56:36PM -0400, Jung-uk Kim wrote:
>> ...
>> Please let me know if you have any objection.
> I think that the atomic.diff is fine.
>
> You did not documented swap and testandset, which would be good to have
> in the manpage.
>
> I think that constraints for all added inlines contradict the explicit
> requirement in the gcc documentation, which states that rmw operands
> should be specified using the 'same location' output operand for the
> input operand (hopefully this can be parsed).  It just happens so that
> for "m" compiler cannot do anything else then passing the address.
>
> The problem is not specific to the new functions, it seems to be present
> in other functions as well, e.g. cmpset.  This probably can be postponed.

The problem is the opposite.  The other functions used to use the '+'
constraint to indicate input-output operands, but gcc broke this so it
was changed in 2005.  gcc.info still says fuzzily that the '+' constraint
"should" only be used for operands that can be allocated in a register:

%  The ordinary output operands must be write-only; GCC will assume that
% the values in these operands before the instruction are dead and need
% not be generated.  Extended asm supports input-output or read-write
% operands.  Use the constraint character `+' to indicate such an operand
% and list it with the output operands.  You should only use read-write
                                              ^^^^^^
% operands when the constraints for the operand (or the operand in which
% only some of the bits are to be changed) allow a register.
                                            ^^^^^^^^^^^^^^^^

but using it for non-register operands caused problems, so the requirement
was "shall".

%  You may, as an alternative, logically split its function into two
             ^^^^^^^^^^^^^^^^^
% separate operands, one input operand and one write-only output operand.
% The connection between them is expressed by constraints which say they
% need to be in the same location when the instruction executes.  You can
% use the same C expression for both operands, or different expressions.
% For example, here we write the (fictitious) `combine' instruction with
% `bar' as its read-only source operand and `foo' as its read-write
% destination:
% 
%      asm ("combine %2,%0" : "=r" (foo) : "0" (foo), "g" (bar));
% 
% The constraint `"0"' for operand 1 says that it must occupy the same
% location as operand 0.  A number in constraint is allowed only in an
% input operand and it must refer to an output operand.

This says the '0' constraint is just an alternative (worse) way of writing
the '+' constraint.

The '+' and '0' constraints should be allowed for all types of operands.
If the compiler doesn't need them for correctness, then they should work
as syntactic sugar for avoiding repeating operands.  (The '0' constraint
is bad since it works as syntactic salt and increases the number of
operands.  The magic numbers for a large number of operands are hard
enough to keep track of without unnecessary ones increasing the number.)
But I think constrains indicating input-output operands, and even more,
are needed for correctness for memory operands.  Without them, there
seems to be nothing (except volatile qualifiers and optimization) to
prevent the compiler copying an input operand to a different place in
memory.  It would have to copy the input operand to memory if it is not
already in memory (and the constraint says memory), and it is not clear
that it can't do this for operands of the form (*dst).  Using the pointer
and hiding the accesses through it in the asm is no good as a fix, since
it now requires memory clobbers and perhaps another register to hold the
pointer.

Perhaps this is fixed in clang or in newer gcc's, but it is hard to
keep down with compiler bugs.  It actually became worse between gcc-3
and gcc-4.  In gcc-3, gcc.info said that the '+' constraint was required
for input-output operands (with no restriction to register operands),
and that the '0' constraint was an alternative restricted to register
operands.  Now it says the above (that '+' "should" only be used for
register operands, and that '0' is an alternative with no other
restrictions).  Hmm, another reading of the gcc-4 info is that it says
that it is input-output operands that require a register operand, so
that it is just invalid to try to make a memory operand input-output.

Bruce


More information about the freebsd-arch mailing list