Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Bug in avo -- MOVL should allow XMM registers as a destination. #436

Open
davecgh opened this issue Jun 24, 2024 · 0 comments
Open

Bug in avo -- MOVL should allow XMM registers as a destination. #436

davecgh opened this issue Jun 24, 2024 · 0 comments

Comments

@davecgh
Copy link

davecgh commented Jun 24, 2024

In order to move a 32-bit value from memory into an SSE register, as discussed in this issue, the Go assembler requires the use of MOVL (which is different than the intel/at&t syntax which uses MOVD and chooses based on the source operand).

Go will do a 64-bit load with MOVD despite being a pointer to a 32-bit value. However, avo complains about bad operands when using MOVL since it's not marked as one of its accepted forms.

Here is a minimal example to show the incorrect behavior of MOVD and that MOVL is indeed the correct opcode:

foo.go:

//go:build ignore

package main

import (
	"github.com/mmcloughlin/avo/attr"
	. "github.com/mmcloughlin/avo/build"
)

func main() {
	TEXT("foo", attr.NOSPLIT, "func(n *uint32, out *[16]byte)")
	Pragma("noescape")

	n, _ := Dereference(Param("n")).Resolve()
	r := XMM()
	MOVD(n.Addr, r)

	out, _ := Dereference(Param("out")).Index(0).Resolve()
	MOVOU(r, out.Addr)
	RET()

	Generate()
}

main.go:

//go:generate go run foo.go -out foo_amd64.s -stubs foo_amd64.go -pkg main

package main

import "fmt"

func main() {
	n := uint32(0xaaaaaaaa)
	var out [16]byte
	foo(&n, &out)
	fmt.Printf("%032x\n", out)
}
$ go generate
$ go build && ./issue
aaaaaaaa9854c3000000000000000000     # notice the junk because it moved 64 bits
$ sed -i 's/MOVD/MOVL/' foo_amd64.s  # replace MOVD with MOVL in generated asm
$ go build && ./issue
aaaaaaaa000000000000000000000000     # correct result

It's also pretty evident in looking at the compiled code that the first case using MOVD generates an incorrect MOVQ:

$ go tool objdump -s foo issue
  foo_amd64.s:8         0x48ad40                488b442408              MOVQ 0x8(SP), AX
  foo_amd64.s:9         0x48ad45                f30f7e00                MOVQ 0(AX), X0         <--------- MOVQ
  foo_amd64.s:10        0x48ad49                488b442410              MOVQ 0x10(SP), AX
  foo_amd64.s:11        0x48ad4e                f30f7f00                MOVDQU X0, 0(AX)
  foo_amd64.s:12        0x48ad52                c3                      RET

Whereas MOVL generates the correct MOVD:

$ go tool objdump -s foo issue
  foo_amd64.s:8         0x48ad40                488b442408              MOVQ 0x8(SP), AX
  foo_amd64.s:9         0x48ad45                660f6e00                MOVD 0(AX), X0    <--------- MOVD
  foo_amd64.s:10        0x48ad49                488b442410              MOVQ 0x10(SP), AX
  foo_amd64.s:11        0x48ad4e                f30f7f00                MOVDQU X0, 0(AX)
  foo_amd64.s:12        0x48ad52                c3                      RET
@davecgh davecgh changed the title MOVL should allow XMM registers as a destination. Bug in avo -- MOVL should allow XMM registers as a destination. Jun 25, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant