cmd/compile: fix sign-extension merging rules

If we have

  y = <int16> (MOVBQSX x)
  z = <int32> (MOVWQSX y)

We used to use this rewrite rule:

(MOVWQSX x:(MOVBQSX _)) -> x

But that resulted in replacing z with a value whose type
is only int16.  Then if z is spilled and restored, it gets
zero extended instead of sign extended.

Instead use the rule

(MOVWQSX (MOVBQSX x)) -> (MOVBQSX x)

The result is has the correct type, so it can be spilled
and restored correctly.  It might mean that a few more extension
ops might not be eliminated, but that's the price for correctness.

Fixes #21963

Change-Id: I6ec82c3d2dbe43cc1fee6fb2bd6b3a72fca3af00
Reviewed-on: https://go-review.googlesource.com/65290
Reviewed-by: Cherry Zhang <cherryyz@google.com>
Run-TryBot: Cherry Zhang <cherryyz@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
Keith Randall 2017-09-21 12:52:38 -07:00
parent 08a1796671
commit 3f04db41a8
3 changed files with 113 additions and 84 deletions

View file

@ -2512,18 +2512,20 @@
(BSFQ (ORQconst <t> [1<<16] (MOVWQZX x))) -> (BSFQ (ORQconst <t> [1<<16] x))
// Redundant sign/zero extensions
(MOVLQSX x:(MOVLQSX _)) -> x
(MOVLQSX x:(MOVWQSX _)) -> x
(MOVLQSX x:(MOVBQSX _)) -> x
(MOVWQSX x:(MOVWQSX _)) -> x
(MOVWQSX x:(MOVBQSX _)) -> x
(MOVBQSX x:(MOVBQSX _)) -> x
(MOVLQZX x:(MOVLQZX _)) -> x
(MOVLQZX x:(MOVWQZX _)) -> x
(MOVLQZX x:(MOVBQZX _)) -> x
(MOVWQZX x:(MOVWQZX _)) -> x
(MOVWQZX x:(MOVBQZX _)) -> x
(MOVBQZX x:(MOVBQZX _)) -> x
// Note: see issue 21963. We have to make sure we use the right type on
// the resulting extension (the outer type, not the inner type).
(MOVLQSX (MOVLQSX x)) -> (MOVLQSX x)
(MOVLQSX (MOVWQSX x)) -> (MOVWQSX x)
(MOVLQSX (MOVBQSX x)) -> (MOVBQSX x)
(MOVWQSX (MOVWQSX x)) -> (MOVWQSX x)
(MOVWQSX (MOVBQSX x)) -> (MOVBQSX x)
(MOVBQSX (MOVBQSX x)) -> (MOVBQSX x)
(MOVLQZX (MOVLQZX x)) -> (MOVLQZX x)
(MOVLQZX (MOVWQZX x)) -> (MOVWQZX x)
(MOVLQZX (MOVBQZX x)) -> (MOVBQZX x)
(MOVWQZX (MOVWQZX x)) -> (MOVWQZX x)
(MOVWQZX (MOVBQZX x)) -> (MOVBQZX x)
(MOVBQZX (MOVBQZX x)) -> (MOVBQZX x)
(MOVQstore [off] {sym} ptr a:(ADDQconst [c] l:(MOVQload [off] {sym} ptr2 mem)) mem)
&& isSamePtr(ptr, ptr2) && a.Uses == 1 && l.Uses == 1 && validValAndOff(c,off) ->

View file

