Commit 1787ced8 authored by Keith Randall's avatar Keith Randall

cmd/compile: remove Symbol wrappers from Aux fields

We used to have {Arg,Auto,Extern}Symbol structs with which we wrapped
a *gc.Node or *obj.LSym before storing them in the Aux field
of an ssa.Value.  This let the SSA part of the compiler distinguish
between autos and args, for example.  We no longer need the wrappers
as we can query the underlying objects directly.

There was also some sloppy usage, where VarDef had a *gc.Node
directly in its Aux field, whereas the use of that variable had
that *gc.Node wrapped in an AutoSymbol. Thus the Aux fields didn't
match (using ==) when they probably should.
This sloppy usage cleanup is the only thing in the CL that changes the
generated code - we can get rid of some more unused auto variables if
the matching happens reliably.

Removing this wrapper also lets us get rid of the varsyms cache
(which was used to prevent wrapping the same *gc.Node twice).

Change-Id: I0dedf8f82f84bfee413d310342b777316bd1d478
Reviewed-on: https://go-review.googlesource.com/64452
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarMatthew Dempsky <mdempsky@google.com>
parent 0a48185b
...@@ -622,6 +622,7 @@ var knownFormats = map[string]string{ ...@@ -622,6 +622,7 @@ var knownFormats = map[string]string{
"byte %c": "", "byte %c": "",
"cmd/compile/internal/arm.shift %d": "", "cmd/compile/internal/arm.shift %d": "",
"cmd/compile/internal/gc.Class %d": "", "cmd/compile/internal/gc.Class %d": "",
"cmd/compile/internal/gc.Class %s": "",
"cmd/compile/internal/gc.Class %v": "", "cmd/compile/internal/gc.Class %v": "",
"cmd/compile/internal/gc.Ctype %d": "", "cmd/compile/internal/gc.Ctype %d": "",
"cmd/compile/internal/gc.Ctype %v": "", "cmd/compile/internal/gc.Ctype %v": "",
......
...@@ -493,10 +493,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -493,10 +493,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
switch v.Aux.(type) { switch v.Aux.(type) {
default: default:
v.Fatalf("aux is of unknown type %T", v.Aux) v.Fatalf("aux is of unknown type %T", v.Aux)
case *ssa.ExternSymbol: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *ssa.ArgSymbol, *ssa.AutoSymbol: case *gc.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:
......
...@@ -273,10 +273,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -273,10 +273,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
switch v.Aux.(type) { switch v.Aux.(type) {
default: default:
v.Fatalf("aux is of unknown type %T", v.Aux) v.Fatalf("aux is of unknown type %T", v.Aux)
case *ssa.ExternSymbol: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *ssa.ArgSymbol, *ssa.AutoSymbol: case *gc.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:
......
...@@ -133,20 +133,21 @@ func (s *ssafn) AllocFrame(f *ssa.Func) { ...@@ -133,20 +133,21 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
scratchUsed := false scratchUsed := false
for _, b := range f.Blocks { for _, b := range f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
switch a := v.Aux.(type) { if n, ok := v.Aux.(*Node); ok {
case *ssa.ArgSymbol: switch n.Class() {
n := a.Node.(*Node) case PPARAM, PPARAMOUT:
// Don't modify nodfp; it is a global. // Don't modify nodfp; it is a global.
if n != nodfp { if n != nodfp {
n.Name.SetUsed(true)
}
case PAUTO:
n.Name.SetUsed(true) n.Name.SetUsed(true)
} }
case *ssa.AutoSymbol:
a.Node.(*Node).Name.SetUsed(true)
} }
if !scratchUsed { if !scratchUsed {
scratchUsed = v.Op.UsesScratch() scratchUsed = v.Op.UsesScratch()
} }
} }
} }
......
...@@ -291,14 +291,7 @@ func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) { ...@@ -291,14 +291,7 @@ func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
return n, ssa.SymWrite return n, ssa.SymWrite
case ssa.OpVarLive: case ssa.OpVarLive:
switch a := v.Aux.(type) { return v.Aux.(*Node), ssa.SymRead
case *ssa.ArgSymbol:
return a.Node.(*Node), ssa.SymRead
case *ssa.AutoSymbol:
return a.Node.(*Node), ssa.SymRead
default:
Fatalf("unknown VarLive aux type: %s", v.LongString())
}
case ssa.OpVarDef, ssa.OpVarKill: case ssa.OpVarDef, ssa.OpVarKill:
return v.Aux.(*Node), ssa.SymWrite return v.Aux.(*Node), ssa.SymWrite
case ssa.OpKeepAlive: case ssa.OpKeepAlive:
...@@ -313,12 +306,10 @@ func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) { ...@@ -313,12 +306,10 @@ func affectedNode(v *ssa.Value) (*Node, ssa.SymEffect) {
var n *Node var n *Node
switch a := v.Aux.(type) { switch a := v.Aux.(type) {
case nil, *ssa.ExternSymbol: case nil, *obj.LSym:
// ok, but no node // ok, but no node
case *ssa.ArgSymbol: case *Node:
n = a.Node.(*Node) n = a
case *ssa.AutoSymbol:
n = a.Node.(*Node)
default: default:
Fatalf("weird aux: %s", v.LongString()) Fatalf("weird aux: %s", v.LongString())
} }
...@@ -931,13 +922,7 @@ func clobberWalk(b *ssa.Block, v *Node, offset int64, t *types.Type) { ...@@ -931,13 +922,7 @@ func clobberWalk(b *ssa.Block, v *Node, offset int64, t *types.Type) {
// clobberPtr generates a clobber of the pointer at offset offset in v. // clobberPtr generates a clobber of the pointer at offset offset in v.
// The clobber instruction is added at the end of b. // The clobber instruction is added at the end of b.
func clobberPtr(b *ssa.Block, v *Node, offset int64) { func clobberPtr(b *ssa.Block, v *Node, offset int64) {
var aux interface{} b.NewValue0IA(src.NoXPos, ssa.OpClobber, types.TypeVoid, offset, v)
if v.Class() == PAUTO {
aux = &ssa.AutoSymbol{Node: v}
} else {
aux = &ssa.ArgSymbol{Node: v}
}
b.NewValue0IA(src.NoXPos, ssa.OpClobber, types.TypeVoid, offset, aux)
} }
func (lv *Liveness) avarinitanyall(b *ssa.Block, any, all bvec) { func (lv *Liveness) avarinitanyall(b *ssa.Block, any, all bvec) {
......
...@@ -163,15 +163,12 @@ func buildssa(fn *Node, worker int) *ssa.Func { ...@@ -163,15 +163,12 @@ func buildssa(fn *Node, worker int) *ssa.Func {
s.startBlock(s.f.Entry) s.startBlock(s.f.Entry)
s.vars[&memVar] = s.startmem s.vars[&memVar] = s.startmem
s.varsyms = map[*Node]interface{}{}
// Generate addresses of local declarations // Generate addresses of local declarations
s.decladdrs = map[*Node]*ssa.Value{} s.decladdrs = map[*Node]*ssa.Value{}
for _, n := range fn.Func.Dcl { for _, n := range fn.Func.Dcl {
switch n.Class() { switch n.Class() {
case PPARAM, PPARAMOUT: case PPARAM, PPARAMOUT:
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Node: n}) s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), n, s.sp)
s.decladdrs[n] = s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), aux, s.sp)
if n.Class() == PPARAMOUT && s.canSSA(n) { if n.Class() == PPARAMOUT && s.canSSA(n) {
// Save ssa-able PPARAMOUT variables so we can // Save ssa-able PPARAMOUT variables so we can
// store them back to the stack at the end of // store them back to the stack at the end of
...@@ -259,9 +256,6 @@ type state struct { ...@@ -259,9 +256,6 @@ type state struct {
// addresses of PPARAM and PPARAMOUT variables. // addresses of PPARAM and PPARAMOUT variables.
decladdrs map[*Node]*ssa.Value decladdrs map[*Node]*ssa.Value
// symbols for PEXTERN, PAUTO and PPARAMOUT variables so they can be reused.
varsyms map[*Node]interface{}
// starting values. Memory, stack pointer, and globals pointer // starting values. Memory, stack pointer, and globals pointer
startmem *ssa.Value startmem *ssa.Value
sp *ssa.Value sp *ssa.Value
...@@ -937,16 +931,12 @@ func (s *state) stmt(n *Node) { ...@@ -937,16 +931,12 @@ func (s *state) stmt(n *Node) {
if !n.Left.Addrtaken() { if !n.Left.Addrtaken() {
s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left) s.Fatalf("VARLIVE variable %v must have Addrtaken set", n.Left)
} }
var aux interface{}
switch n.Left.Class() { switch n.Left.Class() {
case PAUTO: case PAUTO, PPARAM, PPARAMOUT:
aux = s.lookupSymbol(n.Left, &ssa.AutoSymbol{Node: n.Left})
case PPARAM, PPARAMOUT:
aux = s.lookupSymbol(n.Left, &ssa.ArgSymbol{Node: n.Left})
default: default:
s.Fatalf("VARLIVE variable %v must be Auto or Arg", n.Left) s.Fatalf("VARLIVE variable %v must be Auto or Arg", n.Left)
} }
s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, aux, s.mem()) s.vars[&memVar] = s.newValue1A(ssa.OpVarLive, types.TypeMem, n.Left, s.mem())
case OCHECKNIL: case OCHECKNIL:
p := s.expr(n.Left) p := s.expr(n.Left)
...@@ -1420,14 +1410,13 @@ func (s *state) expr(n *Node) *ssa.Value { ...@@ -1420,14 +1410,13 @@ func (s *state) expr(n *Node) *ssa.Value {
len := s.newValue1(ssa.OpStringLen, types.Types[TINT], str) len := s.newValue1(ssa.OpStringLen, types.Types[TINT], str)
return s.newValue3(ssa.OpSliceMake, n.Type, ptr, len, len) return s.newValue3(ssa.OpSliceMake, n.Type, ptr, len, len)
case OCFUNC: case OCFUNC:
aux := s.lookupSymbol(n, &ssa.ExternSymbol{Sym: n.Left.Sym.Linksym()}) aux := n.Left.Sym.Linksym()
return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb) return s.entryNewValue1A(ssa.OpAddr, n.Type, aux, s.sb)
case ONAME: case ONAME:
if n.Class() == PFUNC { if n.Class() == PFUNC {
// "value" of a function is the address of the function's closure // "value" of a function is the address of the function's closure
sym := funcsym(n.Sym).Linksym() sym := funcsym(n.Sym).Linksym()
aux := s.lookupSymbol(n, &ssa.ExternSymbol{Sym: sym}) return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), sym, s.sb)
return s.entryNewValue1A(ssa.OpAddr, types.NewPtr(n.Type), aux, s.sb)
} }
if s.canSSA(n) { if s.canSSA(n) {
return s.variable(n, n.Type) return s.variable(n, n.Type)
...@@ -2203,7 +2192,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value { ...@@ -2203,7 +2192,7 @@ func (s *state) append(n *Node, inplace bool) *ssa.Value {
r := s.rtcall(growslice, true, []*types.Type{pt, types.Types[TINT], types.Types[TINT]}, taddr, p, l, c, nl) r := s.rtcall(growslice, true, []*types.Type{pt, types.Types[TINT], types.Types[TINT]}, taddr, p, l, c, nl)
if inplace { if inplace {
if sn.Op == ONAME { if sn.Op == ONAME && sn.Class() != PEXTERN {
// Tell liveness we're about to build a new slice // Tell liveness we're about to build a new slice
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem()) s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, sn, s.mem())
} }
...@@ -2410,7 +2399,7 @@ func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask) ...@@ -2410,7 +2399,7 @@ func (s *state) assign(left *Node, right *ssa.Value, deref bool, skip skipMask)
} }
// Left is not ssa-able. Compute its address. // Left is not ssa-able. Compute its address.
addr := s.addr(left, false) addr := s.addr(left, false)
if left.Op == ONAME && skip == 0 { if left.Op == ONAME && left.Class() != PEXTERN && skip == 0 {
s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, left, s.mem()) s.vars[&memVar] = s.newValue1A(ssa.OpVarDef, types.TypeMem, left, s.mem())
} }
if isReflectHeaderDataField(left) { if isReflectHeaderDataField(left) {
...@@ -2879,7 +2868,7 @@ func init() { ...@@ -2879,7 +2868,7 @@ func init() {
sys.ARM64) sys.ARM64)
makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value { makeOnesCountAMD64 := func(op64 ssa.Op, op32 ssa.Op) func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
return func(s *state, n *Node, args []*ssa.Value) *ssa.Value { return func(s *state, n *Node, args []*ssa.Value) *ssa.Value {
aux := s.lookupSymbol(n, &ssa.ExternSymbol{Sym: syslook("support_popcnt").Sym.Linksym()}) aux := syslook("support_popcnt").Sym.Linksym()
addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), aux, s.sb) addr := s.entryNewValue1A(ssa.OpAddr, types.Types[TBOOL].PtrTo(), aux, s.sb)
v := s.newValue2(ssa.OpLoad, types.Types[TBOOL], addr, s.mem()) v := s.newValue2(ssa.OpLoad, types.Types[TBOOL], addr, s.mem())
b := s.endBlock() b := s.endBlock()
...@@ -3231,24 +3220,6 @@ func etypesign(e types.EType) int8 { ...@@ -3231,24 +3220,6 @@ func etypesign(e types.EType) int8 {
return 0 return 0
} }
// lookupSymbol is used to retrieve the symbol (Extern, Arg or Auto) used for a particular node.
// This improves the effectiveness of cse by using the same Aux values for the
// same symbols.
func (s *state) lookupSymbol(n *Node, sym interface{}) interface{} {
switch sym.(type) {
default:
s.Fatalf("sym %v is of unknown type %T", sym, sym)
case *ssa.ExternSymbol, *ssa.ArgSymbol, *ssa.AutoSymbol:
// these are the only valid types
}
if lsym, ok := s.varsyms[n]; ok {
return lsym
}
s.varsyms[n] = sym
return sym
}
// addr converts the address of the expression n to SSA, adds it to s and returns the SSA result. // addr converts the address of the expression n to SSA, adds it to s and returns the SSA result.
// The value that the returned Value represents is guaranteed to be non-nil. // The value that the returned Value represents is guaranteed to be non-nil.
// If bounded is true then this address does not require a nil check for its operand // If bounded is true then this address does not require a nil check for its operand
...@@ -3260,8 +3231,7 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { ...@@ -3260,8 +3231,7 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
switch n.Class() { switch n.Class() {
case PEXTERN: case PEXTERN:
// global variable // global variable
aux := s.lookupSymbol(n, &ssa.ExternSymbol{Sym: n.Sym.Linksym()}) v := s.entryNewValue1A(ssa.OpAddr, t, n.Sym.Linksym(), s.sb)
v := s.entryNewValue1A(ssa.OpAddr, t, aux, s.sb)
// TODO: Make OpAddr use AuxInt as well as Aux. // TODO: Make OpAddr use AuxInt as well as Aux.
if n.Xoffset != 0 { if n.Xoffset != 0 {
v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v) v = s.entryNewValue1I(ssa.OpOffPtr, v.Type, n.Xoffset, v)
...@@ -3275,19 +3245,16 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value { ...@@ -3275,19 +3245,16 @@ func (s *state) addr(n *Node, bounded bool) *ssa.Value {
} }
if n == nodfp { if n == nodfp {
// Special arg that points to the frame pointer (Used by ORECOVER). // Special arg that points to the frame pointer (Used by ORECOVER).
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Node: n}) return s.entryNewValue1A(ssa.OpAddr, t, n, s.sp)
return s.entryNewValue1A(ssa.OpAddr, t, aux, s.sp)
} }
s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs) s.Fatalf("addr of undeclared ONAME %v. declared: %v", n, s.decladdrs)
return nil return nil
case PAUTO: case PAUTO:
aux := s.lookupSymbol(n, &ssa.AutoSymbol{Node: n}) return s.newValue1A(ssa.OpAddr, t, n, s.sp)
return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early. case PPARAMOUT: // Same as PAUTO -- cannot generate LEA early.
// ensure that we reuse symbols for out parameters so // ensure that we reuse symbols for out parameters so
// that cse works on their addresses // that cse works on their addresses
aux := s.lookupSymbol(n, &ssa.ArgSymbol{Node: n}) return s.newValue1A(ssa.OpAddr, t, n, s.sp)
return s.newValue1A(ssa.OpAddr, t, aux, s.sp)
default: default:
s.Fatalf("variable address class %v not implemented", classnames[n.Class()]) s.Fatalf("variable address class %v not implemented", classnames[n.Class()])
return nil return nil
...@@ -4672,10 +4639,11 @@ func AuxOffset(v *ssa.Value) (offset int64) { ...@@ -4672,10 +4639,11 @@ func AuxOffset(v *ssa.Value) (offset int64) {
if v.Aux == nil { if v.Aux == nil {
return 0 return 0
} }
switch sym := v.Aux.(type) { n, ok := v.Aux.(*Node)
if !ok {
case *ssa.AutoSymbol: v.Fatalf("bad aux type in %s\n", v.LongString())
n := sym.Node.(*Node) }
if n.Class() == PAUTO {
return n.Xoffset return n.Xoffset
} }
return 0 return 0
...@@ -4697,17 +4665,17 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) { ...@@ -4697,17 +4665,17 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
return return
} }
// Add symbol's offset from its base register. // Add symbol's offset from its base register.
switch sym := v.Aux.(type) { switch n := v.Aux.(type) {
case *ssa.ExternSymbol: case *obj.LSym:
a.Name = obj.NAME_EXTERN a.Name = obj.NAME_EXTERN
a.Sym = sym.Sym a.Sym = n
case *ssa.ArgSymbol: case *Node:
n := sym.Node.(*Node) if n.Class() == PPARAM || n.Class() == PPARAMOUT {
a.Name = obj.NAME_PARAM a.Name = obj.NAME_PARAM
a.Sym = n.Orig.Sym.Linksym() a.Sym = n.Orig.Sym.Linksym()
a.Offset += n.Xoffset a.Offset += n.Xoffset
case *ssa.AutoSymbol: break
n := sym.Node.(*Node) }
a.Name = obj.NAME_AUTO a.Name = obj.NAME_AUTO
a.Sym = n.Sym.Linksym() a.Sym = n.Sym.Linksym()
a.Offset += n.Xoffset a.Offset += n.Xoffset
...@@ -4922,9 +4890,8 @@ func (e *ssafn) StringData(s string) interface{} { ...@@ -4922,9 +4890,8 @@ func (e *ssafn) StringData(s string) interface{} {
e.strings = make(map[string]interface{}) e.strings = make(map[string]interface{})
} }
data := stringsym(s) data := stringsym(s)
aux := &ssa.ExternSymbol{Sym: data} e.strings[s] = data
e.strings[s] = aux return data
return aux
} }
func (e *ssafn) Auto(pos src.XPos, t *types.Type) ssa.GCNode { func (e *ssafn) Auto(pos src.XPos, t *types.Type) ssa.GCNode {
...@@ -5141,3 +5108,16 @@ func (e *ssafn) Syslook(name string) *obj.LSym { ...@@ -5141,3 +5108,16 @@ func (e *ssafn) Syslook(name string) *obj.LSym {
func (n *Node) Typ() *types.Type { func (n *Node) Typ() *types.Type {
return n.Type return n.Type
} }
func (n *Node) StorageClass() ssa.StorageClass {
switch n.Class() {
case PPARAM:
return ssa.ClassParam
case PPARAMOUT:
return ssa.ClassParamOut
case PAUTO:
return ssa.ClassAuto
default:
Fatalf("untranslateable storage class for %v: %s", n, n.Class())
return 0
}
}
...@@ -283,10 +283,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -283,10 +283,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
switch v.Aux.(type) { switch v.Aux.(type) {
default: default:
v.Fatalf("aux is of unknown type %T", v.Aux) v.Fatalf("aux is of unknown type %T", v.Aux)
case *ssa.ExternSymbol: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *ssa.ArgSymbol, *ssa.AutoSymbol: case *gc.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:
......
...@@ -257,10 +257,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -257,10 +257,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
switch v.Aux.(type) { switch v.Aux.(type) {
default: default:
v.Fatalf("aux is of unknown type %T", v.Aux) v.Fatalf("aux is of unknown type %T", v.Aux)
case *ssa.ExternSymbol: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *ssa.ArgSymbol, *ssa.AutoSymbol: case *gc.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:
......
...@@ -628,10 +628,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -628,10 +628,10 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
switch v.Aux.(type) { switch v.Aux.(type) {
default: default:
v.Fatalf("aux is of unknown type %T", v.Aux) v.Fatalf("aux is of unknown type %T", v.Aux)
case *ssa.ExternSymbol: case *obj.LSym:
wantreg = "SB" wantreg = "SB"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case *ssa.ArgSymbol, *ssa.AutoSymbol: case *gc.Node:
wantreg = "SP" wantreg = "SP"
gc.AddAux(&p.From, v) gc.AddAux(&p.From, v)
case nil: case nil:
......
...@@ -133,13 +133,22 @@ type Frontend interface { ...@@ -133,13 +133,22 @@ type Frontend interface {
UseWriteBarrier() bool UseWriteBarrier() bool
} }
// interface used to hold *gc.Node. We'd use *gc.Node directly but // interface used to hold a *gc.Node (a stack variable).
// that would lead to an import cycle. // We'd use *gc.Node directly but that would lead to an import cycle.
type GCNode interface { type GCNode interface {
Typ() *types.Type Typ() *types.Type
String() string String() string
StorageClass() StorageClass
} }
type StorageClass uint8
const (
ClassAuto StorageClass = iota // local stack variable
ClassParam // argument
ClassParamOut // return value
)
// NewConfig returns a new configuration object for the given architecture. // NewConfig returns a new configuration object for the given architecture.
func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config { func NewConfig(arch string, types Types, ctxt *obj.Link, optimize bool) *Config {
c := &Config{arch: arch, Types: types} c := &Config{arch: arch, Types: types}
......
...@@ -132,7 +132,8 @@ func dse(f *Func) { ...@@ -132,7 +132,8 @@ func dse(f *Func) {
} }
} }
// elimUnreadAutos deletes stores to autos that are never read from. // elimUnreadAutos deletes stores (and associated bookkeeping ops VarDef and VarKill)
// to autos that are never read from.
func elimUnreadAutos(f *Func) { func elimUnreadAutos(f *Func) {
// Loop over all ops that affect autos taking note of which // Loop over all ops that affect autos taking note of which
// autos we need and also stores that we might be able to // autos we need and also stores that we might be able to
...@@ -141,19 +142,21 @@ func elimUnreadAutos(f *Func) { ...@@ -141,19 +142,21 @@ func elimUnreadAutos(f *Func) {
var stores []*Value var stores []*Value
for _, b := range f.Blocks { for _, b := range f.Blocks {
for _, v := range b.Values { for _, v := range b.Values {
var sym *AutoSymbol n, ok := v.Aux.(GCNode)
sym, ok := v.Aux.(*AutoSymbol)
if !ok { if !ok {
continue continue
} }
if n.StorageClass() != ClassAuto {
continue
}
effect := v.Op.SymEffect() effect := v.Op.SymEffect()
switch effect { switch effect {
case SymWrite: case SymNone, SymWrite:
// If we haven't seen the auto yet // If we haven't seen the auto yet
// then this might be a store we can // then this might be a store we can
// eliminate. // eliminate.
if !seen[sym.Node] { if !seen[n] {
stores = append(stores, v) stores = append(stores, v)
} }
default: default:
...@@ -163,7 +166,7 @@ func elimUnreadAutos(f *Func) { ...@@ -163,7 +166,7 @@ func elimUnreadAutos(f *Func) {
// because dead loads haven't been // because dead loads haven't been
// eliminated yet. // eliminated yet.
if v.Uses > 0 { if v.Uses > 0 {
seen[sym.Node] = true seen[n] = true
} }
} }
} }
...@@ -171,8 +174,8 @@ func elimUnreadAutos(f *Func) { ...@@ -171,8 +174,8 @@ func elimUnreadAutos(f *Func) {
// Eliminate stores to unread autos. // Eliminate stores to unread autos.
for _, store := range stores { for _, store := range stores {
sym, _ := store.Aux.(*AutoSymbol) n, _ := store.Aux.(GCNode)
if seen[sym.Node] { if seen[n] {
continue continue
} }
......
...@@ -75,6 +75,10 @@ func (d *DummyAuto) String() string { ...@@ -75,6 +75,10 @@ func (d *DummyAuto) String() string {
return d.s return d.s
} }
func (d *DummyAuto) StorageClass() StorageClass {
return ClassAuto
}
func (DummyFrontend) StringData(s string) interface{} { func (DummyFrontend) StringData(s string) interface{} {
return nil return nil
} }
......
...@@ -289,12 +289,13 @@ var genericOps = []opData{ ...@@ -289,12 +289,13 @@ var genericOps = []opData{
// Constant-like things // Constant-like things
{name: "InitMem"}, // memory input to the function. {name: "InitMem"}, // memory input to the function.
{name: "Arg", aux: "SymOff", symEffect: "None"}, // argument to the function. aux=GCNode of arg, off = offset in that arg. {name: "Arg", aux: "SymOff", symEffect: "Read"}, // argument to the function. aux=GCNode of arg, off = offset in that arg.
// The address of a variable. arg0 is the base pointer (SB or SP, depending // The address of a variable. arg0 is the base pointer.
// on whether it is a global or stack variable). The Aux field identifies the // If the variable is a global, the base pointer will be SB and
// variable. It will be either an *ExternSymbol (with arg0=SB), *ArgSymbol (arg0=SP), // the Aux field will be a *obj.LSym.
// or *AutoSymbol (arg0=SP). // If the variable is a local, the base pointer will be SP and
// the Aux field will be a *gc.Node.
{name: "Addr", argLength: 1, aux: "Sym", symEffect: "Addr"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable. {name: "Addr", argLength: 1, aux: "Sym", symEffect: "Addr"}, // Address of a variable. Arg0=SP or SB. Aux identifies the variable.
{name: "SP"}, // stack pointer {name: "SP"}, // stack pointer
...@@ -418,7 +419,7 @@ var genericOps = []opData{ ...@@ -418,7 +419,7 @@ var genericOps = []opData{
{name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem", symEffect: "None"}, // aux is a *gc.Node of a variable that is about to be initialized. arg0=mem, returns mem {name: "VarDef", argLength: 1, aux: "Sym", typ: "Mem", symEffect: "None"}, // 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 {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
{name: "VarLive", argLength: 1, aux: "Sym", symEffect: "None"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem {name: "VarLive", argLength: 1, aux: "Sym", symEffect: "Read"}, // aux is a *gc.Node of a variable that must be kept live. arg0=mem, returns mem
{name: "KeepAlive", argLength: 2, typ: "Mem"}, // arg[0] is a value that must be kept alive until this mark. arg[1]=mem, returns mem {name: "KeepAlive", argLength: 2, typ: "Mem"}, // arg[0] is a value that must be kept alive until this mark. arg[1]=mem, returns mem
{name: "RegKill"}, // regalloc has determined that the value in this register is dead {name: "RegKill"}, // regalloc has determined that the value in this register is dead
......
...@@ -67,7 +67,7 @@ const ( ...@@ -67,7 +67,7 @@ const (
auxFloat32 // auxInt is a float32 (encoded with math.Float64bits) auxFloat32 // auxInt is a float32 (encoded with math.Float64bits)
auxFloat64 // auxInt is a float64 (encoded with math.Float64bits) auxFloat64 // auxInt is a float64 (encoded with math.Float64bits)
auxString // aux is a string auxString // aux is a string
auxSym // aux is a symbol auxSym // aux is a symbol (a *gc.Node for locals or an *obj.LSym for globals)
auxSymOff // aux is a symbol, auxInt is an offset auxSymOff // aux is a symbol, auxInt is an offset
auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff auxSymValAndOff // aux is a symbol, auxInt is a ValAndOff
auxTyp // aux is a type auxTyp // aux is a type
......
...@@ -22524,7 +22524,7 @@ var opcodeTable = [...]opInfo{ ...@@ -22524,7 +22524,7 @@ var opcodeTable = [...]opInfo{
name: "Arg", name: "Arg",
auxType: auxSymOff, auxType: auxSymOff,
argLen: 0, argLen: 0,
symEffect: SymNone, symEffect: SymRead,
generic: true, generic: true,
}, },
{ {
...@@ -22950,7 +22950,7 @@ var opcodeTable = [...]opInfo{ ...@@ -22950,7 +22950,7 @@ var opcodeTable = [...]opInfo{
name: "VarLive", name: "VarLive",
auxType: auxSym, auxType: auxSym,
argLen: 1, argLen: 1,
symEffect: SymNone, symEffect: SymRead,
generic: true, generic: true,
}, },
{ {
......
...@@ -276,18 +276,6 @@ search: ...@@ -276,18 +276,6 @@ search:
return true return true
} }
// isArg returns whether s is an arg symbol
func isArg(s interface{}) bool {
_, ok := s.(*ArgSymbol)
return ok
}
// isAuto returns whether s is an auto symbol
func isAuto(s interface{}) bool {
_, ok := s.(*AutoSymbol)
return ok
}
// isSameSym returns whether sym is the same as the given named symbol // isSameSym returns whether sym is the same as the given named symbol
func isSameSym(sym interface{}, name string) bool { func isSameSym(sym interface{}, name string) bool {
s, ok := sym.(fmt.Stringer) s, ok := sym.(fmt.Stringer)
...@@ -412,11 +400,11 @@ func uaddOvf(a, b int64) bool { ...@@ -412,11 +400,11 @@ func uaddOvf(a, b int64) bool {
// 'sym' is the symbol for the itab // 'sym' is the symbol for the itab
func devirt(v *Value, sym interface{}, offset int64) *obj.LSym { func devirt(v *Value, sym interface{}, offset int64) *obj.LSym {
f := v.Block.Func f := v.Block.Func
ext, ok := sym.(*ExternSymbol) n, ok := sym.(*obj.LSym)
if !ok { if !ok {
return nil return nil
} }
lsym := f.fe.DerefItab(ext.Sym, offset) lsym := f.fe.DerefItab(n, offset)
if f.pass.debug > 0 { if f.pass.debug > 0 {
if lsym != nil { if lsym != nil {
f.Warnl(v.Pos, "de-virtualizing call") f.Warnl(v.Pos, "de-virtualizing call")
......
...@@ -6,7 +6,6 @@ package ssa ...@@ -6,7 +6,6 @@ package ssa
import ( import (
"cmd/compile/internal/types" "cmd/compile/internal/types"
"cmd/internal/obj"
"cmd/internal/src" "cmd/internal/src"
"fmt" "fmt"
"math" "math"
...@@ -264,38 +263,6 @@ func (v *Value) isGenericIntConst() bool { ...@@ -264,38 +263,6 @@ func (v *Value) isGenericIntConst() bool {
return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8) return v != nil && (v.Op == OpConst64 || v.Op == OpConst32 || v.Op == OpConst16 || v.Op == OpConst8)
} }
// ExternSymbol is an aux value that encodes a variable's
// constant offset from the static base pointer.
type ExternSymbol struct {
Sym *obj.LSym
// Note: the offset for an external symbol is not
// calculated until link time.
}
// ArgSymbol is an aux value that encodes an argument or result
// variable's constant offset from FP (FP = SP + framesize).
type ArgSymbol struct {
Node GCNode // A *gc.Node referring to the argument/result variable.
}
// AutoSymbol is an aux value that encodes a local variable's
// constant offset from SP.
type AutoSymbol struct {
Node GCNode // A *gc.Node referring to a local (auto) variable.
}
func (s *ExternSymbol) String() string {
return s.Sym.String()
}
func (s *ArgSymbol) String() string {
return s.Node.String()
}
func (s *AutoSymbol) String() string {
return s.Node.String()
}
// Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering. // Reg returns the register assigned to v, in cmd/internal/obj/$ARCH numbering.
func (v *Value) Reg() int16 { func (v *Value) Reg() int16 {
reg := v.Block.Func.RegAlloc[v.ID] reg := v.Block.Func.RegAlloc[v.ID]
......
...@@ -94,7 +94,7 @@ func writebarrier(f *Func) { ...@@ -94,7 +94,7 @@ func writebarrier(f *Func) {
if sp == nil { if sp == nil {
sp = f.Entry.NewValue0(initpos, OpSP, f.Config.Types.Uintptr) sp = f.Entry.NewValue0(initpos, OpSP, f.Config.Types.Uintptr)
} }
wbsym := &ExternSymbol{Sym: f.fe.Syslook("writeBarrier")} wbsym := f.fe.Syslook("writeBarrier")
wbaddr = f.Entry.NewValue1A(initpos, OpAddr, f.Config.Types.UInt32Ptr, wbsym, sb) wbaddr = f.Entry.NewValue1A(initpos, OpAddr, f.Config.Types.UInt32Ptr, wbsym, sb)
writebarrierptr = f.fe.Syslook("writebarrierptr") writebarrierptr = f.fe.Syslook("writebarrierptr")
typedmemmove = f.fe.Syslook("typedmemmove") typedmemmove = f.fe.Syslook("typedmemmove")
...@@ -182,7 +182,7 @@ func writebarrier(f *Func) { ...@@ -182,7 +182,7 @@ func writebarrier(f *Func) {
pos := w.Pos pos := w.Pos
var fn *obj.LSym var fn *obj.LSym
var typ *ExternSymbol var typ *obj.LSym
var val *Value var val *Value
switch w.Op { switch w.Op {
case OpStoreWB: case OpStoreWB:
...@@ -191,10 +191,10 @@ func writebarrier(f *Func) { ...@@ -191,10 +191,10 @@ func writebarrier(f *Func) {
case OpMoveWB: case OpMoveWB:
fn = typedmemmove fn = typedmemmove
val = w.Args[1] val = w.Args[1]
typ = &ExternSymbol{Sym: w.Aux.(*types.Type).Symbol()} typ = w.Aux.(*types.Type).Symbol()
case OpZeroWB: case OpZeroWB:
fn = typedmemclr fn = typedmemclr
typ = &ExternSymbol{Sym: w.Aux.(*types.Type).Symbol()} typ = w.Aux.(*types.Type).Symbol()
case OpVarDef, OpVarLive, OpVarKill: case OpVarDef, OpVarLive, OpVarKill:
} }
...@@ -274,7 +274,7 @@ func writebarrier(f *Func) { ...@@ -274,7 +274,7 @@ func writebarrier(f *Func) {
// wbcall emits write barrier runtime call in b, returns memory. // wbcall emits write barrier runtime call in b, returns memory.
// if valIsVolatile, it moves val into temp space before making the call. // if valIsVolatile, it moves val into temp space before making the call.
func wbcall(pos src.XPos, b *Block, fn *obj.LSym, typ *ExternSymbol, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value { func wbcall(pos src.XPos, b *Block, fn, typ *obj.LSym, ptr, val, mem, sp, sb *Value, valIsVolatile bool) *Value {
config := b.Func.Config config := b.Func.Config
var tmp GCNode var tmp GCNode
...@@ -284,9 +284,8 @@ func wbcall(pos src.XPos, b *Block, fn *obj.LSym, typ *ExternSymbol, ptr, val, m ...@@ -284,9 +284,8 @@ func wbcall(pos src.XPos, b *Block, fn *obj.LSym, typ *ExternSymbol, ptr, val, m
// value we're trying to move. // value we're trying to move.
t := val.Type.ElemType() t := val.Type.ElemType()
tmp = b.Func.fe.Auto(val.Pos, t) tmp = b.Func.fe.Auto(val.Pos, t)
aux := &AutoSymbol{Node: tmp}
mem = b.NewValue1A(pos, OpVarDef, types.TypeMem, tmp, mem) mem = b.NewValue1A(pos, OpVarDef, types.TypeMem, tmp, mem)
tmpaddr := b.NewValue1A(pos, OpAddr, t.PtrTo(), aux, sp) tmpaddr := b.NewValue1A(pos, OpAddr, t.PtrTo(), tmp, sp)
siz := t.Size() siz := t.Size()
mem = b.NewValue3I(pos, OpMove, types.TypeMem, siz, tmpaddr, val, mem) mem = b.NewValue3I(pos, OpMove, types.TypeMem, siz, tmpaddr, val, mem)
mem.Aux = t mem.Aux = t
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment