s := mem
if storeRc.hasRegs() {
- // TODO(register args)
storeRc.addArg(source)
} else {
dst := x.offsetFrom(storeRc.storeDest, offset, types.NewPtr(t))
// rewriteArgs removes all the Args from a call and converts the call args into appropriate
// stores (or later, register movement). Extra args for interface and closure calls are ignored,
// but removed.
-func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value {
+func (x *expandState) rewriteArgs(v *Value, firstArg int) (*Value, []*Value) {
// Thread the stores on the memory arg
aux := v.Aux.(*AuxCall)
pos := v.Pos.WithNotStmt()
m0 := v.MemoryArg()
mem := m0
allResults := []*Value{}
- for i, a := range v.Args {
- if i < firstArg {
- continue
- }
- if a == m0 { // mem is last.
- break
- }
- auxI := int64(i - firstArg)
+ for i, a := range v.Args[firstArg : len(v.Args)-1] { // skip leading non-parameter SSA Args and trailing mem SSA Arg.
+ auxI := int64(i)
aRegs := aux.RegsOfArg(auxI)
aType := aux.TypeOfArg(auxI)
if a.Op == OpDereference {
}
rc.init(aRegs, aux.abiInfo, result, x.sp)
mem = x.storeArgOrLoad(pos, v.Block, a, mem, aType, aOffset, 0, rc)
- // TODO append mem to Result, update type
}
}
v.resetArgs()
- return mem
+ return mem, allResults
}
// expandCalls converts LE (Late Expansion) calls that act like they receive value args into a lower-level form
for _, v := range b.Values {
switch v.Op {
case OpStaticLECall:
- mem := x.rewriteArgs(v, 0)
- v.SetArgs1(mem)
+ mem, results := x.rewriteArgs(v, 0)
+ v.AddArgs(results...)
+ v.AddArg(mem)
case OpClosureLECall:
code := v.Args[0]
context := v.Args[1]
- mem := x.rewriteArgs(v, 2)
- v.SetArgs3(code, context, mem)
+ mem, results := x.rewriteArgs(v, 2)
+ if len(results) == 0 {
+ v.SetArgs3(code, context, mem)
+ } else {
+ v.SetArgs2(code, context)
+ v.AddArgs(results...)
+ v.AddArg(mem)
+ }
case OpInterLECall:
code := v.Args[0]
- mem := x.rewriteArgs(v, 1)
- v.SetArgs2(code, mem)
+ mem, results := x.rewriteArgs(v, 1)
+ if len(results) == 0 {
+ v.SetArgs2(code, mem)
+ } else {
+ v.SetArgs1(code)
+ v.AddArgs(results...)
+ v.AddArg(mem)
+ }
}
}
if isBlockMultiValueExit(b) {
aux := f.OwnAux
pos := v.Pos.WithNotStmt()
allResults := []*Value{}
- for j, a := range v.Args {
+ for j, a := range v.Args[:len(v.Args)-1] {
i := int64(j)
- if a == m0 {
- break
- }
auxType := aux.TypeOfResult(i)
auxBase := b.NewValue2A(v.Pos, OpLocalAddr, types.NewPtr(auxType), aux.results[i].Name, x.sp, mem)
auxOffset := int64(0)
result = &allResults
}
rc.init(aRegs, aux.abiInfo, result, auxBase)
- // TODO REGISTER
mem = x.storeArgOrLoad(v.Pos, b, a, mem, aux.TypeOfResult(i), auxOffset, 0, rc)
- // TODO append mem to Result, update type
}
}
+ // TODO REGISTER -- keep the Result for block control, splice in contents of AllResults
b.SetControl(mem)
v.reset(OpInvalid) // otherwise it can have a mem operand which will fail check(), even though it is dead.
}