This is the mail archive of the gcc-help@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: bug around inline asm, or expected?


On 7/20/07, Luke <luke@neoclaw.net> wrote:
I hit an odd problem recently while working with some inline assembly
(x86).  I'm not sure if it's a bug, or if it is expected behavior.  I
managed to repro it in a small compilable file:

#include <iostream>

//Compares expectedValue with the value at pInt, and if they are the
same, sets pInt to newValue and returns true with outResultValue set to
newValue.  If they are different then pInt is unaffected, and returns
false with outResultValue set to the value that was found at pInt.
inline bool AtomicCompareExchange(volatile unsigned int *pInt, unsigned
int expectedValue, unsigned int newValue, volatile unsigned int
&outResultValue)
{
   unsigned int changed=0;
   unsigned int rval;
   asm(
           "lock cmpxchgl %4, (%2);"
           "jnz AtomCmpExch_Diff%=;"
           "movl %4, %%eax;"
           "incl %1;"
           "AtomCmpExch_Diff%=:;"
           "movl %%eax, %0;"
       :"=g"(rval), "=g"(changed)
       :"r"(pInt), "a"(expectedValue), "r"(newValue)
       :"memory", "cc");

   outResultValue=rval;
   return changed!=0;
}

int main()
{
   unsigned int value=0x100;
   unsigned int ignored;
   bool changed=AtomicCompareExchange(&value, 0x200, 0x300, ignored);
     if (changed) std::cout<<"Returned true, but should have returned
false.\n";
   else std::cout<<"Returned false as expected.\n";
     return 0;
}

With optimization off it works fine.  Running g++ with -O1 or -O2
though, and it hits a problem: that the inline function always returns
true, when it should in this case return false.  I actually did find a
"solution" to it.  Declaring the "unsigned int changed=0;" as volatile
prevents the problem from happening.  However, it seems a bit odd that
that's necessary, seeing as it's given as an output parameter in the asm
declaration.

Here's the output of g++ -v:
Using built-in specs.
Target: i486-linux-gnu
Configured with: ../src/configure -v
--enable-languages=c,c++,fortran,objc,obj-c++,treelang --prefix=/usr
--enable-shared --with-system-zlib --libexecdir=/usr/lib
--without-included-gettext --enable-threads=posix --enable-nls
--with-gxx-include-dir=/usr/include/c++/4.1.3 --program-suffix=-4.1
--enable-__cxa_atexit --enable-clocale=gnu --enable-libstdcxx-debug
--enable-mpfr --with-tune=i686 --enable-checking=release i486-linux-gnu
Thread model: posix
gcc version 4.1.3 20070629 (prerelease) (Debian 4.1.2-13)


You can try the following: 1) add "volatile" after the "asm" keyword so that GCC doesn't try to move the inline asm block around during the optimization. 2) add ".set noreorder". This should instruct the assembler to emit the instruction "as-is" without doing any reordering optimizations.

--
Mohamed


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]