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) {
return
}
p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
......@@ -691,17 +681,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.To, v)
case ssa.OpPhi:
gc.CheckLoweredPhi(v)
case ssa.OpInitMem:
......
......@@ -162,17 +162,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return
}
p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
case ssa.OpPhi:
......@@ -185,17 +175,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.To, v)
case ssa.OpARMUDIVrtcall:
p := gc.Prog(obj.ACALL)
p.To.Type = obj.TYPE_MEM
......
......@@ -136,17 +136,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return
}
p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
case ssa.OpPhi:
......@@ -159,17 +149,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.To, v)
case ssa.OpARM64ADD,
ssa.OpARM64SUB,
ssa.OpARM64AND,
......
......@@ -75,40 +75,6 @@ func Appendpp(p *obj.Prog, as obj.As, ftype obj.AddrType, freg int16, foffset in
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) {
s := Linksym(nam.Sym)
s.Gotype = Linksym(ngotype(nam))
......@@ -153,23 +119,6 @@ func isfat(t *Type) bool {
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.
// It assumes that a is zeroed on entry.
func Naddr(a *obj.Addr, n *Node) {
......
......@@ -5,6 +5,7 @@
package gc
import (
"cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/sys"
"fmt"
......@@ -93,6 +94,11 @@ func gvardefx(n *Node, as obj.As) {
switch n.Class {
case PAUTO, PPARAM, PPARAMOUT:
if !n.Used {
Prog(obj.ANOP)
return
}
if as == obj.AVARLIVE {
Gins(as, n, nil)
} else {
......@@ -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) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
// TODO(lvd) find out where the PAUTO/OLITERAL nodes come from.
func allocauto(ptxt *obj.Prog) {
var scratchFpMem *Node
func (s *ssaExport) AllocFrame(f *ssa.Func) {
Stksize = 0
stkptrsize = 0
if len(Curfn.Func.Dcl) == 0 {
return
}
// Mark the PAUTO's unused.
for _, ln := range Curfn.Func.Dcl {
if ln.Class == PAUTO {
......@@ -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.
n := Curfn.Func.Dcl[0]
if n.Class == PAUTO && n.Op == ONAME && !n.Used {
// No locals used at all
Curfn.Func.Dcl = nil
scratchUsed := false
for _, b := range f.Blocks {
for _, v := range b.Values {
switch a := v.Aux.(type) {
case *ssa.ArgSymbol:
a.Node.(*Node).Used = true
case *ssa.AutoSymbol:
a.Node.(*Node).Used = true
}
fixautoused(ptxt)
return
// TODO(mdempsky): Encode in opcodeTable
// 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++ {
n = Curfn.Func.Dcl[i]
if n.Class == PAUTO && n.Op == ONAME && !n.Used {
Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
break
}
// To satisfy toolstash -cmp, preserve the unsorted
// declaration order so we can emit the ATYPE instructions in
// the same order.
// TODO(mdempsky): Remove in followup CL.
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.
var w int64
for _, n := range Curfn.Func.Dcl {
if n.Class != PAUTO || n.Op != ONAME {
sort.Sort(byStackVar(Curfn.Func.Dcl))
// Reassign stack offsets of the locals that are used.
for i, n := range Curfn.Func.Dcl {
if n.Op != ONAME || n.Class != PAUTO {
continue
}
if !n.Used {
Curfn.Func.Dcl = Curfn.Func.Dcl[:i]
break
}
dowidth(n.Type)
w = n.Type.Width
w := n.Type.Width
if w >= Thearch.MAXWIDTH || w < 0 {
Fatalf("bad width")
}
......@@ -282,8 +308,6 @@ func allocauto(ptxt *obj.Prog) {
Stksize = Rnd(Stksize, int64(Widthreg))
stkptrsize = Rnd(stkptrsize, int64(Widthreg))
fixautoused(ptxt)
}
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
continue
}
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.From.Gotype = Linksym(ngotype(n))
}
......
......@@ -22,7 +22,7 @@ func TestSizeof(t *testing.T) {
_32bit uintptr // size on 32bit 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},
{Node{}, 92, 144},
{Sym{}, 60, 112},
......
......@@ -4083,9 +4083,9 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
if Thearch.Use387 {
s.SSEto387 = map[int16]int16{}
}
if f.Config.NeedsFpScratch {
s.ScratchFpMem = temp(Types[TUINT64])
}
s.ScratchFpMem = scratchFpMem
scratchFpMem = nil
// Emit basic blocks
for i, b := range f.Blocks {
......@@ -4171,9 +4171,6 @@ func genssa(f *ssa.Func, ptxt *obj.Prog, gcargs, gclocals *Sym) {
}
}
// Allocate stack frame
allocauto(ptxt)
// Generate gc bitmaps.
liveness(Curfn, ptxt, gcargs, gclocals)
......@@ -4287,7 +4284,7 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
a.Name = obj.NAME_AUTO
a.Node = n
a.Sym = Linksym(n.Sym)
// TODO: a.Offset += n.Xoffset once frame offsets for autos are computed during SSA
a.Offset += n.Xoffset
default:
v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
}
......@@ -4409,6 +4406,28 @@ func AutoVar(v *ssa.Value) (*Node, int64) {
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.
func fieldIdx(n *Node) int {
t := n.Left.Type
......
......@@ -271,20 +271,21 @@ type Param struct {
// Func holds Node fields used only with function-like nodes.
type Func struct {
Shortname *Node
Enter Nodes // for example, allocate and initialize memory for escaping parameters
Exit Nodes
Cvars Nodes // closure params
Dcl []*Node // autodcl for this func/closure
Inldcl Nodes // copy of dcl for use in inlining
Closgen int
Outerfunc *Node // outer function (for closure)
FieldTrack map[*Sym]struct{}
Ntype *Node // signature
Top int // top context (Ecall, Eproc, etc)
Closure *Node // OCLOSURE <-> ODCLFUNC
FCurfn *Node
Nname *Node
Shortname *Node
Enter Nodes // for example, allocate and initialize memory for escaping parameters
Exit Nodes
Cvars Nodes // closure params
Dcl []*Node // autodcl for this func/closure
UnsortedDcls []*Node // autodcl for this func/closure
Inldcl Nodes // copy of dcl for use in inlining
Closgen int
Outerfunc *Node // outer function (for closure)
FieldTrack map[*Sym]struct{}
Ntype *Node // signature
Top int // top context (Ecall, Eproc, etc)
Closure *Node // OCLOSURE <-> ODCLFUNC
FCurfn *Node
Nname *Node
Inl Nodes // copy of the body for use in inlining
InlCost int32
......
......@@ -129,17 +129,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
}
r := v.Reg()
p := gc.Prog(loadByType(v.Type, r))
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = r
if isHILO(r) {
......@@ -171,17 +161,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type, r))
p.From.Type = obj.TYPE_REG
p.From.Reg = r
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.To, v)
case ssa.OpMIPS64ADDV,
ssa.OpMIPS64SUBV,
ssa.OpMIPS64AND,
......
......@@ -131,17 +131,6 @@ func storeByType(t ssa.Type) obj.As {
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) {
r := v.Reg()
p := gc.Prog(ppc64.AISEL)
......@@ -191,11 +180,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(ppc64.AFMOVD)
p.From.Type = obj.TYPE_REG
p.From.Reg = x
scratchFpMem(s, &p.To)
s.AddrScratch(&p.To)
p = gc.Prog(ppc64.AMOVD)
p.To.Type = obj.TYPE_REG
p.To.Reg = y
scratchFpMem(s, &p.From)
s.AddrScratch(&p.From)
}
case ssa.OpPPC64Xi2f64:
{
......@@ -204,11 +193,11 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(ppc64.AMOVD)
p.From.Type = obj.TYPE_REG
p.From.Reg = x
scratchFpMem(s, &p.To)
s.AddrScratch(&p.To)
p = gc.Prog(ppc64.AFMOVD)
p.To.Type = obj.TYPE_REG
p.To.Reg = y
scratchFpMem(s, &p.From)
s.AddrScratch(&p.From)
}
case ssa.OpPPC64LoweredGetClosurePtr:
......@@ -217,37 +206,17 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
case ssa.OpLoadReg:
loadOp := loadByType(v.Type)
n, off := gc.AutoVar(v.Args[0])
p := gc.Prog(loadOp)
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
}
gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
case ssa.OpStoreReg:
storeOp := storeByType(v.Type)
n, off := gc.AutoVar(v)
p := gc.Prog(storeOp)
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
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
}
gc.AddrAuto(&p.To, v)
case ssa.OpPPC64DIVD:
// For now,
......
......@@ -430,17 +430,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
return
}
p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
case ssa.OpStoreReg:
......@@ -451,17 +441,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.To, v)
case ssa.OpPhi:
gc.CheckLoweredPhi(v)
case ssa.OpInitMem:
......
......@@ -278,7 +278,8 @@ var passes = [...]pass{
{name: "late nilcheck", fn: nilcheckelim2},
{name: "flagalloc", fn: flagalloc, required: true}, // allocate flags register
{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.
......@@ -329,6 +330,8 @@ var passOrder = [...]constraint{
{"schedule", "flagalloc"},
// regalloc needs flags to be allocated first.
{"flagalloc", "regalloc"},
// stackframe needs to know about spilled registers.
{"regalloc", "stackframe"},
// trim needs regalloc to be done first.
{"regalloc", "trim"},
}
......
......@@ -117,6 +117,9 @@ type Frontend interface {
// Line returns a string describing the given line number.
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
......
......@@ -61,6 +61,8 @@ func (d DummyFrontend) SplitStruct(s LocalSlot, i int) LocalSlot {
func (DummyFrontend) Line(line int32) string {
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) 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 {
switch v.Op {
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
p := gc.Prog(x86.AFSTCW)
scratch387(s, &p.To)
s.AddrScratch(&p.To)
p = gc.Prog(x86.AFLDCW)
p.From.Type = obj.TYPE_MEM
p.From.Name = obj.NAME_EXTERN
......@@ -148,7 +148,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
switch v.Op {
case ssa.Op386ADDSS, ssa.Op386SUBSS, ssa.Op386MULSS, ssa.Op386DIVSS:
p := gc.Prog(x86.AFLDCW)
scratch387(s, &p.From)
s.AddrScratch(&p.From)
}
return true
......@@ -167,7 +167,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p = gc.Prog(x86.AMOVL)
p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_AX
scratch387(s, &p.To)
s.AddrScratch(&p.To)
// Move status word into AX.
p = gc.Prog(x86.AFSTSW)
......@@ -179,7 +179,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
// Restore AX.
p = gc.Prog(x86.AMOVL)
scratch387(s, &p.From)
s.AddrScratch(&p.From)
p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_AX
......@@ -201,9 +201,9 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p := gc.Prog(x86.AMOVL)
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
scratch387(s, &p.To)
s.AddrScratch(&p.To)
p = gc.Prog(x86.AFMOVL)
scratch387(s, &p.From)
s.AddrScratch(&p.From)
p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_F0
popAndSave(s, v)
......@@ -214,7 +214,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
// Save control word.
p := gc.Prog(x86.AFSTCW)
scratch387(s, &p.To)
s.AddrScratch(&p.To)
p.To.Offset += 4
// Load control word which truncates (rounds towards zero).
......@@ -227,15 +227,15 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p = gc.Prog(x86.AFMOVLP)
p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_F0
scratch387(s, &p.To)
s.AddrScratch(&p.To)
p = gc.Prog(x86.AMOVL)
scratch387(s, &p.From)
s.AddrScratch(&p.From)
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
// Restore control word.
p = gc.Prog(x86.AFLDCW)
scratch387(s, &p.From)
s.AddrScratch(&p.From)
p.From.Offset += 4
return true
......@@ -251,9 +251,9 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p := gc.Prog(x86.AFMOVFP)
p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_F0
scratch387(s, &p.To)
s.AddrScratch(&p.To)
p = gc.Prog(x86.AFMOVF)
scratch387(s, &p.From)
s.AddrScratch(&p.From)
p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_F0
popAndSave(s, v)
......@@ -265,17 +265,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
}
// Load+push the value we need.
p := gc.Prog(loadPush(v.Type))
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = x86.REG_F0
// Move the value to its assigned register.
......@@ -297,17 +287,7 @@ func ssaGenValue387(s *gc.SSAGenState, v *ssa.Value) bool {
p := gc.Prog(op)
p.From.Type = obj.TYPE_REG
p.From.Reg = x86.REG_F0
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.To, v)
return true
case ssa.OpCopy:
......@@ -375,12 +355,3 @@ func flush387(s *gc.SSAGenState) {
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) {
return
}
p := gc.Prog(loadByType(v.Type))
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.From, v.Args[0])
p.To.Type = obj.TYPE_REG
p.To.Reg = v.Reg()
......@@ -632,17 +622,7 @@ func ssaGenValue(s *gc.SSAGenState, v *ssa.Value) {
p := gc.Prog(storeByType(v.Type))
p.From.Type = obj.TYPE_REG
p.From.Reg = v.Args[0].Reg()
n, off := gc.AutoVar(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
}
gc.AddrAuto(&p.To, v)
case ssa.OpPhi:
gc.CheckLoweredPhi(v)
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