Skip to content

Commit

Permalink
[release-branch.go1.9] cmd/compile: use unsigned loads for multi-elem…
Browse files Browse the repository at this point in the history
…ent comparisons

When loading multiple elements of an array into a single register,
make sure we treat them as unsigned.  When treated as signed, the
upper bits might all be set, causing the shift-or combo to clobber
the values higher in the register.

Fixes #23719.

Change-Id: Ic87da03e9bd0fe2c60bb214b99f846e4e9446052
Reviewed-on: https://go-review.googlesource.com/92335
Run-TryBot: Keith Randall <[email protected]>
TryBot-Result: Gobot Gobot <[email protected]>
Reviewed-by: Ilya Tocar <[email protected]>
Reviewed-on: https://go-review.googlesource.com/103115
Run-TryBot: Andrew Bonventre <[email protected]>
Reviewed-by: Keith Randall <[email protected]>
  • Loading branch information
randall77 authored and andybons committed Mar 29, 2018
1 parent 9c69ed5 commit f5c8db9
Show file tree
Hide file tree
Showing 3 changed files with 62 additions and 1 deletion.
14 changes: 14 additions & 0 deletions src/cmd/compile/internal/gc/asm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -909,6 +909,20 @@ var linuxAMD64Tests = []*asmTest{
`,
[]string{"b\\+40\\(SP\\)"},
},
{
`
func f73(a,b [3]int16) bool {
return a == b
}`,
[]string{"\tCMPL\t[A-Z]"},
},
{
`
func f74(a,b [12]int8) bool {
return a == b
}`,
[]string{"\tCMPQ\t[A-Z]", "\tCMPL\t[A-Z]"},
},
}

var linux386Tests = []*asmTest{
Expand Down
7 changes: 6 additions & 1 deletion src/cmd/compile/internal/gc/walk.go
Original file line number Diff line number Diff line change
Expand Up @@ -3390,18 +3390,23 @@ func walkcompare(n *Node, init *Nodes) *Node {
i++
remains -= t.Elem().Width
} else {
elemType := t.Elem().ToUnsigned()
cmplw := nod(OINDEX, cmpl, nodintconst(int64(i)))
cmplw = conv(cmplw, convType)
cmplw = conv(cmplw, elemType) // convert to unsigned
cmplw = conv(cmplw, convType) // widen
cmprw := nod(OINDEX, cmpr, nodintconst(int64(i)))
cmprw = conv(cmprw, elemType)
cmprw = conv(cmprw, convType)
// For code like this: uint32(s[0]) | uint32(s[1])<<8 | uint32(s[2])<<16 ...
// ssa will generate a single large load.
for offset := int64(1); offset < step; offset++ {
lb := nod(OINDEX, cmpl, nodintconst(int64(i+offset)))
lb = conv(lb, elemType)
lb = conv(lb, convType)
lb = nod(OLSH, lb, nodintconst(int64(8*t.Elem().Width*offset)))
cmplw = nod(OOR, cmplw, lb)
rb := nod(OINDEX, cmpr, nodintconst(int64(i+offset)))
rb = conv(rb, elemType)
rb = conv(rb, convType)
rb = nod(OLSH, rb, nodintconst(int64(8*t.Elem().Width*offset)))
cmprw = nod(OOR, cmprw, rb)
Expand Down
42 changes: 42 additions & 0 deletions test/fixedbugs/issue23719.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
// run

// Copyright 2018 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 main

func main() {
v1 := [2]int32{-1, 88}
v2 := [2]int32{-1, 99}
if v1 == v2 {
panic("bad comparison")
}

w1 := [2]int16{-1, 88}
w2 := [2]int16{-1, 99}
if w1 == w2 {
panic("bad comparison")
}
x1 := [4]int16{-1, 88, 88, 88}
x2 := [4]int16{-1, 99, 99, 99}
if x1 == x2 {
panic("bad comparison")
}

a1 := [2]int8{-1, 88}
a2 := [2]int8{-1, 99}
if a1 == a2 {
panic("bad comparison")
}
b1 := [4]int8{-1, 88, 88, 88}
b2 := [4]int8{-1, 99, 99, 99}
if b1 == b2 {
panic("bad comparison")
}
c1 := [8]int8{-1, 88, 88, 88, 88, 88, 88, 88}
c2 := [8]int8{-1, 99, 99, 99, 99, 99, 99, 99}
if c1 == c2 {
panic("bad comparison")
}
}

0 comments on commit f5c8db9

Please sign in to comment.