Hi!

First off, thanbk you for the patch!

On Mon, Feb 15, 2021 at 11:22:52PM +0000, Neven Sajko via Gcc-patches wrote:
> There is a long-standing, but undocumented GCC inline assembly feature
> that's part of the extended asm GCC extension to C and C++: extended
> asm empty input constraints.

There is no such thing.  *All* empty constraints have the same
semantics: anything whatsoever will do.  Any register, any constant, any
memory.

> --- a/gcc/doc/md.texi
> +++ b/gcc/doc/md.texi
> @@ -1131,7 +1131,102 @@ the addressing register.
>  @subsection Simple Constraints
>  @cindex simple constraints
> 
> -The simplest kind of constraint is a string full of letters, each of
> +An input constraint is allowed to be an empty string, in which case it is
> +called an empty input constraint.

That is just shorthand for "empty constraint that is used for an input
operand".  It is not special, and it *is* documented:
https://gcc.gnu.org/onlinedocs/gcc/Simple-Constraints.html#Simple-Constraints
  The simplest kind of constraint is a string full of letters, each of
  which describes one kind of operand that is permitted.

A length zero string is allowed as well.  This could be made more
explicit sure; OTOH, it isn't very often useful.  So your example
(using it for making a dependency) is certainly useful to have.  But
it is not a special case at all.

> (When an empty input constraint is used,
> +the assembler template will most probably also be empty. I.e., the @code{asm}
> +declaration need not contain actual assembly code.)

Don't use parentheses like this in documentation please.

> An empty input
> +constraint can be used to create an artificial dependency on a C or C++
> +variable (the variable that appears in the expression associated with the
> +constraint) without incurring unnecessary costs to performance.

It still needs a register (or memory) reserved there (or sometimes a
constant can be used, but you have no dependency in that case!)

> +An example of where such behavior may be useful is for preventing compiler
> +optimizations like dead store elimination or hoisting code outside a loop for
> +certain pieces of C or C++ code.

You should not think about preventing the compiler from doing something.
Instead, you can give the compiler extra information that makes it *do*
something: it has to, because it has to implement the semantics your
source program has.

> Specific applications may include direct
> +interaction with hardware features; or things like testing, fuzzing and
> +benchmarking.

What does this mean?


Here is a simple example showing why this isn't as simple to use as
you imply here:

===
void f(int x)
{
        asm volatile("" :: ""(x));
}

void g(void)
{
        return f(42);
}
===

Both function compile to (taking aarch64 as example) just "ret".  But,
if you look at what the compiler does, you see in the "dfinish" pass it
has for f:

(insn:TI 6 3 20 (asm_operands/v ("") ("") 0 [
            (reg:SI 0 x0 [93])
        ]
         [
            (asm_input:SI ("") zlc.c:3)
        ]
         [] zlc.c:3) "zlc.c":3:2 -1
     (expr_list:REG_DEAD (reg:SI 0 x0 [93])
        (nil)))


(so it has register x0 as input), while function g has

(insn:TI 5 2 16 (asm_operands/v ("") ("") 0 [
            (const_int 42 [0x2a])
        ]
         [
            (asm_input:SI ("") zlc.c:3)
        ]
         [] zlc.c:3) "zlc.c":3:2 -1
     (nil))

which has no dependency, gets fed the constant 42 instead, because
*anything at all* is allowed by an empty constraint.

You can also make this clear by using

        asm volatile("# %0" :: ""(x));

which gives
        # x0    
resp.
        # 42    

or, with -fverbose-asm:
        # x0            // tmp93
and
        # 42            //

which is clear as mud, but it means in f there was a variable as input
to the asm, and in g there wasn't.


Segher

Reply via email to