The encoding/binary package uses portable bit operations to read and write integers.
Using the program:
package test
func readUint64BigEndian(b []byte) uint64 {
_ = b[7] // bounds check hint to compiler; see golang.org/issue/14808
return uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
}
and building with:
GOAMD64=v3 go1.18 build -o test.o test.go
the resulting assembly is:
SUBQ $0x18, SP
MOVQ BP, 0x10(SP)
LEAQ 0x10(SP), BP
MOVQ AX, 0x20(SP)
CMPQ $0x7, BX
JBE 0x9ac
MOVBE 0(AX), AX
MOVQ 0x10(SP), BP
ADDQ $0x18, SP
RET
MOVL $0x7, AX
MOVQ BX, CX
CALL 0x9b9 [1:5]R_CALL:runtime.panicIndex
NOPL
The Zig compiler, with the same code and ReleaseSafe build mode, is able to generate the assembly:
movbe rax, qword ptr [rdi]
ret
See https://godbolt.org/z/MPbE3P9j8.
Note that the movbe instruction was added in AMD64 v3 (https://en.wikipedia.org/wiki/X86-64).
Zig currently uses the LLVM backend, so I don't know if the cost/complexity of this optimization is high.
The
encoding/binarypackage uses portable bit operations to read and write integers.Using the program:
and building with:
the resulting assembly is:
The Zig compiler, with the same code and ReleaseSafe build mode, is able to generate the assembly:
See https://godbolt.org/z/MPbE3P9j8.
Note that the
movbeinstruction was added in AMD64 v3 (https://en.wikipedia.org/wiki/X86-64).Zig currently uses the LLVM backend, so I don't know if the cost/complexity of this optimization is high.