mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/compile: retrieve Args from registers
in progress; doesn't fully work until they are also passed on register on the caller side. For #40724. Change-Id: I29a6680e60bdbe9d132782530214f2a2b51fb8f6 Reviewed-on: https://go-review.googlesource.com/c/go/+/293394 Trust: David Chase <drchase@google.com> Run-TryBot: David Chase <drchase@google.com> Reviewed-by: Cherry Zhang <cherryyz@google.com>
This commit is contained in:
parent
06c72f3627
commit
f2df1e3c34
8 changed files with 64 additions and 14 deletions
|
|
@ -158,6 +158,13 @@ func (a *ABIConfig) LocalsOffset() int64 {
|
||||||
return a.offsetForLocals
|
return a.offsetForLocals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// FloatIndexFor translates r into an index in the floating point parameter
|
||||||
|
// registers. If the result is negative, the input index was actually for the
|
||||||
|
// integer parameter registers.
|
||||||
|
func (a *ABIConfig) FloatIndexFor(r RegIndex) int64 {
|
||||||
|
return int64(r) - int64(a.regAmounts.intRegs)
|
||||||
|
}
|
||||||
|
|
||||||
// NumParamRegs returns the number of parameter registers used for a given type,
|
// NumParamRegs returns the number of parameter registers used for a given type,
|
||||||
// without regard for the number available.
|
// without regard for the number available.
|
||||||
func (a *ABIConfig) NumParamRegs(t *types.Type) int {
|
func (a *ABIConfig) NumParamRegs(t *types.Type) int {
|
||||||
|
|
|
||||||
|
|
@ -980,6 +980,8 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
||||||
ssagen.AddAux(&p.From, v)
|
ssagen.AddAux(&p.From, v)
|
||||||
p.To.Type = obj.TYPE_REG
|
p.To.Type = obj.TYPE_REG
|
||||||
p.To.Reg = v.Reg()
|
p.To.Reg = v.Reg()
|
||||||
|
case ssa.OpArgIntReg, ssa.OpArgFloatReg:
|
||||||
|
ssagen.CheckArgReg(v)
|
||||||
case ssa.OpAMD64LoweredGetClosurePtr:
|
case ssa.OpAMD64LoweredGetClosurePtr:
|
||||||
// Closure pointer is DX.
|
// Closure pointer is DX.
|
||||||
ssagen.CheckLoweredGetClosurePtr(v)
|
ssagen.CheckLoweredGetClosurePtr(v)
|
||||||
|
|
|
||||||
|
|
@ -808,9 +808,9 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value {
|
||||||
}
|
}
|
||||||
auxI := int64(i - firstArg)
|
auxI := int64(i - firstArg)
|
||||||
aRegs := aux.RegsOfArg(auxI)
|
aRegs := aux.RegsOfArg(auxI)
|
||||||
aOffset := aux.OffsetOfArg(auxI)
|
|
||||||
aType := aux.TypeOfArg(auxI)
|
aType := aux.TypeOfArg(auxI)
|
||||||
if a.Op == OpDereference {
|
if a.Op == OpDereference {
|
||||||
|
aOffset := aux.OffsetOfArg(auxI)
|
||||||
if a.MemoryArg() != m0 {
|
if a.MemoryArg() != m0 {
|
||||||
x.f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString())
|
x.f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString())
|
||||||
}
|
}
|
||||||
|
|
@ -821,13 +821,16 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value {
|
||||||
// TODO(register args) this will be more complicated with registers in the picture.
|
// TODO(register args) this will be more complicated with registers in the picture.
|
||||||
mem = x.rewriteDereference(v.Block, x.sp, a, mem, aOffset, aux.SizeOfArg(auxI), aType, pos)
|
mem = x.rewriteDereference(v.Block, x.sp, a, mem, aOffset, aux.SizeOfArg(auxI), aType, pos)
|
||||||
} else {
|
} else {
|
||||||
if x.debug {
|
|
||||||
fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset)
|
|
||||||
}
|
|
||||||
var rc registerCursor
|
var rc registerCursor
|
||||||
var result *[]*Value
|
var result *[]*Value
|
||||||
|
var aOffset int64
|
||||||
if len(aRegs) > 0 {
|
if len(aRegs) > 0 {
|
||||||
result = &allResults
|
result = &allResults
|
||||||
|
} else {
|
||||||
|
aOffset = aux.OffsetOfArg(auxI)
|
||||||
|
}
|
||||||
|
if x.debug {
|
||||||
|
fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset)
|
||||||
}
|
}
|
||||||
rc.init(aRegs, aux.abiInfo, result)
|
rc.init(aRegs, aux.abiInfo, result)
|
||||||
mem = x.storeArgOrLoad(pos, v.Block, x.sp, a, mem, aType, aOffset, 0, rc)
|
mem = x.storeArgOrLoad(pos, v.Block, x.sp, a, mem, aType, aOffset, 0, rc)
|
||||||
|
|
@ -1213,8 +1216,19 @@ func expandCalls(f *Func) {
|
||||||
pa.Offset(), frameOff, v.LongString()))
|
pa.Offset(), frameOff, v.LongString()))
|
||||||
}
|
}
|
||||||
case 1:
|
case 1:
|
||||||
|
r := pa.Registers[0]
|
||||||
|
i := f.ABISelf.FloatIndexFor(r)
|
||||||
|
// TODO seems like this has implications for debugging. How does this affect the location?
|
||||||
|
if i >= 0 { // float PR
|
||||||
|
v.Op = OpArgFloatReg
|
||||||
|
} else {
|
||||||
|
v.Op = OpArgIntReg
|
||||||
|
i = int64(r)
|
||||||
|
}
|
||||||
|
v.AuxInt = i
|
||||||
|
|
||||||
default:
|
default:
|
||||||
panic(badVal("Saw unexpeanded OpArg", v))
|
panic(badVal("Saw unexpanded OpArg", v))
|
||||||
}
|
}
|
||||||
|
|
||||||
case OpStaticLECall:
|
case OpStaticLECall:
|
||||||
|
|
|
||||||
|
|
@ -21,8 +21,12 @@ func checkLower(f *Func) {
|
||||||
continue // lowered
|
continue // lowered
|
||||||
}
|
}
|
||||||
switch v.Op {
|
switch v.Op {
|
||||||
case OpSP, OpSB, OpInitMem, OpArg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpSelectN, OpConvert, OpInlMark:
|
case OpSP, OpSB, OpInitMem, OpArg, OpArgIntReg, OpArgFloatReg, OpPhi, OpVarDef, OpVarKill, OpVarLive, OpKeepAlive, OpSelect0, OpSelect1, OpSelectN, OpConvert, OpInlMark:
|
||||||
continue // ok not to lower
|
continue // ok not to lower
|
||||||
|
case OpMakeResult:
|
||||||
|
if len(b.Controls) == 1 && b.Controls[0] == v {
|
||||||
|
continue
|
||||||
|
}
|
||||||
case OpGetG:
|
case OpGetG:
|
||||||
if f.Config.hasGReg {
|
if f.Config.hasGReg {
|
||||||
// has hardware g register, regalloc takes care of it
|
// has hardware g register, regalloc takes care of it
|
||||||
|
|
|
||||||
|
|
@ -800,7 +800,8 @@ func (s *regAllocState) compatRegs(t *types.Type) regMask {
|
||||||
}
|
}
|
||||||
|
|
||||||
// regspec returns the regInfo for operation op.
|
// regspec returns the regInfo for operation op.
|
||||||
func (s *regAllocState) regspec(op Op) regInfo {
|
func (s *regAllocState) regspec(v *Value) regInfo {
|
||||||
|
op := v.Op
|
||||||
if op == OpConvert {
|
if op == OpConvert {
|
||||||
// OpConvert is a generic op, so it doesn't have a
|
// OpConvert is a generic op, so it doesn't have a
|
||||||
// register set in the static table. It can use any
|
// register set in the static table. It can use any
|
||||||
|
|
@ -808,6 +809,20 @@ func (s *regAllocState) regspec(op Op) regInfo {
|
||||||
m := s.allocatable & s.f.Config.gpRegMask
|
m := s.allocatable & s.f.Config.gpRegMask
|
||||||
return regInfo{inputs: []inputInfo{{regs: m}}, outputs: []outputInfo{{regs: m}}}
|
return regInfo{inputs: []inputInfo{{regs: m}}, outputs: []outputInfo{{regs: m}}}
|
||||||
}
|
}
|
||||||
|
if op == OpArgIntReg {
|
||||||
|
reg := v.Block.Func.Config.intParamRegs[v.AuxInt8()]
|
||||||
|
return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}}
|
||||||
|
}
|
||||||
|
if op == OpArgFloatReg {
|
||||||
|
reg := v.Block.Func.Config.floatParamRegs[v.AuxInt8()]
|
||||||
|
return regInfo{outputs: []outputInfo{{regs: 1 << uint(reg)}}}
|
||||||
|
}
|
||||||
|
if op.IsCall() {
|
||||||
|
// TODO Panic if not okay
|
||||||
|
if ac, ok := v.Aux.(*AuxCall); ok && ac.reg != nil {
|
||||||
|
return *ac.reg
|
||||||
|
}
|
||||||
|
}
|
||||||
return opcodeTable[op].reg
|
return opcodeTable[op].reg
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1163,7 +1178,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||||
for i := len(oldSched) - 1; i >= 0; i-- {
|
for i := len(oldSched) - 1; i >= 0; i-- {
|
||||||
v := oldSched[i]
|
v := oldSched[i]
|
||||||
prefs := desired.remove(v.ID)
|
prefs := desired.remove(v.ID)
|
||||||
regspec := s.regspec(v.Op)
|
regspec := s.regspec(v)
|
||||||
desired.clobber(regspec.clobbers)
|
desired.clobber(regspec.clobbers)
|
||||||
for _, j := range regspec.inputs {
|
for _, j := range regspec.inputs {
|
||||||
if countRegs(j.regs) != 1 {
|
if countRegs(j.regs) != 1 {
|
||||||
|
|
@ -1193,7 +1208,7 @@ func (s *regAllocState) regalloc(f *Func) {
|
||||||
if s.f.pass.debug > regDebug {
|
if s.f.pass.debug > regDebug {
|
||||||
fmt.Printf(" processing %s\n", v.LongString())
|
fmt.Printf(" processing %s\n", v.LongString())
|
||||||
}
|
}
|
||||||
regspec := s.regspec(v.Op)
|
regspec := s.regspec(v)
|
||||||
if v.Op == OpPhi {
|
if v.Op == OpPhi {
|
||||||
f.Fatalf("phi %s not at start of block", v)
|
f.Fatalf("phi %s not at start of block", v)
|
||||||
}
|
}
|
||||||
|
|
@ -2447,7 +2462,7 @@ func (s *regAllocState) computeLive() {
|
||||||
// desired registers back though phi nodes.
|
// desired registers back though phi nodes.
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
regspec := s.regspec(v.Op)
|
regspec := s.regspec(v)
|
||||||
// Cancel desired registers if they get clobbered.
|
// Cancel desired registers if they get clobbered.
|
||||||
desired.clobber(regspec.clobbers)
|
desired.clobber(regspec.clobbers)
|
||||||
// Update desired registers if there are any fixed register inputs.
|
// Update desired registers if there are any fixed register inputs.
|
||||||
|
|
|
||||||
|
|
@ -795,8 +795,6 @@ func devirtLECall(v *Value, sym *obj.LSym) *Value {
|
||||||
v.Op = OpStaticLECall
|
v.Op = OpStaticLECall
|
||||||
auxcall := v.Aux.(*AuxCall)
|
auxcall := v.Aux.(*AuxCall)
|
||||||
auxcall.Fn = sym
|
auxcall.Fn = sym
|
||||||
// TODO(register args) this should not be necessary when fully transition to the new register ABI.
|
|
||||||
auxcall.abiInfo = v.Block.Func.ABIDefault.ABIAnalyzeTypes(nil, ACParamsToTypes(auxcall.args), ACParamsToTypes(auxcall.results))
|
|
||||||
v.RemoveArg(0)
|
v.RemoveArg(0)
|
||||||
return v
|
return v
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -137,7 +137,7 @@ func schedule(f *Func) {
|
||||||
case v.Op == OpVarDef:
|
case v.Op == OpVarDef:
|
||||||
// We want all the vardefs next.
|
// We want all the vardefs next.
|
||||||
score[v.ID] = ScoreVarDef
|
score[v.ID] = ScoreVarDef
|
||||||
case v.Op == OpArg:
|
case v.Op == OpArg || v.Op == OpArgIntReg || v.Op == OpArgFloatReg:
|
||||||
// We want all the args as early as possible, for better debugging.
|
// We want all the args as early as possible, for better debugging.
|
||||||
score[v.ID] = ScoreArg
|
score[v.ID] = ScoreArg
|
||||||
case v.Type.IsMemory():
|
case v.Type.IsMemory():
|
||||||
|
|
|
||||||
|
|
@ -485,7 +485,8 @@ func buildssa(fn *ir.Func, worker int) *ssa.Func {
|
||||||
s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, deferBitsTemp, s.mem(), false)
|
s.vars[memVar] = s.newValue1Apos(ssa.OpVarLive, types.TypeMem, deferBitsTemp, s.mem(), false)
|
||||||
}
|
}
|
||||||
|
|
||||||
params := s.f.ABISelf.ABIAnalyze(fn.Type())
|
var params *abi.ABIParamResultInfo
|
||||||
|
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{}
|
||||||
|
|
@ -7019,11 +7020,20 @@ func CheckLoweredPhi(v *ssa.Value) {
|
||||||
// That register contains the closure pointer on closure entry.
|
// That register contains the closure pointer on closure entry.
|
||||||
func CheckLoweredGetClosurePtr(v *ssa.Value) {
|
func CheckLoweredGetClosurePtr(v *ssa.Value) {
|
||||||
entry := v.Block.Func.Entry
|
entry := v.Block.Func.Entry
|
||||||
|
// TODO register args: not all the register-producing ops can come first.
|
||||||
if entry != v.Block || entry.Values[0] != v {
|
if entry != v.Block || entry.Values[0] != v {
|
||||||
base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
|
base.Fatalf("in %s, badly placed LoweredGetClosurePtr: %v %v", v.Block.Func.Name, v.Block, v)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckArgReg ensures that v is in the function's entry block.
|
||||||
|
func CheckArgReg(v *ssa.Value) {
|
||||||
|
entry := v.Block.Func.Entry
|
||||||
|
if entry != v.Block {
|
||||||
|
base.Fatalf("in %s, badly placed ArgIReg or ArgFReg: %v %v", v.Block.Func.Name, v.Block, v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func AddrAuto(a *obj.Addr, v *ssa.Value) {
|
func AddrAuto(a *obj.Addr, v *ssa.Value) {
|
||||||
n, off := ssa.AutoVar(v)
|
n, off := ssa.AutoVar(v)
|
||||||
a.Type = obj.TYPE_MEM
|
a.Type = obj.TYPE_MEM
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue