instruction gen in amd64, it iseems not the best choice?

114 views
Skip to first unread message

xie cui

unread,
Aug 25, 2020, 11:04:15 PM8/25/20
to golang-nuts
function:
func test3(a int) int {
  return a * 3 + 4
}

go version go1.13.5 darwin/amd64
generate instructions:
  LEAQ    (AX)(AX*2), AX
  LEAQ    4(AX), AX

As far as i known,there a better choice
 LEAQ    4(AX*3), AX

Can it be optimized?

peterGo

unread,
Aug 26, 2020, 12:22:30 AM8/26/20
to golang-nuts
Go has optimizing compilers and linkers which are constantly being improved.

The following example of your program reduces the call to test3 to

MOVQ $0x82, 0(SP)

where 0x82 = 130 = 42 * 3 + 4

$ cat xiecui.go
package main


func test3(a int) int {
    return a*3 + 4
}

func main() {
    a := 42
    t := test3(a)
    println(t)
}

$ go version
go version devel +758ac371ab Tue Aug 25 21:15:43 2020 +0000 linux/amd64

$ go build xiecui.go

$ ./xiecui
130

$ go tool compile -S xiecui.go > xiecui.compile

"".test3 STEXT nosplit size=19 args=0x10 locals=0x0 funcid=0x0
    0x0000 00000 (xiecui.go:3)    TEXT    "".test3(SB), NOSPLIT|ABIInternal, $0-16
    0x0000 00000 (xiecui.go:3)    FUNCDATA    $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x0000 00000 (xiecui.go:3)    FUNCDATA    $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x0000 00000 (xiecui.go:4)    MOVQ    "".a+8(SP), AX
    0x0005 00005 (xiecui.go:4)    LEAQ    (AX)(AX*2), AX
    0x0009 00009 (xiecui.go:4)    LEAQ    4(AX), AX
    0x000d 00013 (xiecui.go:4)    MOVQ    AX, "".~r1+16(SP)
    0x0012 00018 (xiecui.go:4)    RET
"".main STEXT size=77 args=0x0 locals=0x10 funcid=0x0
    0x0000 00000 (xiecui.go:7)    TEXT    "".main(SB), ABIInternal, $16-0
    0x0000 00000 (xiecui.go:7)    MOVQ    (TLS), CX
    0x0009 00009 (xiecui.go:7)    CMPQ    SP, 16(CX)
    0x000d 00013 (xiecui.go:7)    PCDATA    $0, $-2
    0x000d 00013 (xiecui.go:7)    JLS    70
    0x000f 00015 (xiecui.go:7)    PCDATA    $0, $-1
    0x000f 00015 (xiecui.go:7)    SUBQ    $16, SP
    0x0013 00019 (xiecui.go:7)    MOVQ    BP, 8(SP)
    0x0018 00024 (xiecui.go:7)    LEAQ    8(SP), BP
    0x001d 00029 (xiecui.go:7)    FUNCDATA    $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x001d 00029 (xiecui.go:7)    FUNCDATA    $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x001d 00029 (xiecui.go:10)    PCDATA    $1, $0
    0x001d 00029 (xiecui.go:10)    NOP
    0x0020 00032 (xiecui.go:10)    CALL    runtime.printlock(SB)
    0x0025 00037 (xiecui.go:10)    MOVQ    $130, (SP)
    0x002d 00045 (xiecui.go:10)    CALL    runtime.printint(SB)
    0x0032 00050 (xiecui.go:10)    CALL    runtime.printnl(SB)
    0x0037 00055 (xiecui.go:10)    CALL    runtime.printunlock(SB)
    0x003c 00060 (xiecui.go:11)    MOVQ    8(SP), BP
    0x0041 00065 (xiecui.go:11)    ADDQ    $16, SP
    0x0045 00069 (xiecui.go:11)    RET
    0x0046 00070 (xiecui.go:11)    NOP
    0x0046 00070 (xiecui.go:7)    PCDATA    $1, $-1
    0x0046 00070 (xiecui.go:7)    PCDATA    $0, $-2
    0x0046 00070 (xiecui.go:7)    CALL    runtime.morestack_noctxt(SB)
    0x004b 00075 (xiecui.go:7)    PCDATA    $0, $-1
    0x004b 00075 (xiecui.go:7)    JMP    0

$ go tool objdump xiecui > xiecui.objdump

TEXT main.main(SB) /home/peter/Sync/gopath/mod/nuts/xiecui.go
  xiecui.go:7        0x45cc80        64488b0c25f8ffffff    MOVQ FS:0xfffffff8, CX           
  xiecui.go:7        0x45cc89        483b6110        CMPQ 0x10(CX), SP           
  xiecui.go:7        0x45cc8d        7637            JBE 0x45ccc6               
  xiecui.go:7        0x45cc8f        4883ec10        SUBQ $0x10, SP               
  xiecui.go:7        0x45cc93        48896c2408        MOVQ BP, 0x8(SP)           
  xiecui.go:7        0x45cc98        488d6c2408        LEAQ 0x8(SP), BP           
  xiecui.go:10        0x45cc9d        0f1f00            NOPL 0(AX)               
  xiecui.go:10        0x45cca0        e89b17fdff        CALL runtime.printlock(SB)       
  xiecui.go:10        0x45cca5        48c7042482000000    MOVQ $0x82, 0(SP)           
  xiecui.go:10        0x45ccad        e8ae1ffdff        CALL runtime.printint(SB)       
  xiecui.go:10        0x45ccb2        e8491afdff        CALL runtime.printnl(SB)       
  xiecui.go:10        0x45ccb7        e80418fdff        CALL runtime.printunlock(SB)       
  xiecui.go:11        0x45ccbc        488b6c2408        MOVQ 0x8(SP), BP           
  xiecui.go:11        0x45ccc1        4883c410        ADDQ $0x10, SP               
  xiecui.go:11        0x45ccc5        c3            RET                   
  xiecui.go:7        0x45ccc6        e8d5b0ffff        CALL runtime.morestack_noctxt(SB)   
  xiecui.go:7        0x45cccb        ebb3            JMP main.main(SB)   

$

Peter

moeh...@google.com

unread,
Aug 26, 2020, 2:31:31 PM8/26/20
to golang-nuts
As far as I am aware:

A LEA with a scale of 3 does not exist on amd64. Scale can be 1,2,4,8.

A LEA with 3 arguments LEAQ 4(AX)(AX*2) on many modern amd64 compatible machines will use 3 cycles instead of 2 for two simpler LEA.
The newest generation of Intel CPUs seems to have gotten better again avoiding slow LEA.

https://github.com/golang/go/issues/21735
Reply all
Reply to author
Forward
0 new messages