mirror of
https://github.com/golang/go.git
synced 2026-06-27 19:30:52 +00:00
cmd/compile: teach deadstore about moves
Moves that read from read-only memory can't be reading the results of a previous store. These are often generated by constant struct literals. Moves whose results aren't needed because that memory is immediately overwritten, are not needed. Saves a few bytes of generated code (~<0.1%). Change-Id: I8dab6d1b9c066d6b623eae8b8fe31a51dd3de006 Reviewed-on: https://go-review.googlesource.com/c/go/+/771780 LUCI-TryBot-Result: golang-scoped@luci-project-accounts.iam.gserviceaccount.com <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Reviewed-by: Keith Randall <khr@google.com> Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com> Reviewed-by: Jakub Ciolek <jakub@ciolek.dev> Reviewed-by: David Chase <drchase@google.com>
This commit is contained in:
parent
4aa6dad54e
commit
da6a4cd70a
2 changed files with 48 additions and 7 deletions
|
|
@ -50,7 +50,18 @@ func dse(f *Func) {
|
|||
for _, a := range v.Args {
|
||||
if a.Block == b && a.Type.IsMemory() {
|
||||
storeUse.add(a.ID)
|
||||
if v.Op != OpStore && v.Op != OpZero && v.Op != OpVarDef {
|
||||
switch v.Op {
|
||||
case OpStore, OpZero, OpVarDef:
|
||||
// These ops never read from their memory input.
|
||||
case OpMove:
|
||||
// This op reads from its memory argument, but
|
||||
// we can treat it as not doing so if we know
|
||||
// the read is from read-only memory.
|
||||
if v.Args[1].Op == OpAddr && symIsRO(auxToSym(v.Args[1].Aux)) {
|
||||
break
|
||||
}
|
||||
fallthrough
|
||||
default:
|
||||
// CALL, DUFFCOPY, etc. are both
|
||||
// reads and writes.
|
||||
loadUse.add(a.ID)
|
||||
|
|
@ -111,7 +122,7 @@ func dse(f *Func) {
|
|||
shadowed.clear()
|
||||
shadowedRanges = shadowedRanges[:0]
|
||||
}
|
||||
if v.Op == OpStore || v.Op == OpZero {
|
||||
if v.Op == OpStore || v.Op == OpZero || v.Op == OpMove {
|
||||
ptr := v.Args[0]
|
||||
var off int64
|
||||
for ptr.Op == OpOffPtr { // Walk to base pointer
|
||||
|
|
@ -119,7 +130,7 @@ func dse(f *Func) {
|
|||
ptr = ptr.Args[0]
|
||||
}
|
||||
var sz int64
|
||||
if v.Op == OpStore {
|
||||
if v.Op == OpStore || v.Op == OpMove {
|
||||
sz = v.Aux.(*types.Type).Size()
|
||||
} else { // OpZero
|
||||
sz = v.AuxInt
|
||||
|
|
@ -137,13 +148,14 @@ func dse(f *Func) {
|
|||
}
|
||||
|
||||
if si != nil && si.contains(off, off+sz) {
|
||||
// Modify the store/zero into a copy of the memory state,
|
||||
// Modify the store/zero/move into a copy of the memory state,
|
||||
// effectively eliding the store operation.
|
||||
if v.Op == OpStore {
|
||||
// store addr value mem
|
||||
if v.Op == OpStore || v.Op == OpMove {
|
||||
// Store addr value mem
|
||||
// or Move dst src mem
|
||||
v.SetArgs1(v.Args[2])
|
||||
} else {
|
||||
// zero addr mem
|
||||
// Zero addr mem
|
||||
v.SetArgs1(v.Args[1])
|
||||
}
|
||||
v.Aux = nil
|
||||
|
|
|
|||
29
test/codegen/deadstore.go
Normal file
29
test/codegen/deadstore.go
Normal file
|
|
@ -0,0 +1,29 @@
|
|||
// asmcheck
|
||||
|
||||
// Copyright 2026 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 codegen
|
||||
|
||||
type S struct {
|
||||
a, b, c, d, e int
|
||||
}
|
||||
|
||||
func f1(s *S) {
|
||||
// amd64:-`MOVUPS`
|
||||
// arm64:-`STP` -`MOVD`
|
||||
*s = S{}
|
||||
*s = S{a: 3, b: 4, c: 5, d: 6, e: 7}
|
||||
}
|
||||
|
||||
func f2(s *S) {
|
||||
// amd64:-`MOVUPS`
|
||||
// arm64:-`MOVD` -`FSTPQ`
|
||||
*s = S{a: 1, b: 2, c: 3, d: 4, e: 5}
|
||||
s.a = 3
|
||||
s.b = 4
|
||||
s.c = 5
|
||||
s.d = 6
|
||||
s.e = 7
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue