mirror of
https://github.com/golang/go
synced 2024-11-11 20:01:37 -07:00
Revert "cmd/compile: spill output parameters passed in registers as autos"
This reverts commit 8ed438c077
, CL 300749.
Reason for revert: Looks like it crashes on link-register architectures
Change-Id: I0c261df58900008cada3359889d2a87508158447
Reviewed-on: https://go-review.googlesource.com/c/go/+/302053
Reviewed-by: Michael Knyszek <mknyszek@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
8ed438c077
commit
e61c9ddb7f
@ -69,14 +69,6 @@ func (a *ABIParamResultInfo) SpillAreaSize() int64 {
|
|||||||
return a.spillAreaSize
|
return a.spillAreaSize
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArgWidth returns the amount of stack needed for all the inputs
|
|
||||||
// and outputs of a function or method, including ABI-defined parameter
|
|
||||||
// slots and ABI-defined spill slots for register-resident parameters.
|
|
||||||
// The name is inherited from (*Type).ArgWidth(), which it replaces.
|
|
||||||
func (a *ABIParamResultInfo) ArgWidth() int64 {
|
|
||||||
return a.spillAreaSize + a.offsetToSpillArea
|
|
||||||
}
|
|
||||||
|
|
||||||
// RegIndex stores the index into the set of machine registers used by
|
// RegIndex stores the index into the set of machine registers used by
|
||||||
// the ABI on a specific architecture for parameter passing. RegIndex
|
// the ABI on a specific architecture for parameter passing. RegIndex
|
||||||
// values 0 through N-1 (where N is the number of integer registers
|
// values 0 through N-1 (where N is the number of integer registers
|
||||||
@ -422,25 +414,20 @@ func (config *ABIConfig) ABIAnalyzeFuncType(ft *types.Func) *ABIParamResultInfo
|
|||||||
|
|
||||||
// ABIAnalyze returns the same result as ABIAnalyzeFuncType, but also
|
// ABIAnalyze returns the same result as ABIAnalyzeFuncType, but also
|
||||||
// updates the offsets of all the receiver, input, and output fields.
|
// updates the offsets of all the receiver, input, and output fields.
|
||||||
// If setNname is true, it also sets the FrameOffset of the Nname for
|
func (config *ABIConfig) ABIAnalyze(t *types.Type) *ABIParamResultInfo {
|
||||||
// the field(s); this is for use when compiling a function and figuring out
|
|
||||||
// spill locations. Doing this for callers can cause races for register
|
|
||||||
// outputs because their frame location transitions from BOGUS_FUNARG_OFFSET
|
|
||||||
// to zero to an as-if-AUTO offset that has no use for callers.
|
|
||||||
func (config *ABIConfig) ABIAnalyze(t *types.Type, setNname bool) *ABIParamResultInfo {
|
|
||||||
ft := t.FuncType()
|
ft := t.FuncType()
|
||||||
result := config.ABIAnalyzeFuncType(ft)
|
result := config.ABIAnalyzeFuncType(ft)
|
||||||
// Fill in the frame offsets for receiver, inputs, results
|
// Fill in the frame offsets for receiver, inputs, results
|
||||||
k := 0
|
k := 0
|
||||||
if t.NumRecvs() != 0 {
|
if t.NumRecvs() != 0 {
|
||||||
config.updateOffset(result, ft.Receiver.FieldSlice()[0], result.inparams[0], false, setNname)
|
config.updateOffset(result, ft.Receiver.FieldSlice()[0], result.inparams[0], false)
|
||||||
k++
|
k++
|
||||||
}
|
}
|
||||||
for i, f := range ft.Params.FieldSlice() {
|
for i, f := range ft.Params.FieldSlice() {
|
||||||
config.updateOffset(result, f, result.inparams[k+i], false, setNname)
|
config.updateOffset(result, f, result.inparams[k+i], false)
|
||||||
}
|
}
|
||||||
for i, f := range ft.Results.FieldSlice() {
|
for i, f := range ft.Results.FieldSlice() {
|
||||||
config.updateOffset(result, f, result.outparams[i], true, setNname)
|
config.updateOffset(result, f, result.outparams[i], true)
|
||||||
}
|
}
|
||||||
return result
|
return result
|
||||||
}
|
}
|
||||||
@ -455,7 +442,7 @@ func FieldOffsetOf(f *types.Field) int64 {
|
|||||||
return f.Offset
|
return f.Offset
|
||||||
}
|
}
|
||||||
|
|
||||||
func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn, setNname bool) {
|
func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field, a ABIParamAssignment, isReturn bool) {
|
||||||
// Everything except return values in registers has either a frame home (if not in a register) or a frame spill location.
|
// Everything except return values in registers has either a frame home (if not in a register) or a frame spill location.
|
||||||
if !isReturn || len(a.Registers) == 0 {
|
if !isReturn || len(a.Registers) == 0 {
|
||||||
// The type frame offset DOES NOT show effects of minimum frame size.
|
// The type frame offset DOES NOT show effects of minimum frame size.
|
||||||
@ -468,19 +455,11 @@ func (config *ABIConfig) updateOffset(result *ABIParamResultInfo, f *types.Field
|
|||||||
// Set the Offset the first time. After that, we may recompute it, but it should never change.
|
// Set the Offset the first time. After that, we may recompute it, but it should never change.
|
||||||
f.Offset = off
|
f.Offset = off
|
||||||
if f.Nname != nil {
|
if f.Nname != nil {
|
||||||
// always set it in this case.
|
|
||||||
f.Nname.(*ir.Name).SetFrameOffset(off)
|
f.Nname.(*ir.Name).SetFrameOffset(off)
|
||||||
f.Nname.(*ir.Name).SetIsOutputParamInRegisters(false)
|
|
||||||
}
|
}
|
||||||
} else if fOffset != off {
|
} else if fOffset != off {
|
||||||
panic(fmt.Errorf("Offset changed from %d to %d", fOffset, off))
|
panic(fmt.Errorf("Offset changed from %d to %d", fOffset, off))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
if setNname && f.Nname != nil {
|
|
||||||
fname := f.Nname.(*ir.Name)
|
|
||||||
fname.SetIsOutputParamInRegisters(true)
|
|
||||||
fname.SetFrameOffset(0)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -265,13 +265,6 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
|
|||||||
var offs int64
|
var offs int64
|
||||||
|
|
||||||
switch n.Class {
|
switch n.Class {
|
||||||
case ir.PPARAM, ir.PPARAMOUT:
|
|
||||||
if !n.IsOutputParamInRegisters() {
|
|
||||||
abbrev = dwarf.DW_ABRV_PARAM
|
|
||||||
offs = n.FrameOffset() + base.Ctxt.FixedFrameSize()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough
|
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
offs = n.FrameOffset()
|
offs = n.FrameOffset()
|
||||||
abbrev = dwarf.DW_ABRV_AUTO
|
abbrev = dwarf.DW_ABRV_AUTO
|
||||||
@ -282,6 +275,9 @@ func createSimpleVar(fnsym *obj.LSym, n *ir.Name) *dwarf.Var {
|
|||||||
offs -= int64(types.PtrSize)
|
offs -= int64(types.PtrSize)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
case ir.PPARAM, ir.PPARAMOUT:
|
||||||
|
abbrev = dwarf.DW_ABRV_PARAM
|
||||||
|
offs = n.FrameOffset() + base.Ctxt.FixedFrameSize()
|
||||||
default:
|
default:
|
||||||
base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class, n)
|
base.Fatalf("createSimpleVar unexpected class %v for node %v", n.Class, n)
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ func enqueueFunc(fn *ir.Func) {
|
|||||||
ssagen.InitLSym(fn, false)
|
ssagen.InitLSym(fn, false)
|
||||||
types.CalcSize(fn.Type()) // TODO register args; remove this once all is done by abiutils
|
types.CalcSize(fn.Type()) // TODO register args; remove this once all is done by abiutils
|
||||||
a := ssagen.AbiForFunc(fn)
|
a := ssagen.AbiForFunc(fn)
|
||||||
a.ABIAnalyze(fn.Type(), true) // will set parameter spill/home locations correctly
|
a.ABIAnalyze(fn.Type()) // will set parameter spill/home locations correctly
|
||||||
liveness.WriteFuncMap(fn)
|
liveness.WriteFuncMap(fn)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -246,47 +246,44 @@ func (n *Name) Alias() bool { return n.flags&nameAlias != 0 }
|
|||||||
func (n *Name) SetAlias(alias bool) { n.flags.set(nameAlias, alias) }
|
func (n *Name) SetAlias(alias bool) { n.flags.set(nameAlias, alias) }
|
||||||
|
|
||||||
const (
|
const (
|
||||||
nameReadonly = 1 << iota
|
nameReadonly = 1 << iota
|
||||||
nameByval // is the variable captured by value or by reference
|
nameByval // is the variable captured by value or by reference
|
||||||
nameNeedzero // if it contains pointers, needs to be zeroed on function entry
|
nameNeedzero // if it contains pointers, needs to be zeroed on function entry
|
||||||
nameAutoTemp // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
|
nameAutoTemp // is the variable a temporary (implies no dwarf info. reset if escapes to heap)
|
||||||
nameUsed // for variable declared and not used error
|
nameUsed // for variable declared and not used error
|
||||||
nameIsClosureVar // PAUTOHEAP closure pseudo-variable; original (if any) at n.Defn
|
nameIsClosureVar // PAUTOHEAP closure pseudo-variable; original (if any) at n.Defn
|
||||||
nameIsOutputParamHeapAddr // pointer to a result parameter's heap copy
|
nameIsOutputParamHeapAddr // pointer to a result parameter's heap copy
|
||||||
nameIsOutputParamInRegisters // output parameter in registers spills as an auto
|
nameAddrtaken // address taken, even if not moved to heap
|
||||||
nameAddrtaken // address taken, even if not moved to heap
|
nameInlFormal // PAUTO created by inliner, derived from callee formal
|
||||||
nameInlFormal // PAUTO created by inliner, derived from callee formal
|
nameInlLocal // PAUTO created by inliner, derived from callee local
|
||||||
nameInlLocal // PAUTO created by inliner, derived from callee local
|
nameOpenDeferSlot // if temporary var storing info for open-coded defers
|
||||||
nameOpenDeferSlot // if temporary var storing info for open-coded defers
|
nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
|
||||||
nameLibfuzzerExtraCounter // if PEXTERN should be assigned to __libfuzzer_extra_counters section
|
nameAlias // is type name an alias
|
||||||
nameAlias // is type name an alias
|
|
||||||
)
|
)
|
||||||
|
|
||||||
func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 }
|
func (n *Name) Readonly() bool { return n.flags&nameReadonly != 0 }
|
||||||
func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 }
|
func (n *Name) Needzero() bool { return n.flags&nameNeedzero != 0 }
|
||||||
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
|
func (n *Name) AutoTemp() bool { return n.flags&nameAutoTemp != 0 }
|
||||||
func (n *Name) Used() bool { return n.flags&nameUsed != 0 }
|
func (n *Name) Used() bool { return n.flags&nameUsed != 0 }
|
||||||
func (n *Name) IsClosureVar() bool { return n.flags&nameIsClosureVar != 0 }
|
func (n *Name) IsClosureVar() bool { return n.flags&nameIsClosureVar != 0 }
|
||||||
func (n *Name) IsOutputParamHeapAddr() bool { return n.flags&nameIsOutputParamHeapAddr != 0 }
|
func (n *Name) IsOutputParamHeapAddr() bool { return n.flags&nameIsOutputParamHeapAddr != 0 }
|
||||||
func (n *Name) IsOutputParamInRegisters() bool { return n.flags&nameIsOutputParamInRegisters != 0 }
|
func (n *Name) Addrtaken() bool { return n.flags&nameAddrtaken != 0 }
|
||||||
func (n *Name) Addrtaken() bool { return n.flags&nameAddrtaken != 0 }
|
func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0 }
|
||||||
func (n *Name) InlFormal() bool { return n.flags&nameInlFormal != 0 }
|
func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 }
|
||||||
func (n *Name) InlLocal() bool { return n.flags&nameInlLocal != 0 }
|
func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 }
|
||||||
func (n *Name) OpenDeferSlot() bool { return n.flags&nameOpenDeferSlot != 0 }
|
func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 }
|
||||||
func (n *Name) LibfuzzerExtraCounter() bool { return n.flags&nameLibfuzzerExtraCounter != 0 }
|
|
||||||
|
|
||||||
func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) }
|
func (n *Name) setReadonly(b bool) { n.flags.set(nameReadonly, b) }
|
||||||
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
|
func (n *Name) SetNeedzero(b bool) { n.flags.set(nameNeedzero, b) }
|
||||||
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
|
func (n *Name) SetAutoTemp(b bool) { n.flags.set(nameAutoTemp, b) }
|
||||||
func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
|
func (n *Name) SetUsed(b bool) { n.flags.set(nameUsed, b) }
|
||||||
func (n *Name) SetIsClosureVar(b bool) { n.flags.set(nameIsClosureVar, b) }
|
func (n *Name) SetIsClosureVar(b bool) { n.flags.set(nameIsClosureVar, b) }
|
||||||
func (n *Name) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nameIsOutputParamHeapAddr, b) }
|
func (n *Name) SetIsOutputParamHeapAddr(b bool) { n.flags.set(nameIsOutputParamHeapAddr, b) }
|
||||||
func (n *Name) SetIsOutputParamInRegisters(b bool) { n.flags.set(nameIsOutputParamInRegisters, b) }
|
func (n *Name) SetAddrtaken(b bool) { n.flags.set(nameAddrtaken, b) }
|
||||||
func (n *Name) SetAddrtaken(b bool) { n.flags.set(nameAddrtaken, b) }
|
func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b) }
|
||||||
func (n *Name) SetInlFormal(b bool) { n.flags.set(nameInlFormal, b) }
|
func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) }
|
||||||
func (n *Name) SetInlLocal(b bool) { n.flags.set(nameInlLocal, b) }
|
func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) }
|
||||||
func (n *Name) SetOpenDeferSlot(b bool) { n.flags.set(nameOpenDeferSlot, b) }
|
func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) }
|
||||||
func (n *Name) SetLibfuzzerExtraCounter(b bool) { n.flags.set(nameLibfuzzerExtraCounter, b) }
|
|
||||||
|
|
||||||
// OnStack reports whether variable n may reside on the stack.
|
// OnStack reports whether variable n may reside on the stack.
|
||||||
func (n *Name) OnStack() bool {
|
func (n *Name) OnStack() bool {
|
||||||
|
@ -405,17 +405,11 @@ func (lv *liveness) pointerMap(liveout bitvec.BitVec, vars []*ir.Name, args, loc
|
|||||||
}
|
}
|
||||||
node := vars[i]
|
node := vars[i]
|
||||||
switch node.Class {
|
switch node.Class {
|
||||||
case ir.PPARAM, ir.PPARAMOUT:
|
|
||||||
if !node.IsOutputParamInRegisters() {
|
|
||||||
if node.FrameOffset() < 0 {
|
|
||||||
lv.f.Fatalf("Node %v has frameoffset %d\n", node.Sym().Name, node.FrameOffset())
|
|
||||||
}
|
|
||||||
typebits.Set(node.Type(), node.FrameOffset(), args)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough // PPARAMOUT in registers acts memory-allocates like an AUTO
|
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
typebits.Set(node.Type(), node.FrameOffset()+lv.stkptrsize, locals)
|
typebits.Set(node.Type(), node.FrameOffset()+lv.stkptrsize, locals)
|
||||||
|
|
||||||
|
case ir.PPARAM, ir.PPARAMOUT:
|
||||||
|
typebits.Set(node.Type(), node.FrameOffset(), args)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1089,10 +1083,8 @@ func (lv *liveness) emit() (argsSym, liveSym *obj.LSym) {
|
|||||||
for _, n := range lv.vars {
|
for _, n := range lv.vars {
|
||||||
switch n.Class {
|
switch n.Class {
|
||||||
case ir.PPARAM, ir.PPARAMOUT:
|
case ir.PPARAM, ir.PPARAMOUT:
|
||||||
if !n.IsOutputParamInRegisters() {
|
if maxArgNode == nil || n.FrameOffset() > maxArgNode.FrameOffset() {
|
||||||
if maxArgNode == nil || n.FrameOffset() > maxArgNode.FrameOffset() {
|
maxArgNode = n
|
||||||
maxArgNode = n
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1290,7 +1282,6 @@ func isfat(t *types.Type) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO THIS IS ALL WRONG AND NEEDS TO USE ABI.
|
|
||||||
func WriteFuncMap(fn *ir.Func) {
|
func WriteFuncMap(fn *ir.Func) {
|
||||||
if ir.FuncName(fn) == "_" || fn.Sym().Linkname != "" {
|
if ir.FuncName(fn) == "_" || fn.Sym().Linkname != "" {
|
||||||
return
|
return
|
||||||
|
@ -191,16 +191,6 @@ func archRegForAbiReg(r abi.RegIndex, c *Config) uint8 {
|
|||||||
return uint8(m)
|
return uint8(m)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ArgWidth returns the amount of stack needed for all the inputs
|
|
||||||
// and outputs of a function or method, including ABI-defined parameter
|
|
||||||
// slots and ABI-defined spill slots for register-resident parameters.
|
|
||||||
//
|
|
||||||
// The name is taken from the types package's ArgWidth(<function type>),
|
|
||||||
// which predated changes to the ABI; this version handles those changes.
|
|
||||||
func (a *AuxCall) ArgWidth() int64 {
|
|
||||||
return a.abiInfo.ArgWidth()
|
|
||||||
}
|
|
||||||
|
|
||||||
// OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc).
|
// OffsetOfResult returns the SP offset of result which (indexed 0, 1, etc).
|
||||||
func (a *AuxCall) ParamAssignmentForResult(which int64) *abi.ABIParamAssignment {
|
func (a *AuxCall) ParamAssignmentForResult(which int64) *abi.ABIParamAssignment {
|
||||||
return a.abiInfo.OutParam(int(which))
|
return a.abiInfo.OutParam(int(which))
|
||||||
|
@ -104,9 +104,7 @@ func (s *ssafn) AllocFrame(f *ssa.Func) {
|
|||||||
// Reassign stack offsets of the locals that are used.
|
// Reassign stack offsets of the locals that are used.
|
||||||
lastHasPtr := false
|
lastHasPtr := false
|
||||||
for i, n := range fn.Dcl {
|
for i, n := range fn.Dcl {
|
||||||
if n.Op() != ir.ONAME || n.Class != ir.PAUTO && !(n.Class == ir.PPARAMOUT && n.IsOutputParamInRegisters()) {
|
if n.Op() != ir.ONAME || n.Class != ir.PAUTO {
|
||||||
// i.e., stack assign if AUTO, or if PARAMOUT in registers (which has no predefined spill locations)
|
|
||||||
// TODO figure out when we don't need to spill output params.
|
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
if !n.Used() {
|
if !n.Used() {
|
||||||
@ -150,9 +148,9 @@ const maxStackSize = 1 << 30
|
|||||||
func Compile(fn *ir.Func, worker int) {
|
func Compile(fn *ir.Func, worker int) {
|
||||||
f := buildssa(fn, worker)
|
f := buildssa(fn, worker)
|
||||||
// Note: check arg size to fix issue 25507.
|
// Note: check arg size to fix issue 25507.
|
||||||
if f.Frontend().(*ssafn).stksize >= maxStackSize || f.OwnAux.ArgWidth() >= maxStackSize {
|
if f.Frontend().(*ssafn).stksize >= maxStackSize || fn.Type().ArgWidth() >= maxStackSize {
|
||||||
largeStackFramesMu.Lock()
|
largeStackFramesMu.Lock()
|
||||||
largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: f.OwnAux.ArgWidth(), pos: fn.Pos()})
|
largeStackFrames = append(largeStackFrames, largeStack{locals: f.Frontend().(*ssafn).stksize, args: fn.Type().ArgWidth(), pos: fn.Pos()})
|
||||||
largeStackFramesMu.Unlock()
|
largeStackFramesMu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -168,7 +166,7 @@ func Compile(fn *ir.Func, worker int) {
|
|||||||
if pp.Text.To.Offset >= maxStackSize {
|
if pp.Text.To.Offset >= maxStackSize {
|
||||||
largeStackFramesMu.Lock()
|
largeStackFramesMu.Lock()
|
||||||
locals := f.Frontend().(*ssafn).stksize
|
locals := f.Frontend().(*ssafn).stksize
|
||||||
largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: f.OwnAux.ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos()})
|
largeStackFrames = append(largeStackFrames, largeStack{locals: locals, args: fn.Type().ArgWidth(), callee: pp.Text.To.Offset - locals, pos: fn.Pos()})
|
||||||
largeStackFramesMu.Unlock()
|
largeStackFramesMu.Unlock()
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
@ -191,12 +189,6 @@ func StackOffset(slot ssa.LocalSlot) int32 {
|
|||||||
n := slot.N
|
n := slot.N
|
||||||
var off int64
|
var off int64
|
||||||
switch n.Class {
|
switch n.Class {
|
||||||
case ir.PPARAM, ir.PPARAMOUT:
|
|
||||||
if !n.IsOutputParamInRegisters() {
|
|
||||||
off = n.FrameOffset() + base.Ctxt.FixedFrameSize()
|
|
||||||
break
|
|
||||||
}
|
|
||||||
fallthrough // PPARAMOUT in registers allocates like an AUTO
|
|
||||||
case ir.PAUTO:
|
case ir.PAUTO:
|
||||||
off = n.FrameOffset()
|
off = n.FrameOffset()
|
||||||
if base.Ctxt.FixedFrameSize() == 0 {
|
if base.Ctxt.FixedFrameSize() == 0 {
|
||||||
@ -205,6 +197,8 @@ func StackOffset(slot ssa.LocalSlot) int32 {
|
|||||||
if objabi.Framepointer_enabled {
|
if objabi.Framepointer_enabled {
|
||||||
off -= int64(types.PtrSize)
|
off -= int64(types.PtrSize)
|
||||||
}
|
}
|
||||||
|
case ir.PPARAM, ir.PPARAMOUT:
|
||||||
|
off = n.FrameOffset() + base.Ctxt.FixedFrameSize()
|
||||||
}
|
}
|
||||||
return int32(off + slot.Off)
|
return int32(off + slot.Off)
|
||||||
}
|
}
|
||||||
|
@ -372,7 +372,7 @@ func (s *state) emitOpenDeferInfo() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func okOffset(offset int64) int64 {
|
func okOffset(offset int64) int64 {
|
||||||
if offset == types.BOGUS_FUNARG_OFFSET {
|
if offset >= types.BOGUS_FUNARG_OFFSET {
|
||||||
panic(fmt.Errorf("Bogus offset %d", offset))
|
panic(fmt.Errorf("Bogus offset %d", offset))
|
||||||
}
|
}
|
||||||
return offset
|
return offset
|
||||||
@ -516,7 +516,7 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var params *abi.ABIParamResultInfo
|
var params *abi.ABIParamResultInfo
|
||||||
params = s.f.ABISelf.ABIAnalyze(fn.Type(), true)
|
params = s.f.ABISelf.ABIAnalyze(fn.Type())
|
||||||
|
|
||||||
// Generate addresses of local declarations
|
// Generate addresses of local declarations
|
||||||
s.decladdrs = map[*ir.Name]*ssa.Value{}
|
s.decladdrs = map[*ir.Name]*ssa.Value{}
|
||||||
@ -4914,6 +4914,8 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
|
|||||||
closure = iclosure
|
closure = iclosure
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
types.CalcSize(fn.Type())
|
||||||
|
stksize := fn.Type().ArgWidth() // includes receiver, args, and results
|
||||||
|
|
||||||
if regAbiForFuncType(n.X.Type().FuncType()) {
|
if regAbiForFuncType(n.X.Type().FuncType()) {
|
||||||
// fmt.Printf("Saw magic last type in call %v\n", n)
|
// fmt.Printf("Saw magic last type in call %v\n", n)
|
||||||
@ -4925,9 +4927,7 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val
|
|||||||
callABI = s.f.ABI0
|
callABI = s.f.ABI0
|
||||||
}
|
}
|
||||||
|
|
||||||
params := callABI.ABIAnalyze(n.X.Type(), false /* Do not set (register) nNames from caller side -- can cause races. */ )
|
params := callABI.ABIAnalyze(n.X.Type())
|
||||||
types.CalcSize(fn.Type())
|
|
||||||
stksize := params.ArgWidth() // includes receiver, args, and results
|
|
||||||
|
|
||||||
res := n.X.Type().Results()
|
res := n.X.Type().Results()
|
||||||
if k == callNormal {
|
if k == callNormal {
|
||||||
@ -6838,13 +6838,13 @@ func genssa(f *ssa.Func, pp *objw.Progs) {
|
|||||||
f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
|
f.HTMLWriter.WriteColumn("genssa", "genssa", "ssa-prog", buf.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
defframe(&s, e, f)
|
defframe(&s, e)
|
||||||
|
|
||||||
f.HTMLWriter.Close()
|
f.HTMLWriter.Close()
|
||||||
f.HTMLWriter = nil
|
f.HTMLWriter = nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func defframe(s *State, e *ssafn, f *ssa.Func) {
|
func defframe(s *State, e *ssafn) {
|
||||||
pp := s.pp
|
pp := s.pp
|
||||||
|
|
||||||
frame := types.Rnd(s.maxarg+e.stksize, int64(types.RegSize))
|
frame := types.Rnd(s.maxarg+e.stksize, int64(types.RegSize))
|
||||||
@ -6854,7 +6854,7 @@ func defframe(s *State, e *ssafn, f *ssa.Func) {
|
|||||||
|
|
||||||
// Fill in argument and frame size.
|
// Fill in argument and frame size.
|
||||||
pp.Text.To.Type = obj.TYPE_TEXTSIZE
|
pp.Text.To.Type = obj.TYPE_TEXTSIZE
|
||||||
pp.Text.To.Val = int32(types.Rnd(f.OwnAux.ArgWidth(), int64(types.RegSize)))
|
pp.Text.To.Val = int32(types.Rnd(e.curfn.Type().ArgWidth(), int64(types.RegSize)))
|
||||||
pp.Text.To.Offset = frame
|
pp.Text.To.Offset = frame
|
||||||
|
|
||||||
// Insert code to zero ambiguously live variables so that the
|
// Insert code to zero ambiguously live variables so that the
|
||||||
@ -6957,18 +6957,14 @@ func AddAux2(a *obj.Addr, v *ssa.Value, offset int64) {
|
|||||||
a.Name = obj.NAME_EXTERN
|
a.Name = obj.NAME_EXTERN
|
||||||
a.Sym = n
|
a.Sym = n
|
||||||
case *ir.Name:
|
case *ir.Name:
|
||||||
if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
|
if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
|
||||||
a.Name = obj.NAME_PARAM
|
a.Name = obj.NAME_PARAM
|
||||||
a.Sym = ir.Orig(n).(*ir.Name).Linksym()
|
a.Sym = ir.Orig(n).(*ir.Name).Linksym()
|
||||||
a.Offset += n.FrameOffset()
|
a.Offset += n.FrameOffset()
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
a.Name = obj.NAME_AUTO
|
a.Name = obj.NAME_AUTO
|
||||||
if n.Class == ir.PPARAMOUT {
|
a.Sym = n.Linksym()
|
||||||
a.Sym = ir.Orig(n).(*ir.Name).Linksym()
|
|
||||||
} else {
|
|
||||||
a.Sym = n.Linksym()
|
|
||||||
}
|
|
||||||
a.Offset += n.FrameOffset()
|
a.Offset += n.FrameOffset()
|
||||||
default:
|
default:
|
||||||
v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
|
v.Fatalf("aux in %s not implemented %#v", v, v.Aux)
|
||||||
@ -7112,7 +7108,7 @@ func AddrAuto(a *obj.Addr, v *ssa.Value) {
|
|||||||
a.Sym = n.Linksym()
|
a.Sym = n.Linksym()
|
||||||
a.Reg = int16(Arch.REGSP)
|
a.Reg = int16(Arch.REGSP)
|
||||||
a.Offset = n.FrameOffset() + off
|
a.Offset = n.FrameOffset() + off
|
||||||
if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
|
if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
|
||||||
a.Name = obj.NAME_PARAM
|
a.Name = obj.NAME_PARAM
|
||||||
} else {
|
} else {
|
||||||
a.Name = obj.NAME_AUTO
|
a.Name = obj.NAME_AUTO
|
||||||
@ -7549,10 +7545,10 @@ func AddrForParamSlot(slot *ssa.LocalSlot, addr *obj.Addr) {
|
|||||||
addr.Type = obj.TYPE_MEM
|
addr.Type = obj.TYPE_MEM
|
||||||
addr.Sym = n.Linksym()
|
addr.Sym = n.Linksym()
|
||||||
addr.Offset = off
|
addr.Offset = off
|
||||||
if n.Class == ir.PPARAM || (n.Class == ir.PPARAMOUT && !n.IsOutputParamInRegisters()) {
|
if n.Class == ir.PPARAM || n.Class == ir.PPARAMOUT {
|
||||||
addr.Name = obj.NAME_PARAM
|
addr.Name = obj.NAME_PARAM
|
||||||
addr.Offset += n.FrameOffset()
|
addr.Offset += n.FrameOffset()
|
||||||
} else { // out parameters in registers allocate stack slots like autos.
|
} else {
|
||||||
addr.Name = obj.NAME_AUTO
|
addr.Name = obj.NAME_AUTO
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -119,7 +119,7 @@ func abitest(t *testing.T, ft *types.Type, exp expectedDump) {
|
|||||||
types.CalcSize(ft)
|
types.CalcSize(ft)
|
||||||
|
|
||||||
// Analyze with full set of registers.
|
// Analyze with full set of registers.
|
||||||
regRes := configAMD64.ABIAnalyze(ft, false)
|
regRes := configAMD64.ABIAnalyze(ft)
|
||||||
regResString := strings.TrimSpace(regRes.String())
|
regResString := strings.TrimSpace(regRes.String())
|
||||||
|
|
||||||
// Check results.
|
// Check results.
|
||||||
|
@ -163,9 +163,19 @@ func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 {
|
|||||||
if f.Type.Align > 0 {
|
if f.Type.Align > 0 {
|
||||||
o = Rnd(o, int64(f.Type.Align))
|
o = Rnd(o, int64(f.Type.Align))
|
||||||
}
|
}
|
||||||
if isStruct { // For receiver/args/results, do not set, it depends on ABI
|
if isStruct { // For receiver/args/results, depends on ABI
|
||||||
f.Offset = o
|
f.Offset = o
|
||||||
}
|
}
|
||||||
|
if f.Nname != nil {
|
||||||
|
// addrescapes has similar code to update these offsets.
|
||||||
|
// Usually addrescapes runs after calcStructOffset,
|
||||||
|
// in which case we could drop this,
|
||||||
|
// but function closure functions are the exception.
|
||||||
|
// NOTE(rsc): This comment may be stale.
|
||||||
|
// It's possible the ordering has changed and this is
|
||||||
|
// now the common case. I'm not sure.
|
||||||
|
f.Nname.(VarObject).RecordFrameOffset(o)
|
||||||
|
}
|
||||||
|
|
||||||
w := f.Type.Width
|
w := f.Type.Width
|
||||||
if w < 0 {
|
if w < 0 {
|
||||||
|
@ -1750,7 +1750,7 @@ func NewTypeParam(pkg *Pkg) *Type {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
const BOGUS_FUNARG_OFFSET = -1000000000
|
const BOGUS_FUNARG_OFFSET = 1000000000
|
||||||
|
|
||||||
func unzeroFieldOffsets(f []*Field) {
|
func unzeroFieldOffsets(f []*Field) {
|
||||||
for i := range f {
|
for i := range f {
|
||||||
@ -1759,7 +1759,7 @@ func unzeroFieldOffsets(f []*Field) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// NewSignature returns a new function type for the given receiver,
|
// NewSignature returns a new function type for the given receiver,
|
||||||
// parameters, results, and type parameters, any of which may be nil.
|
// parametes, results, and type parameters, any of which may be nil.
|
||||||
func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Type {
|
func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Type {
|
||||||
var recvs []*Field
|
var recvs []*Field
|
||||||
if recv != nil {
|
if recv != nil {
|
||||||
|
@ -13,12 +13,12 @@ import "fmt"
|
|||||||
|
|
||||||
// Test that register results are correctly returned (and passed)
|
// Test that register results are correctly returned (and passed)
|
||||||
|
|
||||||
type MagicLastTypeNameForTestingRegisterABI func(int, MagicLastTypeNameForTestingRegisterABI) int
|
type MagicLastTypeNameForTestingRegisterABI func(int,MagicLastTypeNameForTestingRegisterABI) int
|
||||||
|
|
||||||
//go:registerparams
|
//go:registerparams
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func minus(decrement int) MagicLastTypeNameForTestingRegisterABI {
|
func minus(decrement int) MagicLastTypeNameForTestingRegisterABI {
|
||||||
return MagicLastTypeNameForTestingRegisterABI(func(x int, _ MagicLastTypeNameForTestingRegisterABI) int { return x - decrement })
|
return MagicLastTypeNameForTestingRegisterABI( func(x int, _ MagicLastTypeNameForTestingRegisterABI) int { return x-decrement} )
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:noinline
|
//go:noinline
|
||||||
|
@ -1,36 +0,0 @@
|
|||||||
// run
|
|
||||||
|
|
||||||
//go:build !wasm
|
|
||||||
// +build !wasm
|
|
||||||
|
|
||||||
// Copyright 2021 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.
|
|
||||||
|
|
||||||
// wasm is excluded because the compiler chatter about register abi pragma ends up
|
|
||||||
// on stdout, and causes the expected output to not match.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type i5f5 struct {
|
|
||||||
a, b int16
|
|
||||||
c, d, e int32
|
|
||||||
r, s, t, u, v float32
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:registerparams
|
|
||||||
//go:noinline
|
|
||||||
func F(x i5f5) i5f5 {
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
x := i5f5{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
|
||||||
y := x
|
|
||||||
z := F(x)
|
|
||||||
if y != z {
|
|
||||||
fmt.Printf("y=%v, z=%v\n", y, z)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,43 +0,0 @@
|
|||||||
// run
|
|
||||||
|
|
||||||
//go:build !wasm
|
|
||||||
// +build !wasm
|
|
||||||
|
|
||||||
// Copyright 2021 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.
|
|
||||||
|
|
||||||
// wasm is excluded because the compiler chatter about register abi pragma ends up
|
|
||||||
// on stdout, and causes the expected output to not match.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type i4 struct {
|
|
||||||
a, b, c, d int
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:registerparams
|
|
||||||
//go:noinline
|
|
||||||
func F(x i4) i4 {
|
|
||||||
ab := x.a + x.b
|
|
||||||
bc := x.b + x.c
|
|
||||||
cd := x.c + x.d
|
|
||||||
ad := x.a + x.d
|
|
||||||
ba := x.a - x.b
|
|
||||||
cb := x.b - x.c
|
|
||||||
dc := x.c - x.d
|
|
||||||
da := x.a - x.d
|
|
||||||
|
|
||||||
return i4{ab*bc + da, cd*ad + cb, ba*cb + ad, dc*da + bc}
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
x := i4{1, 2, 3, 4}
|
|
||||||
y := x
|
|
||||||
z := F(x)
|
|
||||||
if (i4{12, 34, 6, 8}) != z {
|
|
||||||
fmt.Printf("y=%v, z=%v\n", y, z)
|
|
||||||
}
|
|
||||||
}
|
|
@ -14,7 +14,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type toobig struct {
|
type toobig struct {
|
||||||
a, b, c string
|
a,b,c string
|
||||||
}
|
}
|
||||||
|
|
||||||
//go:registerparams
|
//go:registerparams
|
||||||
@ -29,8 +29,8 @@ type AnInterface interface {
|
|||||||
|
|
||||||
//go:registerparams
|
//go:registerparams
|
||||||
//go:noinline
|
//go:noinline
|
||||||
func I(a, b, c string) toobig {
|
func I(a,b,c string) toobig {
|
||||||
return toobig{a, b, c}
|
return toobig{a,b,c}
|
||||||
}
|
}
|
||||||
|
|
||||||
// AnIid prevents the compiler from figuring out what the interface really is.
|
// AnIid prevents the compiler from figuring out what the interface really is.
|
||||||
@ -40,13 +40,12 @@ func AnIid(x AnInterface) AnInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var tmp toobig
|
var tmp toobig
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
x := I("Ahoy", "1,", "2")
|
x := I("Ahoy", "1,", "2")
|
||||||
y := I("3", "there,", "4")
|
y := I("3", "there,", "4")
|
||||||
z := I("5", "6,", "Matey")
|
z := I("5", "6,", "Matey")
|
||||||
tmp = x.MagicMethodNameForTestingRegisterABI(y, z)
|
tmp = x.MagicMethodNameForTestingRegisterABI(y,z)
|
||||||
fmt.Println(tmp.a, tmp.b, tmp.c)
|
fmt.Println(tmp.a, tmp.b, tmp.c)
|
||||||
tmp = AnIid(&x).MagicMethodNameForTestingRegisterABI(y, z)
|
tmp = AnIid(&x).MagicMethodNameForTestingRegisterABI(y,z)
|
||||||
fmt.Println(tmp.a, tmp.b, tmp.c)
|
fmt.Println(tmp.a, tmp.b, tmp.c)
|
||||||
}
|
}
|
||||||
|
@ -1,48 +0,0 @@
|
|||||||
// run
|
|
||||||
|
|
||||||
//go:build !wasm
|
|
||||||
// +build !wasm
|
|
||||||
|
|
||||||
// Copyright 2021 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.
|
|
||||||
|
|
||||||
// wasm is excluded because the compiler chatter about register abi pragma ends up
|
|
||||||
// on stdout, and causes the expected output to not match.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type i4 struct {
|
|
||||||
a, b, c, d int
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:noinline
|
|
||||||
func spills(px *i4) {
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:registerparams
|
|
||||||
//go:noinline
|
|
||||||
func F(x i4) i4 {
|
|
||||||
ab := x.a + x.b
|
|
||||||
bc := x.b + x.c
|
|
||||||
cd := x.c + x.d
|
|
||||||
ad := x.a + x.d
|
|
||||||
ba := x.a - x.b
|
|
||||||
cb := x.b - x.c
|
|
||||||
dc := x.c - x.d
|
|
||||||
da := x.a - x.d
|
|
||||||
i := i4{ab*bc + da, cd*ad + cb, ba*cb + ad, dc*da + bc}
|
|
||||||
spills(&i)
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
x := i4{1, 2, 3, 4}
|
|
||||||
y := x
|
|
||||||
z := F(x)
|
|
||||||
if z != (i4{12, 34, 6, 8}) {
|
|
||||||
fmt.Printf("y=%v, z=%v\n", y, z)
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,44 +0,0 @@
|
|||||||
// run
|
|
||||||
|
|
||||||
//go:build !wasm
|
|
||||||
// +build !wasm
|
|
||||||
|
|
||||||
// Copyright 2021 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.
|
|
||||||
|
|
||||||
// wasm is excluded because the compiler chatter about register abi pragma ends up
|
|
||||||
// on stdout, and causes the expected output to not match.
|
|
||||||
|
|
||||||
package main
|
|
||||||
|
|
||||||
import "fmt"
|
|
||||||
|
|
||||||
type i5f5 struct {
|
|
||||||
a, b int16
|
|
||||||
c, d, e int32
|
|
||||||
r, s, t, u, v float32
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:noinline
|
|
||||||
func spills(_ *float32) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//go:registerparams
|
|
||||||
//go:noinline
|
|
||||||
func F(x i5f5) i5f5 {
|
|
||||||
y := x.v
|
|
||||||
spills(&y)
|
|
||||||
x.r = y
|
|
||||||
return x
|
|
||||||
}
|
|
||||||
|
|
||||||
func main() {
|
|
||||||
x := i5f5{1, 2, 3, 4, 5, 6, 7, 8, 9, 10}
|
|
||||||
y := x
|
|
||||||
z := F(x)
|
|
||||||
if (i5f5{1, 2, 3, 4, 5, 10, 7, 8, 9, 10}) != z {
|
|
||||||
fmt.Printf("y=%v, z=%v\n", y, z)
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user