1
0
mirror of https://github.com/golang/go synced 2024-10-05 16:41:21 -06:00

[dev.ssa] cmd/compile: used Bounded field to fix empty range loops

for i, v := range a {
    }

Walk converts this to a regular for loop, like this:

    for i := 0, p := &a[0]; i < len(a); i++, p++ {
        v := *p
    }

Unfortunately, &a[0] fails its bounds check when a is
the empty slice (or string).  The old compiler gets around this
by marking &a[0] as Bounded, meaning "don't emit bounds checks
for this index op".  This change makes SSA honor that same mark.

The SSA compiler hasn't implemented bounds check panics yet,
so the failed bounds check just causes the current routine
to return immediately.

Fixes bytes package tests.

Change-Id: Ibe838853ef4046c92f76adbded8cca3b1e449e0b
Reviewed-on: https://go-review.googlesource.com/13685
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
This commit is contained in:
Keith Randall 2015-08-18 14:17:30 -07:00
parent 67cbd5b51d
commit 46e62f873a
2 changed files with 24 additions and 3 deletions

View File

@ -1313,7 +1313,9 @@ func (s *state) expr(n *Node) *ssa.Value {
len = s.constInt(Types[TINT], n.Left.Type.Bound)
elemtype = n.Left.Type.Type
}
s.boundsCheck(i, len)
if !n.Bounded {
s.boundsCheck(i, len)
}
return s.newValue2(ssa.OpArrayIndex, elemtype, a, i)
} else { // slice
p := s.addr(n)
@ -1530,7 +1532,9 @@ func (s *state) addr(n *Node) *ssa.Value {
i := s.expr(n.Right)
i = s.extendIndex(i)
len := s.newValue1(ssa.OpSliceLen, Types[TUINTPTR], a)
s.boundsCheck(i, len)
if !n.Bounded {
s.boundsCheck(i, len)
}
p := s.newValue1(ssa.OpSlicePtr, Ptrto(n.Left.Type.Type), a)
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), p, i)
} else { // array
@ -1538,7 +1542,9 @@ func (s *state) addr(n *Node) *ssa.Value {
i := s.expr(n.Right)
i = s.extendIndex(i)
len := s.constInt(Types[TINT], n.Left.Type.Bound)
s.boundsCheck(i, len)
if !n.Bounded {
s.boundsCheck(i, len)
}
return s.newValue2(ssa.OpPtrIndex, Ptrto(n.Left.Type.Type), a, i)
}
case OIND:

View File

@ -43,10 +43,25 @@ func testPhiControl() {
}
}
func emptyRange_ssa(b []byte) bool {
for _, x := range b {
_ = x
}
return true
}
func testEmptyRange() {
if !emptyRange_ssa([]byte{}) {
println("emptyRange_ssa([]byte{})=false, want true")
failed = true
}
}
var failed = false
func main() {
testPhiControl()
testEmptyRange()
if failed {
panic("failed")
}