cmd/compile: use unsigned loads for multi-element 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 <khr@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Ilya Tocar <ilya.tocar@intel.com>
This commit is contained in:
Keith Randall 2018-02-06 09:44:34 -08:00 committed by Keith Randall
parent 85bdd05c05
commit 23e8e197b0
3 changed files with 62 additions and 1 deletions

View file

@ -1002,6 +1002,20 @@ var linuxAMD64Tests = []*asmTest{
}`,
pos: []string{"\tCMPL\t[A-Z]"},
},
{
fn: `
func $(a,b [3]int16) bool {
return a == b
}`,
pos: []string{"\tCMPL\t[A-Z]"},
},
{
fn: `
func $(a,b [12]int8) bool {
return a == b
}`,
pos: []string{"\tCMPQ\t[A-Z]", "\tCMPL\t[A-Z]"},
},
{
fn: `
func f70(a,b [15]byte) bool {

View file

@ -3415,18 +3415,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)

View file

@ -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")
}
}