Repository: go
Issue: cmd/compile: a flaw in algebraic simplification rules inside Go compiler
Labels: Performance,NeedsInvestigation,compiler/runtime

<!--
Please answer these questions before submitting your issue. Thanks!
For questions please use one of our forums: https://github.com/golang/go/wiki/Questions
-->

### What version of Go are you using (`go version`)?

<pre>
$ go version
go version go1.14 windows/amd64
</pre>

### Does this issue reproduce with the latest release?

Yes.

### What operating system and processor architecture are you using (`go env`)?

<details><summary><code>go env</code> Output</summary><br><pre>
$ go env
set GO111MODULE=                                                                                                                                                                              set GOARCH=amd64                                                                                                                                                                              set GOBIN=                                                                                                                                                                                    set GOCACHE=C:\Users\Peter\AppData\Local\go-build                                                                                                                                             set GOENV=C:\Users\Peter\AppData\Roaming\go\env                                                                                                                                               set GOEXE=.exe                                                                                                                                                                                set GOFLAGS=                                                                                                                                                                                  set GOHOSTARCH=amd64                                                                                                                                                                          set GOHOSTOS=windows                                                                                                                                                                          set GOINSECURE=                                                                                                                                                                               set GONOPROXY=                                                                                                                                                                                set GONOSUMDB=                                                                                                                                                                                set GOOS=windows                                                                                                                                                                              set GOPATH=C:\Users\Peter\go                                                                                                                                                                  set GOPRIVATE=                                                                                                                                                                                set GOPROXY=https://proxy.golang.org,direct                                                                                                                                                   set GOROOT=D:\Programs\Go                                                                                                                                                                     set GOSUMDB=sum.golang.org                                                                                                                                                                    set GOTMPDIR=                                                                                                                                                                                 set GOTOOLDIR=D:\Programs\Go\pkg\tool\windows_amd64                                                                                                                                           set GCCGO=gccgo                                                                                                                                                                               set AR=ar                                                                                                                                                                                     set CC=gcc                                                                                                                                                                                    set CXX=g++                                                                                                                                                                                   set CGO_ENABLED=1                                                                                                                                                                             set GOMOD=                                                                                                                                                                                    set CGO_CFLAGS=-g -O2                                                                                                                                                                         set CGO_CPPFLAGS=                                                                                                                                                                             set CGO_CXXFLAGS=-g -O2                                                                                                                                                                       set CGO_FFLAGS=-g -O2                                                                                                                                                                         set CGO_LDFLAGS=-g -O2                                                                                                                                                                        set PKG_CONFIG=pkg-config                                                                                                                                                                     set GOGCCFLAGS=-m64 -mthreads -fmessage-length=0 -fdebug-prefix-map=C:\Users\Peter\AppData\Local\Temp\go-build872647486=/tmp/go-build -gno-record-gcc-switches 
</pre></details>

### What did you do?

<!--
If possible, provide a recipe for reproducing the error.
A complete runnable program is good.
A link on play.golang.org is best.
-->

<pre>
package main

func foo(x int, y int, z int, abc int) int {
    return (((((1000 - x) + y) - z) - 10) + abc) - 42;
}
</pre>

### What did you expect to see?

I was expecting to see "abc - x + y - z + 948" as the result.

### What did you see instead?

<pre>
"".foo STEXT nosplit size=46 args=0x28 locals=0x0
    0x0000 00000 (1.go:5)   TEXT    "".foo(SB), NOSPLIT|ABIInternal, $0-40
    0x0000 00000 (1.go:5)   PCDATA  $0, $-2
    0x0000 00000 (1.go:5)   PCDATA  $1, $-2
    0x0000 00000 (1.go:5)   FUNCDATA    $0, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x0000 00000 (1.go:5)   FUNCDATA    $1, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x0000 00000 (1.go:5)   FUNCDATA    $2, gclocals·33cdeccccebe80329f1fdbee7f5874cb(SB)
    0x0000 00000 (1.go:6)   PCDATA  $0, $0
    0x0000 00000 (1.go:6)   PCDATA  $1, $0
    0x0000 00000 (1.go:6)   MOVQ    "".y+16(SP), AX
    0x0005 00005 (1.go:6)   MOVQ    "".x+8(SP), CX
    0x000a 00010 (1.go:6)   SUBQ    CX, AX
    0x000d 00013 (1.go:6)   ADDQ    $1000, AX
    0x0013 00019 (1.go:6)   MOVQ    "".z+24(SP), CX
    0x0018 00024 (1.go:6)   SUBQ    CX, AX
    0x001b 00027 (1.go:6)   MOVQ    "".abc+32(SP), CX
    0x0020 00032 (1.go:6)   LEAQ    (CX)(AX*1), AX
    0x0024 00036 (1.go:6)   LEAQ    -52(AX), AX
    0x0028 00040 (1.go:6)   MOVQ    AX, "".~r4+40(SP)
    0x002d 00045 (1.go:6)   RET
</pre>

So clearly there is a room for improvement in rules of algebraic simplifications of the compiler.

I suggest to add/replace just a few of reassociate rules in the file "https://github.com/golang/go/blob/master/src/cmd/compile/internal/ssa/gen/generic.rules". I made my own set of rules for add/sub combinations which could be used here:

<pre>
    # x + (C - z) -> C + (x - z)
    # x - (z - C) -> C + (x - z)
    # x - (z + C) -> (x - z) - C
    # x - (C - z) -> (x + z) - C
    # (x + C) - z -> C + (x - z)
    # (C - x) - z -> C - (x - z)
    # C + (D - x) -> (C + D) - x
    # C + (x - D) -> (C - D) + x
    # C - (x - D) -> (C + D) - x
    # C - (D - x) -> (C - D) + x
</pre>

I've tested them with my own compiler tools. Hope you will find them useful!