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()
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:
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:
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
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:
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,
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))
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) {
package gc
import (
+ "cmd/compile/internal/ssa"
"cmd/internal/obj"
"cmd/internal/sys"
"fmt"
switch n.Class {
case PAUTO, PPARAM, PPARAMOUT:
+ if !n.Used {
+ Prog(obj.ANOP)
+ return
+ }
+
if as == obj.AVARLIVE {
Gins(as, n, nil)
} else {
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 {
}
}
- 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")
}
Stksize = Rnd(Stksize, int64(Widthreg))
stkptrsize = Rnd(stkptrsize, int64(Widthreg))
-
- fixautoused(ptxt)
}
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))
}
_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},
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 {
}
}
- // Allocate stack frame
- allocauto(ptxt)
-
// Generate gc bitmaps.
liveness(Curfn, ptxt, gcargs, gclocals)
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)
}
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
// 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
}
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) {
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,
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)
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:
{
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:
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,
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:
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:
{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.
{"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"},
}
// 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
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 }
--- /dev/null
+// 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)
+}
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
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
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)
// 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
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)
// 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).
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
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)
}
// 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.
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:
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
-}
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()
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: