public inbox for gcc-help@gcc.gnu.org
 help / color / mirror / Atom feed
* problems with read-write "asm" operands
@ 2002-11-05 18:19 Ben Liblit
  2002-11-05 18:44 ` Ben Liblit
  0 siblings, 1 reply; 2+ messages in thread
From: Ben Liblit @ 2002-11-05 18:19 UTC (permalink / raw)
  To: gcc-help

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!)

^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: problems with read-write "asm" operands
  2002-11-05 18:19 problems with read-write "asm" operands Ben Liblit
@ 2002-11-05 18:44 ` Ben Liblit
  0 siblings, 0 replies; 2+ messages in thread
From: Ben Liblit @ 2002-11-05 18:44 UTC (permalink / raw)
  To: gcc-help

Sorry to reply to my own posting, but here's a slightly simpler version 
of the same code with nearly the same problem:

	unsigned counters[3];

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

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

	  ++counters[slot];
	}

The job of the inline assembly code is now just to set "slot" to either 
0, 1, or 2 depending on whether left is <, ==, or > right.  Manipulation 
of the counters array is done in C code, which makes things somewhat 
more readable and more clearly expresses what kinds of side effects can 
occur.

Both "slot" and "le" are zero initialized in the C code, and both are 
declared as read-write ("+") operands.  However....

   - If I compile with "-O9", the register selected for "slot" is
     correctly zero initialized.  The register selected for "le",
     however, is not.  It simply inherits whatever leftover value
     might previously have been in that register.

   - If I compile with "-g", neither register is zero initialized.
     Each simply inherits whatever leftover value might previously have
     been in its selected register.

This is getting mighty strange.  Anybody got a clue?

^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2002-11-06  2:44 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2002-11-05 18:19 problems with read-write "asm" operands Ben Liblit
2002-11-05 18:44 ` Ben Liblit

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).