This is the mail archive of the
gcc-help@gcc.gnu.org
mailing list for the GCC project.
problems with read-write "asm" operands
- From: Ben Liblit <liblit at eecs dot berkeley dot edu>
- To: gcc-help at gcc dot gnu dot org
- Date: Tue, 05 Nov 2002 18:19:03 -0800
- Subject: 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!)