]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: correct sparseSet probes in regalloc to avoid index error
authorDavid Chase <drchase@google.com>
Sat, 7 May 2016 00:05:02 +0000 (17:05 -0700)
committerDavid Chase <drchase@google.com>
Mon, 9 May 2016 18:35:44 +0000 (18:35 +0000)
In regalloc, a sparse map is preallocated for later use by
spill-in-loop sinking.  However, variables (spills) are added
during register allocation before spill sinking, and a map
query involving any of these new variables will index out of
bounds in the map.

To fix:
1) fix the queries to use s.orig[v.ID].ID instead, to ensure
proper indexing.  Note that s.orig will be nil for values
that are not eligible for spilling (like memory and flags).

2) add a test.

Fixes #15585.

Change-Id: I8f2caa93b132a0f2a9161d2178320d5550583075
Reviewed-on: https://go-review.googlesource.com/22911
Reviewed-by: Keith Randall <khr@golang.org>
Run-TryBot: David Chase <drchase@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>

src/cmd/compile/internal/ssa/regalloc.go
test/fixedbugs/issue15585.go [new file with mode: 0644]

index 1b12c6f300cee323a9fc7290ad88861df456de02..6c391aba2994bc1af4ee9addf43d5734023080d2 100644 (file)
@@ -1311,20 +1311,25 @@ func (s *regAllocState) regalloc(f *Func) {
                                                // Start with live at end.
                                                for _, li := range s.live[ss.ID] {
                                                        if s.isLoopSpillCandidate(loop, s.orig[li.ID]) {
+                                                               // s.live contains original IDs, use s.orig above to map back to *Value
                                                                entryCandidates.setBit(li.ID, uint(whichExit))
                                                        }
                                                }
                                                // Control can also be live.
-                                               if ss.Control != nil && s.isLoopSpillCandidate(loop, ss.Control) {
-                                                       entryCandidates.setBit(ss.Control.ID, uint(whichExit))
+                                               if ss.Control != nil && s.orig[ss.Control.ID] != nil && s.isLoopSpillCandidate(loop, s.orig[ss.Control.ID]) {
+                                                       entryCandidates.setBit(s.orig[ss.Control.ID].ID, uint(whichExit))
                                                }
                                                // Walk backwards, filling in locally live values, removing those defined.
                                                for i := len(ss.Values) - 1; i >= 0; i-- {
                                                        v := ss.Values[i]
-                                                       entryCandidates.remove(v.ID) // Cannot be an issue, only keeps the sets smaller.
+                                                       vorig := s.orig[v.ID]
+                                                       if vorig != nil {
+                                                               entryCandidates.remove(vorig.ID) // Cannot be an issue, only keeps the sets smaller.
+                                                       }
                                                        for _, a := range v.Args {
-                                                               if s.isLoopSpillCandidate(loop, a) {
-                                                                       entryCandidates.setBit(a.ID, uint(whichExit))
+                                                               aorig := s.orig[a.ID]
+                                                               if aorig != nil && s.isLoopSpillCandidate(loop, aorig) {
+                                                                       entryCandidates.setBit(aorig.ID, uint(whichExit))
                                                                }
                                                        }
                                                }
diff --git a/test/fixedbugs/issue15585.go b/test/fixedbugs/issue15585.go
new file mode 100644 (file)
index 0000000..79eb13f
--- /dev/null
@@ -0,0 +1,45 @@
+// compile
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bug
+
+func example(n int) (rc int) {
+       var cc, ll, pp, rr [27]int
+       for q0 := 0; q0 < n-2; q0++ {
+               for q1 := q0 + 2; q1 < n; q1++ {
+                       var c, d, l, p, r int
+                       b0 := 1 << uint(q0)
+                       b1 := 1 << uint(q1)
+                       l = ((b0 << 1) | b1) << 1
+                       c = b0 | b1 | (-1 << uint(n))
+                       r = ((b0 >> 1) | b1) >> 1
+               E:
+                       if c != -1 {
+                               p = ^(l | c | r)
+                       } else {
+                               rc++
+                               goto R
+                       }
+               L:
+                       if p != 0 {
+                               lsb := p & -p
+                               p &^= lsb
+                               ll[d], cc[d], rr[d], pp[d] = l, c, r, p
+                               l, c, r = (l|lsb)<<1, c|lsb, (r|lsb)>>1
+                               d++
+                               goto E
+                       }
+               R:
+                       d--
+                       if d >= 0 {
+                               l, c, r, p = ll[d], cc[d], rr[d], pp[d]
+                               goto L
+                       }
+               }
+       }
+       rc <<= 1
+       return
+}