mirror of
https://github.com/golang/go
synced 2024-11-17 16:04:47 -07:00
cmd/compile: rip out support for OpVarKill from ssa backend
Change-Id: I008479a7516d8379186ce630748e503d94d3b1e8 Reviewed-on: https://go-review.googlesource.com/c/go/+/419235 Reviewed-by: David Chase <drchase@google.com> Reviewed-by: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org> Run-TryBot: Keith Randall <khr@golang.org>
This commit is contained in:
parent
908499adec
commit
6dc7b060cd
@ -249,7 +249,7 @@ func (lv *argLiveness) valueEffect(v *ssa.Value, live bitvec.BitVec) bool {
|
||||
func mayFault(v *ssa.Value) bool {
|
||||
switch v.Op {
|
||||
case ssa.OpLoadReg, ssa.OpStoreReg, ssa.OpCopy, ssa.OpPhi,
|
||||
ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive,
|
||||
ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive,
|
||||
ssa.OpSelect0, ssa.OpSelect1, ssa.OpSelectN, ssa.OpMakeResult,
|
||||
ssa.OpConvert, ssa.OpInlMark, ssa.OpGetG:
|
||||
return false
|
||||
|
@ -80,15 +80,6 @@ import (
|
||||
// the liveness analysis work on single-word values as well, although
|
||||
// there are complications around interface values, slices, and strings,
|
||||
// all of which cannot be treated as individual words.
|
||||
//
|
||||
// OpVarKill is the opposite of OpVarDef: it marks a value as no longer needed,
|
||||
// even if its address has been taken. That is, an OpVarKill annotation asserts
|
||||
// that its argument is certainly dead, for use when the liveness analysis
|
||||
// would not otherwise be able to deduce that fact.
|
||||
|
||||
// TODO: get rid of OpVarKill here. It's useful for stack frame allocation
|
||||
// so the compiler can allocate two temps to the same location. Here it's now
|
||||
// useless, since the implementation of stack objects.
|
||||
|
||||
// blockEffects summarizes the liveness effects on an SSA block.
|
||||
type blockEffects struct {
|
||||
@ -269,7 +260,7 @@ func (lv *liveness) valueEffects(v *ssa.Value) (int32, liveEffect) {
|
||||
// OpVarFoo pseudo-ops. Ignore them to prevent "lost track of
|
||||
// variable" ICEs (issue 19632).
|
||||
switch v.Op {
|
||||
case ssa.OpVarDef, ssa.OpVarKill, ssa.OpVarLive, ssa.OpKeepAlive:
|
||||
case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive:
|
||||
if !n.Used() {
|
||||
return -1, 0
|
||||
}
|
||||
@ -334,7 +325,7 @@ func affectedVar(v *ssa.Value) (*ir.Name, ssa.SymEffect) {
|
||||
|
||||
case ssa.OpVarLive:
|
||||
return v.Aux.(*ir.Name), ssa.SymRead
|
||||
case ssa.OpVarDef, ssa.OpVarKill:
|
||||
case ssa.OpVarDef:
|
||||
return v.Aux.(*ir.Name), ssa.SymWrite
|
||||
case ssa.OpKeepAlive:
|
||||
n, _ := ssa.AutoVar(v.Args[0])
|
||||
|
@ -39,7 +39,7 @@ 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 && v.Op != OpVarKill {
|
||||
if v.Op != OpStore && v.Op != OpZero && v.Op != OpVarDef {
|
||||
// CALL, DUFFCOPY, etc. are both
|
||||
// reads and writes.
|
||||
loadUse.add(a.ID)
|
||||
@ -156,7 +156,7 @@ func elimDeadAutosGeneric(f *Func) {
|
||||
changed = true
|
||||
}
|
||||
return
|
||||
case OpVarDef, OpVarKill:
|
||||
case OpVarDef:
|
||||
// v should be eliminated if we eliminate the auto.
|
||||
n, ok := v.Aux.(*ir.Name)
|
||||
if !ok || n.Class != ir.PAUTO {
|
||||
|
@ -613,7 +613,7 @@ func BuildFuncDebug(ctxt *obj.Link, f *Func, loggingLevel int, stackOffset func(
|
||||
// This would probably be better as an output from stackframe.
|
||||
for _, b := range f.Blocks {
|
||||
for _, v := range b.Values {
|
||||
if v.Op == OpVarDef || v.Op == OpVarKill {
|
||||
if v.Op == OpVarDef {
|
||||
n := v.Aux.(*ir.Name)
|
||||
if ir.IsSynthetic(n) {
|
||||
continue
|
||||
@ -1080,7 +1080,7 @@ func (state *debugState) processValue(v *Value, vSlots []SlotID, vReg *Register)
|
||||
}
|
||||
|
||||
switch {
|
||||
case v.Op == OpVarDef, v.Op == OpVarKill:
|
||||
case v.Op == OpVarDef:
|
||||
n := v.Aux.(*ir.Name)
|
||||
if ir.IsSynthetic(n) {
|
||||
break
|
||||
|
@ -528,7 +528,6 @@ var genericOps = []opData{
|
||||
{name: "Unknown"},
|
||||
|
||||
{name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem", symEffect: "None", zeroWidth: true}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem
|
||||
{name: "VarKill", argLength: 1, aux: "Sym", symEffect: "None"}, // aux is a *gc.Node of a variable that is known to be dead. arg0=mem, returns mem
|
||||
// TODO: what's the difference between VarLive and KeepAlive?
|
||||
{name: "VarLive", argLength: 1, aux: "Sym", symEffect: "Read", zeroWidth: true}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
|
||||
{name: "KeepAlive", argLength: 2, typ: "Mem", zeroWidth: true}, // arg[0] is a value that must be kept alive until this mark. arg[1]=mem, returns mem
|
||||
|
@ -21,7 +21,7 @@ func checkLower(f *Func) {
|
||||
continue // lowered
|
||||
}
|
||||
switch v.Op {
|
||||
case OpSP, OpSB, OpInitMem, OpArg, OpArgIntReg, OpArgFloatReg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpSelectN, OpConvert, OpInlMark:
|
||||
case OpSP, OpSB, OpInitMem, OpArg, OpArgIntReg, OpArgFloatReg, OpPhi, OpVarDef, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpSelectN, OpConvert, OpInlMark:
|
||||
continue // ok not to lower
|
||||
case OpMakeResult:
|
||||
if b.Controls[0] == v {
|
||||
|
@ -236,7 +236,7 @@ func nilcheckelim2(f *Func) {
|
||||
continue
|
||||
}
|
||||
if v.Type.IsMemory() || v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
|
||||
if v.Op == OpVarKill || v.Op == OpVarLive || (v.Op == OpVarDef && !v.Aux.(*ir.Name).Type().HasPointers()) {
|
||||
if v.Op == OpVarLive || (v.Op == OpVarDef && !v.Aux.(*ir.Name).Type().HasPointers()) {
|
||||
// These ops don't really change memory.
|
||||
continue
|
||||
// Note: OpVarDef requires that the defined variable not have pointers.
|
||||
|
@ -62,7 +62,7 @@ func nextGoodStatementIndex(v *Value, i int, b *Block) int {
|
||||
// statement boundary.
|
||||
func notStmtBoundary(op Op) bool {
|
||||
switch op {
|
||||
case OpCopy, OpPhi, OpVarKill, OpVarDef, OpVarLive, OpUnknown, OpFwdRef, OpArg, OpArgIntReg, OpArgFloatReg:
|
||||
case OpCopy, OpPhi, OpVarDef, OpVarLive, OpUnknown, OpFwdRef, OpArg, OpArgIntReg, OpArgFloatReg:
|
||||
return true
|
||||
}
|
||||
return false
|
||||
|
@ -3088,7 +3088,6 @@ const (
|
||||
OpFwdRef
|
||||
OpUnknown
|
||||
OpVarDef
|
||||
OpVarKill
|
||||
OpVarLive
|
||||
OpKeepAlive
|
||||
OpInlMark
|
||||
@ -39144,13 +39143,6 @@ var opcodeTable = [...]opInfo{
|
||||
symEffect: SymNone,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "VarKill",
|
||||
auxType: auxSym,
|
||||
argLen: 1,
|
||||
symEffect: SymNone,
|
||||
generic: true,
|
||||
},
|
||||
{
|
||||
name: "VarLive",
|
||||
auxType: auxSym,
|
||||
|
@ -520,7 +520,7 @@ func (v *Value) LackingPos() bool {
|
||||
// The exact definition of LackingPos is somewhat heuristically defined and may change
|
||||
// in the future, for example if some of these operations are generated more carefully
|
||||
// with respect to their source position.
|
||||
return v.Op == OpVarDef || v.Op == OpVarKill || v.Op == OpVarLive || v.Op == OpPhi ||
|
||||
return v.Op == OpVarDef || v.Op == OpVarLive || v.Op == OpPhi ||
|
||||
(v.Op == OpFwdRef || v.Op == OpCopy) && v.Type == types.TypeMem
|
||||
}
|
||||
|
||||
|
@ -163,7 +163,7 @@ func writebarrier(f *Func) {
|
||||
last = w
|
||||
end = i + 1
|
||||
}
|
||||
case OpVarDef, OpVarLive, OpVarKill:
|
||||
case OpVarDef, OpVarLive:
|
||||
continue
|
||||
default:
|
||||
if last == nil {
|
||||
@ -279,7 +279,7 @@ func writebarrier(f *Func) {
|
||||
fn = typedmemclr
|
||||
typ = reflectdata.TypeLinksym(w.Aux.(*types.Type))
|
||||
nWBops--
|
||||
case OpVarDef, OpVarLive, OpVarKill:
|
||||
case OpVarDef, OpVarLive:
|
||||
}
|
||||
|
||||
// then block: emit write barrier call
|
||||
@ -301,7 +301,7 @@ func writebarrier(f *Func) {
|
||||
}
|
||||
// Note that we set up a writebarrier function call.
|
||||
f.fe.SetWBPos(pos)
|
||||
case OpVarDef, OpVarLive, OpVarKill:
|
||||
case OpVarDef, OpVarLive:
|
||||
memThen = bThen.NewValue1A(pos, w.Op, types.TypeMem, w.Aux, memThen)
|
||||
}
|
||||
|
||||
@ -315,7 +315,7 @@ func writebarrier(f *Func) {
|
||||
case OpZeroWB:
|
||||
memElse = bElse.NewValue2I(pos, OpZero, types.TypeMem, w.AuxInt, ptr, memElse)
|
||||
memElse.Aux = w.Aux
|
||||
case OpVarDef, OpVarLive, OpVarKill:
|
||||
case OpVarDef, OpVarLive:
|
||||
memElse = bElse.NewValue1A(pos, w.Op, types.TypeMem, w.Aux, memElse)
|
||||
}
|
||||
}
|
||||
|
@ -1470,9 +1470,6 @@ func (s *state) stmt(n ir.Node) {
|
||||
s.Fatalf("dottype of non-load")
|
||||
}
|
||||
mem := s.mem()
|
||||
if mem.Op == ssa.OpVarKill {
|
||||
mem = mem.Args[0]
|
||||
}
|
||||
if res.Args[1] != mem {
|
||||
s.Fatalf("memory no longer live from 2-result dottype load")
|
||||
}
|
||||
@ -6947,7 +6944,7 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
|
||||
case ssa.OpGetG:
|
||||
// nothing to do when there's a g register,
|
||||
// and checkLower complains if there's not
|
||||
case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive, ssa.OpVarKill:
|
||||
case ssa.OpVarDef, ssa.OpVarLive, ssa.OpKeepAlive:
|
||||
// nothing to do; already used by liveness
|
||||
case ssa.OpPhi:
|
||||
CheckLoweredPhi(v)
|
||||
|
Loading…
Reference in New Issue
Block a user