Adding xadd instruction to X86

Hi,

I'm trying to add the xadd instruction to the X86 back end.
xadd r/m32, r32
exchanges r/m32 and r32, and loads the sum into r/m32. I'm
interested in the case where the destination operand is a
memory location.

I've added the following entry to X86InstrInfo.td:
def XADD32mr : I<0x87, MRMDestMem,
                (ops i32mem:$src1, R32:$src2),
                "xadd{l} {$src1|$src2}, {$src2|$src1}">;

The xadd is emitted for the intrinsic function:
call int (<integer type>*, <integer type>)*
%llvm.atomic_fetch_add_store(<integer type>* <pointer>,
                                                           
<integer type> <value>)

I currently have the following code (PtrReg contains the
pointer argument, ValReg the value arg, and TmpReg an unused
register.):

addDirectMem(BuildMI(BB, X86::XADD32mr, 4,
TmpReg).addReg(TwoReg), ValReg);

This fails the assertion isMem. Any help with this would be
appreciated.

Thanks,

Brent

Brent Monroe wrote:

Hi,

I'm trying to add the xadd instruction to the X86 back end. xadd r/m32, r32 exchanges r/m32 and r32, and loads the sum into r/m32. I'm
interested in the case where the destination operand is a
memory location.

I think it might be easier if you drop by my office. I'll be here until 5:30, and I'll be here until 5:00 tomorrow.

I've added the following entry to X86InstrInfo.td:
def XADD32mr : I<0x87, MRMDestMem,
                (ops i32mem:$src1, R32:$src2),
                "xadd{l} {$src1|$src2}, {$src2|$src1}">;

Comparing it to the XCHG32mr instruction, the last line as $src1 and $src2 reversed. Is this correct?

The xadd is emitted for the intrinsic function:
call int (<integer type>*, <integer type>)*
%llvm.atomic_fetch_add_store(<integer type>* <pointer>,
                                                           <integer type> <value>)

I currently have the following code (PtrReg contains the
pointer argument, ValReg the value arg, and TmpReg an unused
register.):

addDirectMem(BuildMI(BB, X86::XADD32mr, 4,
TmpReg).addReg(TwoReg), ValReg);

This fails the assertion isMem. Any help with this would be
appreciated.

Thanks,

Brent

_______________________________________________
LLVM Developers mailing list
LLVMdev@cs.uiuc.edu http://llvm.cs.uiuc.edu
http://mail.cs.uiuc.edu/mailman/listinfo/llvmdev

-- John T.

I'm trying to add the xadd instruction to the X86 back end.
xadd r/m32, r32
exchanges r/m32 and r32, and loads the sum into r/m32. I'm
interested in the case where the destination operand is a
memory location.

I've added the following entry to X86InstrInfo.td:
def XADD32mr : I<0x87, MRMDestMem,
                (ops i32mem:$src1, R32:$src2),

This looks fine.

                "xadd{l} {$src1|$src2}, {$src2|$src1}">;

I haven't checked this, but it's probably fine.

The xadd is emitted for the intrinsic function:
call int (<integer type>*, <integer type>)*
%llvm.atomic_fetch_add_store(<integer type>* <pointer>,

<integer type> <value>)

I currently have the following code (PtrReg contains the
pointer argument, ValReg the value arg, and TmpReg an unused
register.):

addDirectMem(BuildMI(BB, X86::XADD32mr, 4,
TmpReg).addReg(TwoReg), ValReg);

This is the problem. Try this:
addDirectMem(BuildMI(BB, X86::XADD32mr, 4, TmpReg), ValReg).addReg(TwoReg);

In particular, you want to add the memory address before the other reg.

Another problem though, is that (without looking at manual) I think xadd
modifies the register value. If this is the case, you will want to define
it as a "two-operand" instruction. Making the above change should get the
assertion to go away though.

-Chris

Chris Lattner wrote:

I'm trying to add the xadd instruction to the X86 back end.
xadd r/m32, r32
exchanges r/m32 and r32, and loads the sum into r/m32. I'm
interested in the case where the destination operand is a
memory location.

I've added the following entry to X86InstrInfo.td:
def XADD32mr : I<0x87, MRMDestMem,
               (ops i32mem:$src1, R32:$src2),

This looks fine.

               "xadd{l} {$src1|$src2}, {$src2|$src1}">;

I haven't checked this, but it's probably fine.

The xadd is emitted for the intrinsic function:
call int (<integer type>*, <integer type>)*
%llvm.atomic_fetch_add_store(<integer type>* <pointer>,

<integer type> <value>)

I currently have the following code (PtrReg contains the
pointer argument, ValReg the value arg, and TmpReg an unused
register.):

addDirectMem(BuildMI(BB, X86::XADD32mr, 4,
TmpReg).addReg(TwoReg), ValReg);

This is the problem. Try this:
addDirectMem(BuildMI(BB, X86::XADD32mr, 4, TmpReg), ValReg).addReg(TwoReg);

In particular, you want to add the memory address before the other reg.

Another problem though, is that (without looking at manual) I think xadd
modifies the register value. If this is the case, you will want to define
it as a "two-operand" instruction. Making the above change should get the
assertion to go away though.

How do we define an instruction as a two-operand instruction?

-Chris

-- John T.

let isTwoAddress = 1 in
  // instruction def

See X86InstrInfo.def for examples.

Chris Lattner wrote:
> Another problem though, is that (without looking at manual) I think xadd
> modifies the register value. If this is the case, you will want to define
> it as a "two-operand" instruction. Making the above change should get the
> assertion to go away though.

How do we define an instruction as a two-operand instruction?

As Misha said, you add the isTwoAddress attribute to the instruction.
However, this is necessary, but not sufficient. :slight_smile:

Here's the deal. X86 is inherently a two address machine, with many
operations like this. Other architectures have instructions which are
read/modify/write in the same way, e.g. cmoves, rlwimi on PPC, etc, and
are handled the same. Consider the following X86 instruction:

  REG += REG

This doesn't work well for SSA and many compiler analyses/optimizations.
To deal with this, we model this instruction as:

  DestReg = SrcReg + REG

... splitting the read/modify/write appart. To make this *CORRECT*, we
force the register allocator to allocate the first two operands to the
same physical register (this is what isTwoAddress actually causes to
happen). Note that isTwoAddress is currently limited to working with
instructions whose 'twoaddressness' is the 0th and 1st operand, so to use
this, your instruction must have the two-addressy operand there.

From my understanding of XADD and your goals, you basically want this

instruction (in intel syntax):

LOCK; XADD [mem], REG32

This operation has the effect of atomically doing these operations:

  tmp = load [mem]
  [mem] += REG32
  REG32 = tmp

This operation read/modify/writes both memory and the register. The
memory doesn't need special two-address support to implement, so you'd
implement this like this:

R32Result = XADD32mr_LOCKED R32Src, [memloc]

And mark it two address. This form would lead to something like this in
the .td file:

let isTwoAddress = 1 in
  def XADD32mr_LOCKED : I<0xC1, MRMDestMem,
                           (ops R32:$dst, R32:$srcreg, i32mem:$mem),
                           "xadd{l} {$dst|$mem}, {$mem|$dst}">, LOCK, TB;

Note that the X86 backend currently doesn't define 'LOCK'. To implement
it, look at how other prefixes like TB, and REP are implemented. Also,
I'm not sure where you got the 0x87 opcode from: from what I can see, xadd
(mem32) is 0xC1.

Hopefully this helps, if so, I would appreciate it if you could
massage it and turn it into a patch against llvm/doc/CodeGenerator.html :slight_smile:

-Chris