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
// 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 {
// 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
}
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])
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)
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 {
// 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
}
switch {
- case v.Op == OpVarDef, v.Op == OpVarKill:
+ case v.Op == OpVarDef:
n := v.Aux.(*ir.Name)
if ir.IsSynthetic(n) {
break
{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
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 {
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.
// 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
OpFwdRef
OpUnknown
OpVarDef
- OpVarKill
OpVarLive
OpKeepAlive
OpInlMark
symEffect: SymNone,
generic: true,
},
- {
- name: "VarKill",
- auxType: auxSym,
- argLen: 1,
- symEffect: SymNone,
- generic: true,
- },
{
name: "VarLive",
auxType: auxSym,
// 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
}
last = w
end = i + 1
}
- case OpVarDef, OpVarLive, OpVarKill:
+ case OpVarDef, OpVarLive:
continue
default:
if last == nil {
fn = typedmemclr
typ = reflectdata.TypeLinksym(w.Aux.(*types.Type))
nWBops--
- case OpVarDef, OpVarLive, OpVarKill:
+ case OpVarDef, OpVarLive:
}
// then block: emit write barrier call
}
// 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)
}
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)
}
}
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")
}
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)