asm with C expression operands (i386)

Andrew Haley aph@redhat.com
Thu Apr 30 11:06:00 GMT 2009


Tomek wrote:
> Hello
> 
> I am asking about memory constraints in asm statements.
> Suppose we have a class:
> 
> class foo
> {
> public:
>         int table[2];
> };
> 
> and a function
> 
> void do_something(foo & out_in, const foo & in)
> {
>      __asm__ (
>      "do something with out_in.table and in.table"
>      );
> }
> 
> I am not sure how to correctly write constraints for out_in.table and
> in.table. Assume that 'in' object is only for reading and 'out_in' is
> for reading and writing. Following http://gcc.gnu.org/onlinedocs/gcc/Extended-Asm.html
> I was trying to write:
> 
> void do_something(foo & out_in, const foo & in)
> {
>     __asm__ (
>     "some magic stuff"
>     : "+m"( ({ struct { int x[2]; } *p = (void *)out_in.table ; *p; }) )
>     : other constraints
>     : ....
>     );
> }
> 
> but it gave me:
> test.cpp:50: error: invalid conversion from 'void*' to 'do_something(foo&, const foo&)::<anonymous struct>*'
> (gcc 4.3.3 mingw)
> 
> I changed a little the function and got:
> 
> void do_something(foo & out_in, const foo & in)
> {
> struct temp { int t[2]; };
> temp * table1 = (temp*)out_in.table;
> temp * table2 = (temp*)in.table;

I don't think this is even legal C++.

> 
>    __asm__ (
>    // out_in.table[0] = in.table[0] + in.table[1] + out_in.table[0];
>    // out_in.table[1] = 0;
>    // (i386 asm)
>    
>    "movl (%%ecx),  %%eax   \n"
>    "addl 4(%%ecx), %%eax   \n"
>    "addl %%eax, (%%ebx)    \n"
>    "movl $0, 4(%%ebx)              \n"
> 
>    : "+m" ( *table1 )
>    : "b" (out_in.table), "c" (in.table), "m" ( *table2 )
>    : "%eax", "cc"
>    );
> }
> 
> And my question: is that a correct way to declare that out_in.table
> is read and written by the asm statement (and in.table is only
> for reading)? In this example don't I need to use 'volatile' with the
> __asm__ keyword?

I don't think so.

I've discussed this with some other gcc developers, and consensus is
that if you want to be safe, clobber memory and make the asm volatile.

Like this:

  __asm__ volatile (
	   // out_in.table[0] = in.table[0] + in.table[1] + out_in.table[0];
	   // out_in.table[1] = 0;
	   // (i386 asm)

	   "movl (%2),  %0   \n"
	   "addl 4(%2), %1   \n"
	   "addl %0, (%1)    \n"
	   "movl $0, 4(%1)       \n"

	   : "+r"(tmp)
	   : "r" (out_in.table), "r" (in.table)
	   : "cc", "memory" );

This does mean that your asm is effectively a memory barrier, but we can't
see any way to avoid that.

Andrew.



More information about the Gcc-help mailing list