Skip to content

Commit

Permalink
cmd/compile: fix CSE with commutative ops
Browse files Browse the repository at this point in the history
CSE opportunities were being missed for commutative ops. We used to
order the args of commutative ops (by arg ID) once at the start of CSE.
But that may not be enough.

i1 = (Load ptr mem)
i2 = (Load ptr mem)
x1 = (Add i1 j)
x2 = (Add i2 j)

Equivalent commutative ops x1 and x2 may not get their args ordered in
the same way because because at the start of CSE, we don't know that
the i values will be CSEd. If x1 and x2 get opposite orders we won't
CSE them.

Instead, (re)order the args of commutative operations by their
equivalence class IDs each time we partition an equivalence class.

Change-Id: Ic609fa83b85299782a5e85bf93dc6023fccf4b0c
Reviewed-on: https://go-review.googlesource.com/33632
Run-TryBot: Keith Randall <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Todd Neal <todd@tneal.org>
  • Loading branch information
randall77 committed Feb 2, 2017
1 parent 34b563f commit 6317f92
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 5 deletions.
14 changes: 10 additions & 4 deletions src/cmd/compile/internal/ssa/cse.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,6 @@ func cse(f *Func) {
if v.Type.IsMemory() {
continue // memory values can never cse
}
if opcodeTable[v.Op].commutative && len(v.Args) == 2 && v.Args[1].ID < v.Args[0].ID {
// Order the arguments of binary commutative operations.
v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
}
a = append(a, v)
}
}
Expand Down Expand Up @@ -92,6 +88,15 @@ func cse(f *Func) {
for i := 0; i < len(partition); i++ {
e := partition[i]

if opcodeTable[e[0].Op].commutative {
// Order the first two args before comparison.
for _, v := range e {
if valueEqClass[v.Args[0].ID] > valueEqClass[v.Args[1].ID] {
v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
}
}
}

// Sort by eq class of arguments.
byArgClass.a = e
byArgClass.eqClass = valueEqClass
Expand All @@ -101,6 +106,7 @@ func cse(f *Func) {
splitPoints = append(splitPoints[:0], 0)
for j := 1; j < len(e); j++ {
v, w := e[j-1], e[j]
// Note: commutative args already correctly ordered by byArgClass.
eqArgs := true
for k, a := range v.Args {
b := w.Args[k]
Expand Down
15 changes: 14 additions & 1 deletion test/prove.go
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ func f11c(a []int, i int) {

func f11d(a []int, i int) {
useInt(a[2*i+7])
useInt(a[2*i+7])
useInt(a[2*i+7]) // ERROR "Proved boolean IsInBounds$"
}

func f12(a []int, b int) {
Expand Down Expand Up @@ -438,6 +438,19 @@ func f13i(a uint) int {
return 3
}

func f14(p, q *int, a []int) {
// This crazy ordering usually gives i1 the lowest value ID,
// j the middle value ID, and i2 the highest value ID.
// That used to confuse CSE because it ordered the args
// of the two + ops below differently.
// That in turn foiled bounds check elimination.
i1 := *p
j := *q
i2 := *p
useInt(a[i1+j])
useInt(a[i2+j]) // ERROR "Proved boolean IsInBounds$"
}

//go:noinline
func useInt(a int) {
}
Expand Down

4 comments on commit 6317f92

@navytux
Copy link
Contributor

@navytux navytux commented on 6317f92 Feb 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@randall77 I was rebasing https://go-review.googlesource.com/34635/ and noticed/bisected: this commit (6317f92) broke TestAssembly. TestAssembly is marked as slow and does not take part in regular all.bash runs so probably that's why it was not caught before. Details below:

go$ git checkout -b t 6317f92f~
go$ cd src/
go$ ./all.bash
...
ALL TESTS PASSED
go/src$ go test ./cmd/compile/internal/...
?       cmd/compile/internal/amd64      [no test files]
?       cmd/compile/internal/arm        [no test files]
?       cmd/compile/internal/arm64      [no test files]
ok      cmd/compile/internal/gc 9.422s
?       cmd/compile/internal/mips       [no test files]
?       cmd/compile/internal/mips64     [no test files]
?       cmd/compile/internal/ppc64      [no test files]
?       cmd/compile/internal/s390x      [no test files]
ok      cmd/compile/internal/ssa        0.079s
ok      cmd/compile/internal/syntax     2.502s
ok      cmd/compile/internal/test       0.002s [no tests to run]
?       cmd/compile/internal/x86        [no test files]

go/src$ git reset --hard 6317f92f
HEAD сейчас на 6317f92f6e cmd/compile: fix CSE with commutative ops
go$ ./all.bash
...
ALL TESTS PASSED
go/src$ go test ./cmd/compile/internal/...
?       cmd/compile/internal/amd64      [no test files]
?       cmd/compile/internal/arm        [no test files]
?       cmd/compile/internal/arm64      [no test files]
--- FAIL: TestAssembly (5.34s)
        asm_test.go:46: expected:       MOVQ    \(.*\)\(.*\*1\),
                go:
                import "encoding/binary"
                func f(b []byte, i int) uint64 {
                        return binary.LittleEndian.Uint64(b[i:])
                }

                asm:"".f t=1 size=186 args=0x28 locals=0x8
                        0x0000 00000 (/tmp/TestAssembly618200287/test.go:5)     TEXT    "".f(SB), $8-40
                        0x0000 00000 (/tmp/TestAssembly618200287/test.go:5)     SUBQ    $8, SP
                        0x0004 00004 (/tmp/TestAssembly618200287/test.go:5)     MOVQ    BP, (SP)
                        0x0008 00008 (/tmp/TestAssembly618200287/test.go:5)     LEAQ    (SP), BP
                        0x000c 00012 (/tmp/TestAssembly618200287/test.go:5)     FUNCDATA        $0, gclocals·6b4b7e46e7c3e785dae149c064ae0142(SB)
                        0x000c 00012 (/tmp/TestAssembly618200287/test.go:5)     FUNCDATA        $1, gclocals·69c1753bd5f81501d95132d08af04464(SB)
                        0x000c 00012 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    "".i+40(FP), AX
                        0x0011 00017 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    "".b+24(FP), CX
                        0x0016 00022 (/tmp/TestAssembly618200287/test.go:6)     CMPQ    AX, CX
                        0x0019 00025 (/tmp/TestAssembly618200287/test.go:6)     JHI     $0, 179
                        0x001f 00031 (/tmp/TestAssembly618200287/test.go:6)     SUBQ    AX, CX
                        0x0022 00034 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    "".b+32(FP), DX
                        0x0027 00039 (/tmp/TestAssembly618200287/test.go:6)     SUBQ    AX, DX
                        0x002a 00042 (/tmp/TestAssembly618200287/test.go:6)     DECQ    DX
                        0x002d 00045 (/tmp/TestAssembly618200287/test.go:6)     SARQ    $63, DX
                        0x0031 00049 (/tmp/TestAssembly618200287/test.go:6)     XORQ    $-1, DX
                        0x0035 00053 (/tmp/TestAssembly618200287/test.go:6)     ANDQ    DX, AX
                        0x0038 00056 (/tmp/TestAssembly618200287/test.go:6)     CMPQ    CX, $7
                        0x003c 00060 (/tmp/TestAssembly618200287/test.go:6)     JLS     $0, 172
                        0x003e 00062 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    "".b+16(FP), CX
                        0x0043 00067 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 2(CX)(AX*1), DX
                        0x0048 00072 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 3(CX)(AX*1), BX
                        0x004d 00077 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX (CX)(AX*1), SI
                        0x0051 00081 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 1(CX)(AX*1), DI
                        0x0056 00086 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 4(CX)(AX*1), R8
                        0x005c 00092 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 5(CX)(AX*1), R9
                        0x0062 00098 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 6(CX)(AX*1), R10
                        0x0068 00104 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 7(CX)(AX*1), AX
                        0x006d 00109 (/tmp/TestAssembly618200287/test.go:6)     SHLQ    $8, DI
                        0x0071 00113 (/tmp/TestAssembly618200287/test.go:6)     ORQ     SI, DI
                        0x0074 00116 (/tmp/TestAssembly618200287/test.go:6)     SHLQ    $16, DX
                        0x0078 00120 (/tmp/TestAssembly618200287/test.go:6)     ORQ     DI, DX
                        0x007b 00123 (/tmp/TestAssembly618200287/test.go:6)     SHLQ    $24, BX
                        0x007f 00127 (/tmp/TestAssembly618200287/test.go:6)     ORQ     DX, BX
                        0x0082 00130 (/tmp/TestAssembly618200287/test.go:6)     SHLQ    $32, R8
                        0x0086 00134 (/tmp/TestAssembly618200287/test.go:6)     ORQ     BX, R8
                        0x0089 00137 (/tmp/TestAssembly618200287/test.go:6)     SHLQ    $40, R9
                        0x008d 00141 (/tmp/TestAssembly618200287/test.go:6)     ORQ     R8, R9
                        0x0090 00144 (/tmp/TestAssembly618200287/test.go:6)     SHLQ    $48, R10
                        0x0094 00148 (/tmp/TestAssembly618200287/test.go:6)     ORQ     R9, R10
                        0x0097 00151 (/tmp/TestAssembly618200287/test.go:6)     SHLQ    $56, AX
                        0x009b 00155 (/tmp/TestAssembly618200287/test.go:6)     ORQ     R10, AX
                        0x009e 00158 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    AX, "".~r2+48(FP)
                        0x00a3 00163 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    (SP), BP
                        0x00a7 00167 (/tmp/TestAssembly618200287/test.go:6)     ADDQ    $8, SP
                        0x00ab 00171 (/tmp/TestAssembly618200287/test.go:6)     RET
                        0x00ac 00172 (/tmp/TestAssembly618200287/test.go:6)     PCDATA  $0, $1
                        0x00ac 00172 (/tmp/TestAssembly618200287/test.go:6)     CALL    runtime.panicindex(SB)
                        0x00b1 00177 (/tmp/TestAssembly618200287/test.go:6)     UNDEF
                        0x00b3 00179 (/tmp/TestAssembly618200287/test.go:6)     PCDATA  $0, $1
                        0x00b3 00179 (/tmp/TestAssembly618200287/test.go:6)     CALL    runtime.panicslice(SB)
                        0x00b8 00184 (/tmp/TestAssembly618200287/test.go:6)     UNDEF
                        0x0000 48 83 ec 08 48 89 2c 24 48 8d 2c 24 48 8b 44 24  H...H.,$H.,$H.D$
                        0x0010 28 48 8b 4c 24 18 48 39 c8 0f 87 94 00 00 00 48  (H.L$.H9.......H
                        0x0020 29 c1 48 8b 54 24 20 48 29 c2 48 ff ca 48 c1 fa  ).H.T$ H).H..H..
                        0x0030 3f 48 83 f2 ff 48 21 d0 48 83 f9 07 76 6e 48 8b  ?H...H!.H...vnH.
                        0x0040 4c 24 10 0f b6 54 01 02 0f b6 5c 01 03 0f b6 34  L$...T....\....4
                        0x0050 01 0f b6 7c 01 01 44 0f b6 44 01 04 44 0f b6 4c  ...|..D..D..D..L
                        0x0060 01 05 44 0f b6 54 01 06 0f b6 44 01 07 48 c1 e7  ..D..T....D..H..
                        0x0070 08 48 09 f7 48 c1 e2 10 48 09 fa 48 c1 e3 18 48  .H..H...H..H...H
                        0x0080 09 d3 49 c1 e0 20 49 09 d8 49 c1 e1 28 4d 09 c1  ..I.. I..I..(M..
                        0x0090 49 c1 e2 30 4d 09 ca 48 c1 e0 38 4c 09 d0 48 89  I..0M..H..8L..H.
                        0x00a0 44 24 30 48 8b 2c 24 48 83 c4 08 c3 e8 00 00 00  D$0H.,$H........
                        0x00b0 00 0f 0b e8 00 00 00 00 0f 0b                    ..........
                        rel 173+4 t=8 runtime.panicindex+0
                        rel 180+4 t=8 runtime.panicslice+0

        asm_test.go:46: expected:       MOVL    \(.*\),
                go:
                import "encoding/binary"
                func f(b []byte) uint32 {
                        return binary.LittleEndian.Uint32(b)
                }

                asm:"".f t=1 size=78 args=0x20 locals=0x8
                        0x0000 00000 (/tmp/TestAssembly618200287/test.go:5)     TEXT    "".f(SB), $8-32
                        0x0000 00000 (/tmp/TestAssembly618200287/test.go:5)     SUBQ    $8, SP
                        0x0004 00004 (/tmp/TestAssembly618200287/test.go:5)     MOVQ    BP, (SP)
                        0x0008 00008 (/tmp/TestAssembly618200287/test.go:5)     LEAQ    (SP), BP
                        0x000c 00012 (/tmp/TestAssembly618200287/test.go:5)     FUNCDATA        $0, gclocals·4032f753396f2012ad1784f398b170f4(SB)
                        0x000c 00012 (/tmp/TestAssembly618200287/test.go:5)     FUNCDATA        $1, gclocals·69c1753bd5f81501d95132d08af04464(SB)
                        0x000c 00012 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    "".b+24(FP), AX
                        0x0011 00017 (/tmp/TestAssembly618200287/test.go:6)     CMPQ    AX, $3
                        0x0015 00021 (/tmp/TestAssembly618200287/test.go:6)     JLS     $0, 71
                        0x0017 00023 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    "".b+16(FP), AX
                        0x001c 00028 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 2(AX), CX
                        0x0020 00032 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 3(AX), DX
                        0x0024 00036 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX (AX), BX
                        0x0027 00039 (/tmp/TestAssembly618200287/test.go:6)     MOVBLZX 1(AX), AX
                        0x002b 00043 (/tmp/TestAssembly618200287/test.go:6)     SHLL    $8, AX
                        0x002e 00046 (/tmp/TestAssembly618200287/test.go:6)     ORL     AX, BX
                        0x0030 00048 (/tmp/TestAssembly618200287/test.go:6)     SHLL    $16, CX
                        0x0033 00051 (/tmp/TestAssembly618200287/test.go:6)     ORL     BX, CX
                        0x0035 00053 (/tmp/TestAssembly618200287/test.go:6)     SHLL    $24, DX
                        0x0038 00056 (/tmp/TestAssembly618200287/test.go:6)     ORL     CX, DX
                        0x003a 00058 (/tmp/TestAssembly618200287/test.go:6)     MOVL    DX, "".~r1+40(FP)
                        0x003e 00062 (/tmp/TestAssembly618200287/test.go:6)     MOVQ    (SP), BP
                        0x0042 00066 (/tmp/TestAssembly618200287/test.go:6)     ADDQ    $8, SP
                        0x0046 00070 (/tmp/TestAssembly618200287/test.go:6)     RET
                        0x0047 00071 (/tmp/TestAssembly618200287/test.go:6)     PCDATA  $0, $1
                        0x0047 00071 (/tmp/TestAssembly618200287/test.go:6)     CALL    runtime.panicindex(SB)
                        0x004c 00076 (/tmp/TestAssembly618200287/test.go:6)     UNDEF
                        0x0000 48 83 ec 08 48 89 2c 24 48 8d 2c 24 48 8b 44 24  H...H.,$H.,$H.D$
                        0x0010 18 48 83 f8 03 76 30 48 8b 44 24 10 0f b6 48 02  .H...v0H.D$...H.
                        0x0020 0f b6 50 03 0f b6 18 0f b6 40 01 c1 e0 08 09 c3  ..P......@......
                        0x0030 c1 e1 10 09 d9 c1 e2 18 09 ca 89 54 24 28 48 8b  ...........T$(H.
                        0x0040 2c 24 48 83 c4 08 c3 e8 00 00 00 00 0f 0b        ,$H...........
                        rel 72+4 t=8 runtime.panicindex+0

(and other failures)

thanks beforehand for feedback,
Kirill

/cc @TocarIP, @rasky

@TocarIP
Copy link
Contributor

@TocarIP TocarIP commented on 6317f92 Feb 7, 2017

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest creating an issue in https://github.com/golang/go/issues
Edit:
There is #18946

@randall77
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@navytux should be fixed now.

@navytux
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@randall77, yes, thanks for feedback.

Please sign in to comment.