mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
[dev.simd] cmd/compile: remove stores to unread parameters
Currently, we remove stores to local variables that are not read. We don't do that for arguments. But arguments and locals are essentially the same. Arguments are passed by value, and are not expected to be read in the caller's frame. So we can remove the writes to them as well. One exception is the cgo_unsafe_arg directive, which makes all the arguments effectively address-taken. cgo_unsafe_arg implies ABI0, so we just skip ABI0 functions' arguments. Change-Id: I8999fc50da6a87f22c1ec23e9a0c15483b6f7df8 Reviewed-on: https://go-review.googlesource.com/c/go/+/705815 LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Junyang Shao <shaojunyang@google.com>
This commit is contained in:
parent
2d8cb80d7c
commit
2b50ffe172
3 changed files with 26 additions and 4 deletions
|
|
@ -7,6 +7,7 @@ package ssa
|
||||||
import (
|
import (
|
||||||
"cmd/compile/internal/ir"
|
"cmd/compile/internal/ir"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
|
"cmd/internal/obj"
|
||||||
)
|
)
|
||||||
|
|
||||||
// dse does dead-store elimination on the Function.
|
// dse does dead-store elimination on the Function.
|
||||||
|
|
@ -213,7 +214,7 @@ func elimDeadAutosGeneric(f *Func) {
|
||||||
case OpAddr, OpLocalAddr:
|
case OpAddr, OpLocalAddr:
|
||||||
// Propagate the address if it points to an auto.
|
// Propagate the address if it points to an auto.
|
||||||
n, ok := v.Aux.(*ir.Name)
|
n, ok := v.Aux.(*ir.Name)
|
||||||
if !ok || n.Class != ir.PAUTO {
|
if !ok || (n.Class != ir.PAUTO && !isABIInternalParam(f, n)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if addr[v] == nil {
|
if addr[v] == nil {
|
||||||
|
|
@ -224,7 +225,7 @@ func elimDeadAutosGeneric(f *Func) {
|
||||||
case OpVarDef:
|
case OpVarDef:
|
||||||
// v should be eliminated if we eliminate the auto.
|
// v should be eliminated if we eliminate the auto.
|
||||||
n, ok := v.Aux.(*ir.Name)
|
n, ok := v.Aux.(*ir.Name)
|
||||||
if !ok || n.Class != ir.PAUTO {
|
if !ok || (n.Class != ir.PAUTO && !isABIInternalParam(f, n)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if elim[v] == nil {
|
if elim[v] == nil {
|
||||||
|
|
@ -240,7 +241,7 @@ func elimDeadAutosGeneric(f *Func) {
|
||||||
// may not be used by the inline code, but will be used by
|
// may not be used by the inline code, but will be used by
|
||||||
// panic processing).
|
// panic processing).
|
||||||
n, ok := v.Aux.(*ir.Name)
|
n, ok := v.Aux.(*ir.Name)
|
||||||
if !ok || n.Class != ir.PAUTO {
|
if !ok || (n.Class != ir.PAUTO && !isABIInternalParam(f, n)) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
if !used.Has(n) {
|
if !used.Has(n) {
|
||||||
|
|
@ -373,7 +374,7 @@ func elimUnreadAutos(f *Func) {
|
||||||
if !ok {
|
if !ok {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if n.Class != ir.PAUTO {
|
if n.Class != ir.PAUTO && !isABIInternalParam(f, n) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -413,3 +414,16 @@ func elimUnreadAutos(f *Func) {
|
||||||
store.Op = OpCopy
|
store.Op = OpCopy
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// isABIInternalParam returns whether n is a parameter of an ABIInternal
|
||||||
|
// function. For dead store elimination, we can treat parameters the same
|
||||||
|
// way as autos. Storing to a parameter can be removed if it is not read
|
||||||
|
// or address-taken.
|
||||||
|
//
|
||||||
|
// We check ABI here because for a cgo_unsafe_arg function (which is ABI0),
|
||||||
|
// all the args are effectively address-taken, but not necessarily have
|
||||||
|
// an Addr or LocalAddr op. We could probably just check for cgo_unsafe_arg,
|
||||||
|
// but ABIInternal is mostly what matters.
|
||||||
|
func isABIInternalParam(f *Func, n *ir.Name) bool {
|
||||||
|
return n.Class == ir.PPARAM && f.ABISelf.Which() == obj.ABIInternal
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,6 +44,8 @@ func badLR2(arg int) {
|
||||||
lrPtr := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&arg)) - lrOff))
|
lrPtr := (*uintptr)(unsafe.Pointer(uintptr(unsafe.Pointer(&arg)) - lrOff))
|
||||||
*lrPtr = 0xbad
|
*lrPtr = 0xbad
|
||||||
|
|
||||||
|
runtime.KeepAlive(lrPtr) // prevent dead store elimination
|
||||||
|
|
||||||
// Print a backtrace. This should include diagnostics for the
|
// Print a backtrace. This should include diagnostics for the
|
||||||
// bad return PC and a hex dump.
|
// bad return PC and a hex dump.
|
||||||
panic("backtrace")
|
panic("backtrace")
|
||||||
|
|
|
||||||
|
|
@ -168,3 +168,9 @@ func getp1() *[4]int {
|
||||||
func getp2() *[4]int {
|
func getp2() *[4]int {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Store to an argument without read can be removed.
|
||||||
|
func storeArg(a [2]int) {
|
||||||
|
// amd64:-`MOVQ\t\$123,.*\.a\+\d+\(SP\)`
|
||||||
|
a[1] = 123
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue