Commit 8c24bff5 authored by Matthew Dempsky's avatar Matthew Dempsky

cmd/compile: layout stack frame during SSA

Identify live stack variables during SSA and compute the stack frame
layout earlier so that we can emit instructions with the correct
offsets upfront.

Passes toolstash/buildall.

Change-Id: I191100dba274f1e364a15bdcfdc1d1466cdd1db5
Reviewed-on: https://go-review.googlesource.com/30216
Run-TryBot: Matthew Dempsky <mdempsky@google.com>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarKeith Randall <khr@golang.org>
parent f239196b
...@@ -669,17 +669,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -669,17 +669,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return return
} }
p := gc.Prog(loadByType(v.Type)) p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(v.Args[0]) gc.AddrAuto(&p.From, v.Args[0])
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
...@@ -691,17 +681,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -691,17 +681,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type)) p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(v) gc.AddrAuto(&p.To, v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
case ssa.OpPhi: case ssa.OpPhi:
gc.CheckLoweredPhi(v) gc.CheckLoweredPhi(v)
case ssa.OpInitMem: case ssa.OpInitMem:
......
...@@ -162,17 +162,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -162,17 +162,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return return
} }
p := gc.Prog(loadByType(v.Type)) p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(v.Args[0]) gc.AddrAuto(&p.From, v.Args[0])
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpPhi: case ssa.OpPhi:
...@@ -185,17 +175,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -185,17 +175,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type)) p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(v) gc.AddrAuto(&p.To, v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
case ssa.OpARMUDIVrtcall: case ssa.OpARMUDIVrtcall:
p := gc.Prog(obj.ACALL) p := gc.Prog(obj.ACALL)
p.To.Type = obj.TYPE_MEM p.To.Type = obj.TYPE_MEM
......
...@@ -136,17 +136,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -136,17 +136,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return return
} }
p := gc.Prog(loadByType(v.Type)) p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(v.Args[0]) gc.AddrAuto(&p.From, v.Args[0])
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpPhi: case ssa.OpPhi:
...@@ -159,17 +149,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -159,17 +149,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type)) p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(v) gc.AddrAuto(&p.To, v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
case ssa.OpARM64ADD, case ssa.OpARM64ADD,
ssa.OpARM64SUB, ssa.OpARM64SUB,
ssa.OpARM64AND, ssa.OpARM64AND,
......
...@@ -75,40 +75,6 @@ func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset in ...@@ -75,40 +75,6 @@ func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset in
return q return q
} }
// Fixup instructions after allocauto (formerly compactframe) has moved all autos around.
func fixautoused(p *obj.Prog) {
for lp := &p; ; {
p = *lp
if p == nil {
break
}
if p.As == obj.ATYPE && p.From.Node != nil && p.From.Name == obj.NAME_AUTO && !((p.From.Node).(*Node)).Used {
*lp = p.Link
continue
}
if (p.As == obj.AVARDEF || p.As == obj.AVARKILL || p.As == obj.AVARLIVE) && p.To.Node != nil && !((p.To.Node).(*Node)).Used {
// Cannot remove VARDEF instruction, because - unlike TYPE handled above -
// VARDEFs are interspersed with other code, and a jump might be using the
// VARDEF as a target. Replace with a no-op instead. A later pass will remove
// the no-ops.
obj.Nopout(p)
continue
}
if p.From.Name == obj.NAME_AUTO && p.From.Node != nil {
p.From.Offset += p.From.Node.(*Node).Xoffset
}
if p.To.Name == obj.NAME_AUTO && p.To.Node != nil {
p.To.Offset += p.To.Node.(*Node).Xoffset
}
lp = &p.Link
}
}
func ggloblnod(nam *Node) { func ggloblnod(nam *Node) {
s := Linksym(nam.Sym) s := Linksym(nam.Sym)
s.Gotype = Linksym(ngotype(nam)) s.Gotype = Linksym(ngotype(nam))
...@@ -153,23 +119,6 @@ func isfat(t *Type) bool { ...@@ -153,23 +119,6 @@ func isfat(t *Type) bool {
return false return false
} }
// Sweep the prog list to mark any used nodes.
func markautoused(p *obj.Prog) {
for ; p != nil; p = p.Link {
if p.As == obj.ATYPE || p.As == obj.AVARDEF || p.As == obj.AVARKILL {
continue
}
if p.From.Node != nil {
((p.From.Node).(*Node)).Used = true
}
if p.To.Node != nil {
((p.To.Node).(*Node)).Used = true
}
}
}
// Naddr rewrites a to refer to n. // Naddr rewrites a to refer to n.
// It assumes that a is zeroed on entry. // It assumes that a is zeroed on entry.
func Naddr(a *obj.Addr, n *Node) { func Naddr(a *obj.Addr, n *Node) {
......
...@@ -5,6 +5,7 @@ ...@@ -5,6 +5,7 @@
package gc package gc
import ( import (
"cmd/compile/internal/ssa"
"cmd/internal/obj" "cmd/internal/obj"
"cmd/internal/sys" "cmd/internal/sys"
"fmt" "fmt"
...@@ -93,6 +94,11 @@ func gvardefx(n *Node, as obj.As) { ...@@ -93,6 +94,11 @@ func gvardefx(n *Node, as obj.As) {
switch n.Class { switch n.Class {
case PAUTO, PPARAM, PPARAMOUT: case PAUTO, PPARAM, PPARAMOUT:
if !n.Used {
Prog(obj.ANOP)
return
}
if as == obj.AVARLIVE { if as == obj.AVARLIVE {
Gins(as, n, nil) Gins(as, n, nil)
} else { } else {
...@@ -214,15 +220,12 @@ func (s byStackVar) Len() int { return len(s) } ...@@ -214,15 +220,12 @@ func (s byStackVar) Len() int { return len(s) }
func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) } func (s byStackVar) Less(i, j int) bool { return cmpstackvarlt(s[i], s[j]) }
func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] } func (s byStackVar) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from. var scratchFpMem *Node
func allocauto(ptxt *obj.Prog) {
func (s *ssaExport) AllocFrame(f *ssa.Func) {
Stksize = 0 Stksize = 0
stkptrsize = 0 stkptrsize = 0
if len(Curfn.Func.Dcl) == 0 {
return
}
// Mark the PAUTO's unused. // Mark the PAUTO's unused.
for _, ln := range Curfn.Func.Dcl { for _, ln := range Curfn.Func.Dcl {
if ln.Class == PAUTO { if ln.Class == PAUTO {
...@@ -230,37 +233,60 @@ func allocauto(ptxt *obj.Prog) { ...@@ -230,37 +233,60 @@ func allocauto(ptxt *obj.Prog) {
} }
} }
markautoused(ptxt) for _, l := range f.RegAlloc {
if ls, ok := l.(ssa.LocalSlot); ok {
ls.N.(*Node).Used = true
}
sort.Sort(byStackVar(Curfn.Func.Dcl)) }
// Unused autos are at the end, chop 'em off. scratchUsed := false
n := Curfn.Func.Dcl[0] for _, b := range f.Blocks {
if n.Class == PAUTO && n.Op == ONAME && !n.Used { for _, v := range b.Values {
// No locals used at all switch a := v.Aux.(type) {
Curfn.Func.Dcl = nil case *ssa.ArgSymbol:
a.Node.(*Node).Used = true
case *ssa.AutoSymbol:
a.Node.(*Node).Used = true
}
fixautoused(ptxt) // TODO(mdempsky): Encode in opcodeTable
return // whether an Op requires scratch memory.
switch v.Op {
case ssa.Op386UCOMISS, ssa.Op386UCOMISD,
ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS,
ssa.Op386CVTSD2SS, ssa.Op386CVTSL2SS, ssa.Op386CVTSL2SD, ssa.Op386CVTTSD2SL, ssa.Op386CVTTSS2SL,
ssa.OpPPC64Xf2i64, ssa.OpPPC64Xi2f64:
scratchUsed = true
}
}
} }
for i := 1; i < len(Curfn.Func.Dcl); i++ { // To satisfy toolstash -cmp, preserve the unsorted
n = Curfn.Func.Dcl[i] // declaration order so we can emit the ATYPE instructions in
if n.Class == PAUTO && n.Op == ONAME && !n.Used { // the same order.
Curfn.Func.Dcl = Curfn.Func.Dcl[:i] // TODO(mdempsky): Remove in followup CL.
break Curfn.Func.UnsortedDcls = append([]*Node(nil), Curfn.Func.Dcl...)
}
if f.Config.NeedsFpScratch {
scratchFpMem = temp(Types[TUINT64])
scratchFpMem.Used = scratchUsed
} }
// Reassign stack offsets of the locals that are still there. sort.Sort(byStackVar(Curfn.Func.Dcl))
var w int64
for _, n := range Curfn.Func.Dcl { // Reassign stack offsets of the locals that are used.
if n.Class != PAUTO || n.Op != ONAME { for i, n := range Curfn.Func.Dcl {
if n.Op != ONAME || n.Class != PAUTO {
continue continue
} }
if !n.Used {
Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
break
}
dowidth(n.Type) dowidth(n.Type)
w = n.Type.Width w := n.Type.Width
if w >= Thearch.MAXWIDTH || w < 0 { if w >= Thearch.MAXWIDTH || w < 0 {
Fatalf("bad width") Fatalf("bad width")
} }
...@@ -282,8 +308,6 @@ func allocauto(ptxt *obj.Prog) { ...@@ -282,8 +308,6 @@ func allocauto(ptxt *obj.Prog) {
Stksize = Rnd(Stksize, int64(Widthreg)) Stksize = Rnd(Stksize, int64(Widthreg))
stkptrsize = Rnd(stkptrsize, int64(Widthreg)) stkptrsize = Rnd(stkptrsize, int64(Widthreg))
fixautoused(ptxt)
} }
func compile(fn *Node) { func compile(fn *Node) {
...@@ -408,12 +432,22 @@ func compile(fn *Node) { ...@@ -408,12 +432,22 @@ func compile(fn *Node) {
} }
} }
for _, n := range fn.Func.Dcl { for _, n := range fn.Func.UnsortedDcls {
if n.Op != ONAME { // might be OTYPE or OLITERAL if n.Op != ONAME { // might be OTYPE or OLITERAL
continue continue
} }
switch n.Class { switch n.Class {
case PAUTO, PPARAM, PPARAMOUT: case PAUTO:
if !n.Used {
// Hacks to appease toolstash -cmp.
// TODO(mdempsky): Remove in followup CL.
pcloc++
Pc.Pc++
Linksym(ngotype(n))
continue
}
fallthrough
case PPARAM, PPARAMOUT:
p := Gins(obj.ATYPE, n, nil) p := Gins(obj.ATYPE, n, nil)
p.From.Gotype = Linksym(ngotype(n)) p.From.Gotype = Linksym(ngotype(n))
} }
......
...@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) { ...@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit platforms _32bit uintptr // size on 32bit platforms
_64bit uintptr // size on 64bit platforms _64bit uintptr // size on 64bit platforms
}{ }{
{Func{}, 96, 168}, {Func{}, 108, 192}, // TODO(mdempsky): Change back to 96, 168 in followup CL.
{Name{}, 52, 80}, {Name{}, 52, 80},
{Node{}, 92, 144}, {Node{}, 92, 144},
{Sym{}, 60, 112}, {Sym{}, 60, 112},
......
...@@ -4083,9 +4083,9 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { ...@@ -4083,9 +4083,9 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
if Thearch.Use387 { if Thearch.Use387 {
s.SSEto387 = map[int16]int16{} s.SSEto387 = map[int16]int16{}
} }
if f.Config.NeedsFpScratch {
s.ScratchFpMem = temp(Types[TUINT64]) s.ScratchFpMem = scratchFpMem
} scratchFpMem = nil
// Emit basic blocks // Emit basic blocks
for i, b := range f.Blocks { for i, b := range f.Blocks {
...@@ -4171,9 +4171,6 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) { ...@@ -4171,9 +4171,6 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
} }
} }
// Allocate stack frame
allocauto(ptxt)
// Generate gc bitmaps. // Generate gc bitmaps.
liveness(Curfn, ptxt, gcargs, gclocals) liveness(Curfn, ptxt, gcargs, gclocals)
...@@ -4287,7 +4284,7 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) { ...@@ -4287,7 +4284,7 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
a.Name = obj.NAME_AUTO a.Name = obj.NAME_AUTO
a.Node = n a.Node = n
a.Sym = Linksym(n.Sym) a.Sym = Linksym(n.Sym)
// TODO: a.Offset += n.Xoffset once frame offsets for autos are computed during SSA a.Offset += n.Xoffset
default: default:
v.Fatalf("aux in %s not implemented %#v", v, v.Aux) v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
} }
...@@ -4409,6 +4406,28 @@ func AutoVar(v *ssa.Value) (*Node, int64) { ...@@ -4409,6 +4406,28 @@ func AutoVar(v *ssa.Value) (*Node, int64) {
return loc.N.(*Node), loc.Off return loc.N.(*Node), loc.Off
} }
func AddrAuto(a *obj.Addr, v *ssa.Value) {
n, off := AutoVar(v)
a.Type = obj.TYPE_MEM
a.Node = n
a.Sym = Linksym(n.Sym)
a.Offset = n.Xoffset + off
if n.Class == PPARAM || n.Class == PPARAMOUT {
a.Name = obj.NAME_PARAM
} else {
a.Name = obj.NAME_AUTO
}
}
func (s *SSAGenState) AddrScratch(a *obj.Addr) {
a.Type = obj.TYPE_MEM
a.Name = obj.NAME_AUTO
a.Node = s.ScratchFpMem
a.Sym = Linksym(s.ScratchFpMem.Sym)
a.Reg = int16(Thearch.REGSP)
a.Offset = s.ScratchFpMem.Xoffset
}
// fieldIdx finds the index of the field referred to by the ODOT node n. // fieldIdx finds the index of the field referred to by the ODOT node n.
func fieldIdx(n *Node) int { func fieldIdx(n *Node) int {
t := n.Left.Type t := n.Left.Type
......
...@@ -271,20 +271,21 @@ type Param struct { ...@@ -271,20 +271,21 @@ type Param struct {
// Func holds Node fields used only with function-like nodes. // Func holds Node fields used only with function-like nodes.
type Func struct { type Func struct {
Shortname *Node Shortname *Node
Enter Nodes // for example, allocate and initialize memory for escaping parameters Enter Nodes // for example, allocate and initialize memory for escaping parameters
Exit Nodes Exit Nodes
Cvars Nodes // closure params Cvars Nodes // closure params
Dcl []*Node // autodcl for this func/closure Dcl []*Node // autodcl for this func/closure
Inldcl Nodes // copy of dcl for use in inlining UnsortedDcls []*Node // autodcl for this func/closure
Closgen int Inldcl Nodes // copy of dcl for use in inlining
Outerfunc *Node // outer function (for closure) Closgen int
FieldTrack map[*Sym]struct{} Outerfunc *Node // outer function (for closure)
Ntype *Node // signature FieldTrack map[*Sym]struct{}
Top int // top context (Ecall, Eproc, etc) Ntype *Node // signature
Closure *Node // OCLOSURE <-> ODCLFUNC Top int // top context (Ecall, Eproc, etc)
FCurfn *Node Closure *Node // OCLOSURE <-> ODCLFUNC
Nname *Node FCurfn *Node
Nname *Node
Inl Nodes // copy of the body for use in inlining Inl Nodes // copy of the body for use in inlining
InlCost int32 InlCost int32
......
...@@ -129,17 +129,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -129,17 +129,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
} }
r := v.Reg() r := v.Reg()
p := gc.Prog(loadByType(v.Type, r)) p := gc.Prog(loadByType(v.Type, r))
n, off := gc.AutoVar(v.Args[0]) gc.AddrAuto(&p.From, v.Args[0])
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = r p.To.Reg = r
if isHILO(r) { if isHILO(r) {
...@@ -171,17 +161,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -171,17 +161,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type, r)) p := gc.Prog(storeByType(v.Type, r))
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = r p.From.Reg = r
n, off := gc.AutoVar(v) gc.AddrAuto(&p.To, v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
case ssa.OpMIPS64ADDV, case ssa.OpMIPS64ADDV,
ssa.OpMIPS64SUBV, ssa.OpMIPS64SUBV,
ssa.OpMIPS64AND, ssa.OpMIPS64AND,
......
...@@ -131,17 +131,6 @@ func storeByType(t ssa.Type) obj.As { ...@@ -131,17 +131,6 @@ func storeByType(t ssa.Type) obj.As {
panic("bad store type") panic("bad store type")
} }
// scratchFpMem initializes an Addr (field of a Prog)
// to reference the scratchpad memory for movement between
// F and G registers for FP conversions.
func scratchFpMem(s *gc.SSAGenState, a *obj.Addr) {
a.Type = obj.TYPE_MEM
a.Name = obj.NAME_AUTO
a.Node = s.ScratchFpMem
a.Sym = gc.Linksym(s.ScratchFpMem.Sym)
a.Reg = ppc64.REGSP
}
func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) { func ssaGenISEL(v *ssa.Value, cr int64, r1, r2 int16) {
r := v.Reg() r := v.Reg()
p := gc.Prog(ppc64.AISEL) p := gc.Prog(ppc64.AISEL)
...@@ -191,11 +180,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -191,11 +180,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(ppc64.AFMOVD) p := gc.Prog(ppc64.AFMOVD)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x p.From.Reg = x
scratchFpMem(s, &p.To) s.AddrScratch(&p.To)
p = gc.Prog(ppc64.AMOVD) p = gc.Prog(ppc64.AMOVD)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = y p.To.Reg = y
scratchFpMem(s, &p.From) s.AddrScratch(&p.From)
} }
case ssa.OpPPC64Xi2f64: case ssa.OpPPC64Xi2f64:
{ {
...@@ -204,11 +193,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -204,11 +193,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(ppc64.AMOVD) p := gc.Prog(ppc64.AMOVD)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x p.From.Reg = x
scratchFpMem(s, &p.To) s.AddrScratch(&p.To)
p = gc.Prog(ppc64.AFMOVD) p = gc.Prog(ppc64.AFMOVD)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = y p.To.Reg = y
scratchFpMem(s, &p.From) s.AddrScratch(&p.From)
} }
case ssa.OpPPC64LoweredGetClosurePtr: case ssa.OpPPC64LoweredGetClosurePtr:
...@@ -217,37 +206,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -217,37 +206,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpLoadReg: case ssa.OpLoadReg:
loadOp := loadByType(v.Type) loadOp := loadByType(v.Type)
n, off := gc.AutoVar(v.Args[0])
p := gc.Prog(loadOp) p := gc.Prog(loadOp)
p.From.Type = obj.TYPE_MEM gc.AddrAuto(&p.From, v.Args[0])
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpStoreReg: case ssa.OpStoreReg:
storeOp := storeByType(v.Type) storeOp := storeByType(v.Type)
n, off := gc.AutoVar(v)
p := gc.Prog(storeOp) p := gc.Prog(storeOp)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
p.To.Type = obj.TYPE_MEM gc.AddrAuto(&p.To, v)
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
case ssa.OpPPC64DIVD: case ssa.OpPPC64DIVD:
// For now, // For now,
......
...@@ -430,17 +430,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -430,17 +430,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return return
} }
p := gc.Prog(loadByType(v.Type)) p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(v.Args[0]) gc.AddrAuto(&p.From, v.Args[0])
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
case ssa.OpStoreReg: case ssa.OpStoreReg:
...@@ -451,17 +441,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -451,17 +441,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type)) p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(v) gc.AddrAuto(&p.To, v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
case ssa.OpPhi: case ssa.OpPhi:
gc.CheckLoweredPhi(v) gc.CheckLoweredPhi(v)
case ssa.OpInitMem: case ssa.OpInitMem:
......
...@@ -278,7 +278,8 @@ var passes = [...]pass{ ...@@ -278,7 +278,8 @@ var passes = [...]pass{
{name: "late nilcheck", fn: nilcheckelim2}, {name: "late nilcheck", fn: nilcheckelim2},
{name: "flagalloc", fn: flagalloc, required: true}, // allocate flags register {name: "flagalloc", fn: flagalloc, required: true}, // allocate flags register
{name: "regalloc", fn: regalloc, required: true}, // allocate int & float registers + stack slots {name: "regalloc", fn: regalloc, required: true}, // allocate int & float registers + stack slots
{name: "trim", fn: trim}, // remove empty blocks {name: "stackframe", fn: stackframe, required: true},
{name: "trim", fn: trim}, // remove empty blocks
} }
// Double-check phase ordering constraints. // Double-check phase ordering constraints.
...@@ -329,6 +330,8 @@ var passOrder = [...]constraint{ ...@@ -329,6 +330,8 @@ var passOrder = [...]constraint{
{"schedule", "flagalloc"}, {"schedule", "flagalloc"},
// regalloc needs flags to be allocated first. // regalloc needs flags to be allocated first.
{"flagalloc", "regalloc"}, {"flagalloc", "regalloc"},
// stackframe needs to know about spilled registers.
{"regalloc", "stackframe"},
// trim needs regalloc to be done first. // trim needs regalloc to be done first.
{"regalloc", "trim"}, {"regalloc", "trim"},
} }
......
...@@ -117,6 +117,9 @@ type Frontend interface { ...@@ -117,6 +117,9 @@ type Frontend interface {
// Line returns a string describing the given line number. // Line returns a string describing the given line number.
Line(int32) string Line(int32) string
// AllocFrame assigns frame offsets to all live auto variables.
AllocFrame(f *Func)
} }
// interface used to hold *gc.Node. We'd use *gc.Node directly but // interface used to hold *gc.Node. We'd use *gc.Node directly but
......
...@@ -61,6 +61,8 @@ func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot { ...@@ -61,6 +61,8 @@ func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
func (DummyFrontend) Line(line int32) string { func (DummyFrontend) Line(line int32) string {
return "unknown.go:0" return "unknown.go:0"
} }
func (DummyFrontend) AllocFrame(f *Func) {
}
func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) } func (d DummyFrontend) Logf(msg string, args ...interface{}) { d.t.Logf(msg, args...) }
func (d DummyFrontend) Log() bool { return true } func (d DummyFrontend) Log() bool { return true }
......
// Copyright 2016 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 ssa
// stackframe calls back into the frontend to assign frame offsets.
func stackframe(f *Func) {
f.Config.fe.AllocFrame(f)
}
...@@ -120,7 +120,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -120,7 +120,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
switch v.Op { switch v.Op {
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS: case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
p := gc.Prog(x86.AFSTCW) p := gc.Prog(x86.AFSTCW)
scratch387(s, &p.To) s.AddrScratch(&p.To)
p = gc.Prog(x86.AFLDCW) p = gc.Prog(x86.AFLDCW)
p.From.Type = obj.TYPE_MEM p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN p.From.Name = obj.NAME_EXTERN
...@@ -148,7 +148,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -148,7 +148,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
switch v.Op { switch v.Op {
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS: case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
p := gc.Prog(x86.AFLDCW) p := gc.Prog(x86.AFLDCW)
scratch387(s, &p.From) s.AddrScratch(&p.From)
} }
return true return true
...@@ -167,7 +167,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -167,7 +167,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p = gc.Prog(x86.AMOVL) p = gc.Prog(x86.AMOVL)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_AX p.From.Reg = x86.REG_AX
scratch387(s, &p.To) s.AddrScratch(&p.To)
// Move status word into AX. // Move status word into AX.
p = gc.Prog(x86.AFSTSW) p = gc.Prog(x86.AFSTSW)
...@@ -179,7 +179,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -179,7 +179,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
// Restore AX. // Restore AX.
p = gc.Prog(x86.AMOVL) p = gc.Prog(x86.AMOVL)
scratch387(s, &p.From) s.AddrScratch(&p.From)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_AX p.To.Reg = x86.REG_AX
...@@ -201,9 +201,9 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -201,9 +201,9 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p := gc.Prog(x86.AMOVL) p := gc.Prog(x86.AMOVL)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
scratch387(s, &p.To) s.AddrScratch(&p.To)
p = gc.Prog(x86.AFMOVL) p = gc.Prog(x86.AFMOVL)
scratch387(s, &p.From) s.AddrScratch(&p.From)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_F0 p.To.Reg = x86.REG_F0
popAndSave(s, v) popAndSave(s, v)
...@@ -214,7 +214,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -214,7 +214,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
// Save control word. // Save control word.
p := gc.Prog(x86.AFSTCW) p := gc.Prog(x86.AFSTCW)
scratch387(s, &p.To) s.AddrScratch(&p.To)
p.To.Offset += 4 p.To.Offset += 4
// Load control word which truncates (rounds towards zero). // Load control word which truncates (rounds towards zero).
...@@ -227,15 +227,15 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -227,15 +227,15 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p = gc.Prog(x86.AFMOVLP) p = gc.Prog(x86.AFMOVLP)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_F0 p.From.Reg = x86.REG_F0
scratch387(s, &p.To) s.AddrScratch(&p.To)
p = gc.Prog(x86.AMOVL) p = gc.Prog(x86.AMOVL)
scratch387(s, &p.From) s.AddrScratch(&p.From)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
// Restore control word. // Restore control word.
p = gc.Prog(x86.AFLDCW) p = gc.Prog(x86.AFLDCW)
scratch387(s, &p.From) s.AddrScratch(&p.From)
p.From.Offset += 4 p.From.Offset += 4
return true return true
...@@ -251,9 +251,9 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -251,9 +251,9 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p := gc.Prog(x86.AFMOVFP) p := gc.Prog(x86.AFMOVFP)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_F0 p.From.Reg = x86.REG_F0
scratch387(s, &p.To) s.AddrScratch(&p.To)
p = gc.Prog(x86.AFMOVF) p = gc.Prog(x86.AFMOVF)
scratch387(s, &p.From) s.AddrScratch(&p.From)
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_F0 p.To.Reg = x86.REG_F0
popAndSave(s, v) popAndSave(s, v)
...@@ -265,17 +265,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -265,17 +265,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
} }
// Load+push the value we need. // Load+push the value we need.
p := gc.Prog(loadPush(v.Type)) p := gc.Prog(loadPush(v.Type))
n, off := gc.AutoVar(v.Args[0]) gc.AddrAuto(&p.From, v.Args[0])
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_F0 p.To.Reg = x86.REG_F0
// Move the value to its assigned register. // Move the value to its assigned register.
...@@ -297,17 +287,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool { ...@@ -297,17 +287,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p := gc.Prog(op) p := gc.Prog(op)
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_F0 p.From.Reg = x86.REG_F0
n, off := gc.AutoVar(v) gc.AddrAuto(&p.To, v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
return true return true
case ssa.OpCopy: case ssa.OpCopy:
...@@ -375,12 +355,3 @@ func flush387(s *gc.SSAGenState) { ...@@ -375,12 +355,3 @@ func flush387(s *gc.SSAGenState) {
delete(s.SSEto387, k) delete(s.SSEto387, k)
} }
} }
// scratch387 initializes a to the scratch location used by some 387 rewrites.
func scratch387(s *gc.SSAGenState, a *obj.Addr) {
a.Type = obj.TYPE_MEM
a.Name = obj.NAME_AUTO
a.Node = s.ScratchFpMem
a.Sym = gc.Linksym(s.ScratchFpMem.Sym)
a.Reg = x86.REG_SP
}
...@@ -610,17 +610,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -610,17 +610,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return return
} }
p := gc.Prog(loadByType(v.Type)) p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(v.Args[0]) gc.AddrAuto(&p.From, v.Args[0])
p.From.Type = obj.TYPE_MEM
p.From.Node = n
p.From.Sym = gc.Linksym(n.Sym)
p.From.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.From.Name = obj.NAME_PARAM
p.From.Offset += n.Xoffset
} else {
p.From.Name = obj.NAME_AUTO
}
p.To.Type = obj.TYPE_REG p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg() p.To.Reg = v.Reg()
...@@ -632,17 +622,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) { ...@@ -632,17 +622,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type)) p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg() p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(v) gc.AddrAuto(&p.To, v)
p.To.Type = obj.TYPE_MEM
p.To.Node = n
p.To.Sym = gc.Linksym(n.Sym)
p.To.Offset = off
if n.Class == gc.PPARAM || n.Class == gc.PPARAMOUT {
p.To.Name = obj.NAME_PARAM
p.To.Offset += n.Xoffset
} else {
p.To.Name = obj.NAME_AUTO
}
case ssa.OpPhi: case ssa.OpPhi:
gc.CheckLoweredPhi(v) gc.CheckLoweredPhi(v)
case ssa.OpInitMem: case ssa.OpInitMem:
......
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