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]

problems with read-write "asm" operands


I'm having trouble with a complex bit of inline x86 assembly code in GCC 3.2. I have two read-write operands, but GCC is treating their prior values as dead.

Here's the problematic code:

unsigned counters[3];

int bump(int left, int right)
{
int lt = 0;
int le = 0;

asm ("cmp %3,%4\n"
"setl %b0\n"
"setle %b1\n"
"add %k1,%k0\n"
"incl %2(,%k0,4)\n"
: "+&q,&q" (lt), "+&q,&q" (le)
: "rV,rV" (counters), "r,g" (left), "g,r" (right)
: "cc");
}

The purpose of this function is to bump one of three counters depending on the relative values of left and right. Specifically, it is intended to be a faster version of:

counters[0] += (left < right);
counters[1] += (left == right);
counters[2] += (left > right);

The x86 "setl" and "setle" instructions only set the low-order byte of a 32-bit register. So it's important that the registers holding (lt) and (le) be zeroed at the outset. I'm trying to do that in the C code, since that way GCC can see the initializations and move or optimize them more freely. The (lt) and (le) operands are declared using "+" to tell GCC that they are read-write: I use the initial zero value (read), and I will scribble over that value (write).

However, the generated assembly code contains no zero initialization! I would have expected to see "xor %eax,%eax", for example, if register %eax had been selected. But there's nothing. We jump right into the "cmp" instruction with no clearing of the registers selected for (lt) and (le).

What am I doing wrong here? I thought that "+" would suffice to tell GCC that I care about these operands' values before the assembly directive. But for some reason its throwing those initializing assignments away. :-(

- * -

Secondary question: this assembly code has a side effect. It modifies one of counter[0], counter[1], or counter[2]. But there doesn't seem to be any way for me to tell GCC about this. I could put "memory" in the clobber list, but that seems to be *too* strong. After all, this isn't going to touch arbitrary memory. It's just going to update one of only three possible locations. How can I express that?

- * -

Thanks for any advice. (Oh, and if you think you know a faster way to code the same functionality, I'd love to see it!)


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