mmcloughlin / avo

Generate x86 Assembly with Go
BSD 3-Clause "New" or "Revised" License
2.71k stars 89 forks source link

gotypes: error with Store(xmm, ReturnIndex(0)) #145

Open rleiwang opened 4 years ago

rleiwang commented 4 years ago

I am trying to implement https://github.com/lemire/streamvbyte/blob/master/src/streamvbyte_x64_decode.c#L2.

However, Using Store(xmm, ReturnIndex(0)) resulted an error in go generate asm.go:85: component is not primitive exit status 1. Instead I changed to Store(xmm, ReturnIndex(0).Index(0)) to work around it.

I also manually changed to use AVX512, VMOVDQU8. The following is Go assembler code.

    // func Shuffle(mask []byte, data []byte) [4]uint32
    // Requires: AVX, SSE2, SSSE3
    TEXT ·Shuffle(SB), NOSPLIT, $0-64
        MOVQ    data_base+24(FP), AX
        VMOVDQU8 (AX), X0
        MOVQ    mask_base+0(FP), AX
        PSHUFB  (AX), X0
        VMOVDQU8 X0, ret_0+48(FP)
        RET
mmcloughlin commented 4 years ago

Would you be able to make this work if your function signature took a pointer to the output? Like:

shuffle(mask, data []byte, out *byte)
mmcloughlin commented 4 years ago

I may be able to extend the gotypes.Component interface to make this possible. I'd need to think about this some more.

https://pkg.go.dev/github.com/mmcloughlin/avo@v0.0.0-20200425082757-f891fe8d9749/gotypes?tab=doc#Component

rleiwang commented 4 years ago

@mmcloughlin Thanks for the quick response. For now, I would prefer use Store(xmm, ReturnIndex(0).Index(0)) if it works, since [4]uint32 is a value type.

mmcloughlin commented 4 years ago

@klauspost has encountered the same problem:

I am trying to generate a function in avo that has func(data [n][16]byte) signature, and I'm trying to load the [16]byte into YMM registers. My problem is that if I use Load(Param("data").Index(i), YMM()) (and XMM) I get component is not primitive and I cannot find a way to get it back to a VecVirtual anyway. I would like to send values directly on the stack, since slices are bigger and pointers is just an extra indirection. I also tried to resolve the address so I could just use a MOVOU myself, but couldn't make that work either.

https://gophers.slack.com/archives/C6WDZJ70S/p1589142748014600

mmcloughlin commented 4 years ago

As discussed on Slack, probably the solution here is to provide an accessor method Component.Addr() for:

https://github.com/mmcloughlin/avo/blob/fa88270b07e447bf4d3d65b081c8f728bc4ba1f7/gotypes/components.go#L64

The only question in my mind is what to do with errors that can occur in method chaining, like when i is too large in Param("data").Index(i).Addr(). Should the signature be:

  1. Addr() operand.Mem which panics when there is an error
  2. Addr() (operand.Mem, error)

If it returns an error, a Must function might be useful. This could possibly belong in the operand package.

rleiwang commented 4 years ago

@mmcloughlin Thanks for the update. I did what you suggested for the time being.

func(masks, data []byte, offset int, out []uint32)

https://github.com/rleiwang/svb/blob/10f63e6855cff78e14a0371425cbf569e8456590/asm.go#L11