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