@ -4671,16 +4671,16 @@ func rewriteValueAMD64_OpAMD64MOVBQSX_0(v *Value) bool {
v.AddArg(x)
return true
}
// match: (MOVBQSX x:(MOVBQSX _))
// match: (MOVBQSX (MOVBQSX x))
// cond:
// result: x
// result: (MOVBQSX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVBQSX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVBQSX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVBQSX)
v.AddArg(x)
return true
}
@ -4888,16 +4888,16 @@ func rewriteValueAMD64_OpAMD64MOVBQZX_0(v *Value) bool {
v.AddArg(x)
return true
}
// match: (MOVBQZX x:(MOVBQZX _))
// match: (MOVBQZX (MOVBQZX x))
// cond:
// result: x
// result: (MOVBQZX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVBQZX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVBQZX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVBQZX)
v.AddArg(x)
return true
}
@ -6815,42 +6815,42 @@ func rewriteValueAMD64_OpAMD64MOVLQSX_0(v *Value) bool {
v.AddArg(x)
return true
}
// match: (MOVLQSX x:(MOVLQSX _))
// match: (MOVLQSX (MOVLQSX x))
// cond:
// result: x
// result: (MOVLQSX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVLQSX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVLQSX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVLQSX)
v.AddArg(x)
return true
}
// match: (MOVLQSX x:(MOVWQSX _))
// match: (MOVLQSX (MOVWQSX x))
// cond:
// result: x
// result: (MOVWQSX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVWQSX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVWQSX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVWQSX)
v.AddArg(x)
return true
}
// match: (MOVLQSX x:(MOVBQSX _))
// match: (MOVLQSX (MOVBQSX x))
// cond:
// result: x
// result: (MOVBQSX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVBQSX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVBQSX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVBQSX)
v.AddArg(x)
return true
}
@ -7047,42 +7047,42 @@ func rewriteValueAMD64_OpAMD64MOVLQZX_0(v *Value) bool {
v.AddArg(x)
return true
}
// match: (MOVLQZX x:(MOVLQZX _))
// match: (MOVLQZX (MOVLQZX x))
// cond:
// result: x
// result: (MOVLQZX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVLQZX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVLQZX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVLQZX)
v.AddArg(x)
return true
}
// match: (MOVLQZX x:(MOVWQZX _))
// match: (MOVLQZX (MOVWQZX x))
// cond:
// result: x
// result: (MOVWQZX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVWQZX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVWQZX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVWQZX)
v.AddArg(x)
return true
}
// match: (MOVLQZX x:(MOVBQZX _))
// match: (MOVLQZX (MOVBQZX x))
// cond:
// result: x
// result: (MOVBQZX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVBQZX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVBQZX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVBQZX)
v.AddArg(x)
return true
}
@ -12005,29 +12005,29 @@ func rewriteValueAMD64_OpAMD64MOVWQSX_0(v *Value) bool {
v.AddArg(x)
return true
}
// match: (MOVWQSX x:(MOVWQSX _))
// match: (MOVWQSX (MOVWQSX x))
// cond:
// result: x
// result: (MOVWQSX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVWQSX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVWQSX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVWQSX)
v.AddArg(x)
return true
}
// match: (MOVWQSX x:(MOVBQSX _))
// match: (MOVWQSX (MOVBQSX x))
// cond:
// result: x
// result: (MOVBQSX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVBQSX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVBQSX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVBQSX)
v.AddArg(x)
return true
}
@ -12237,29 +12237,29 @@ func rewriteValueAMD64_OpAMD64MOVWQZX_0(v *Value) bool {
v.AddArg(x)
return true
}
// match: (MOVWQZX x:(MOVWQZX _))
// match: (MOVWQZX (MOVWQZX x))
// cond:
// result: x
// result: (MOVWQZX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVWQZX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVWQZX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVWQZX)
v.AddArg(x)
return true
}
// match: (MOVWQZX x:(MOVBQZX _))
// match: (MOVWQZX (MOVBQZX x))
// cond:
// result: x
// result: (MOVBQZX x)
for {
x := v.Args[0]
if x.Op != OpAMD64MOVBQZX {
v_0 := v.Args[0]
if v_0.Op != OpAMD64MOVBQZX {
break
}
v.reset(OpCopy)
v.Type = x.Type
x := v_0.Args[0]
v.reset(OpAMD64MOVBQZX)
v.AddArg(x)
return true
}

View file

@ -0,0 +1,27 @@
// run
// Copyright 2017 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
import (
"fmt"
"runtime"
)
//go:noinline
func f(x []int32, y *int8) int32 {
c := int32(int16(*y))
runtime.GC()
return x[0] * c
}
func main() {
var x = [1]int32{5}
var y int8 = -1
if got, want := f(x[:], &y), int32(-5); got != want {
panic(fmt.Sprintf("wanted %d, got %d", want, got))
}
}