]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile: refactor out an almost-superfluous arg
authorDavid Chase <drchase@google.com>
Wed, 17 Feb 2021 17:17:25 +0000 (12:17 -0500)
committerDavid Chase <drchase@google.com>
Thu, 4 Mar 2021 02:09:42 +0000 (02:09 +0000)
Moved all "target" information into "storeRC"; it was a register
cursor, now it is a register cursor that also carries the store
target with it if there are no registers.  Also allows booby-trapping
to ensure that the target is unambiguously one or the other.

For #40724.

Change-Id: I53ba4b91679e5fcc89c63b7d31225135299c6ec6
Reviewed-on: https://go-review.googlesource.com/c/go/+/293397
Trust: David Chase <drchase@google.com>
Run-TryBot: David Chase <drchase@google.com>
Reviewed-by: Cherry Zhang <cherryyz@google.com>
src/cmd/compile/internal/ssa/expand_calls.go

index 87b8a02b2544647fc3b27310078a992314e2edff..1868e3f073d9764aed35b7c89fde7ceadc79a15a 100644 (file)
@@ -62,12 +62,31 @@ func removeTrivialWrapperTypes(t *types.Type) *types.Type {
 // A registerCursor tracks which register is used for an Arg or regValues, or a piece of such.
 type registerCursor struct {
        // TODO(register args) convert this to a generalized target cursor.
+       storeDest *Value // if there are no register targets, then this is the base of the store.
        regsLen   int    // the number of registers available for this Arg/result (which is all in registers or not at all)
        nextSlice Abi1RO // the next register/register-slice offset
        config    *abi.ABIConfig
        regValues *[]*Value // values assigned to registers accumulate here
 }
 
+func (rc *registerCursor) String() string {
+       dest := "<none>"
+       if rc.storeDest != nil {
+               dest = rc.storeDest.String()
+       }
+       regs := "<none>"
+       if rc.regValues != nil {
+               regs = ""
+               for i, x := range *rc.regValues {
+                       if i > 0 {
+                               regs = regs + "; "
+                       }
+                       regs = regs + x.LongString()
+               }
+       }
+       return fmt.Sprintf("RCSR{storeDest=%v, regsLen=%d, nextSlice=%d, regValues=[%s], config=%v", dest, rc.regsLen, rc.nextSlice, regs, rc.config)
+}
+
 // next effectively post-increments the register cursor; the receiver is advanced,
 // the old value is returned.
 func (c *registerCursor) next(t *types.Type) registerCursor {
@@ -139,10 +158,11 @@ func (c *registerCursor) at(t *types.Type, i int) registerCursor {
        panic("Haven't implemented this case yet, do I need to?")
 }
 
-func (c *registerCursor) init(regs []abi.RegIndex, info *abi.ABIParamResultInfo, result *[]*Value) {
+func (c *registerCursor) init(regs []abi.RegIndex, info *abi.ABIParamResultInfo, result *[]*Value, storeDest *Value) {
        c.regsLen = len(regs)
        c.nextSlice = 0
        if len(regs) == 0 {
+               c.storeDest = storeDest // only save this if there are no registers, will explode if misused.
                return
        }
        c.config = info.Config()
@@ -519,20 +539,20 @@ func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset,
 // Parameters:
 //  pos           -- the location of any generated code.
 //  b             -- the block into which any generated code should normally be placed
-//  base          -- for the stores that will ultimately be generated, the base to which the offset is applied. (Note this disappears in a future CL, folded into storeRc)
 //  source        -- the value, possibly an aggregate, to be stored.
 //  mem           -- the mem flowing into this decomposition (loads depend on it, stores updated it)
 //  t             -- the type of the value to be stored
-//  offset        -- if the value is stored in memory, it is stored at base + offset
+//  offset        -- if the value is stored in memory, it is stored at base (see storeRc) + offset
 //  loadRegOffset -- regarding source as a value in registers, the register offset in ABI1.  Meaningful only if source is OpArg.
-//  storeRc       -- storeRC; if the value is stored in registers, this specifies the registers.  StoreRc also identifies whether the target is registers or memory.
+//  storeRc       -- storeRC; if the value is stored in registers, this specifies the registers.
+//                   StoreRc also identifies whether the target is registers or memory, and has the base for the store operation.
 //
 // TODO -- this needs cleanup; it just works for SSA-able aggregates, and won't fully generalize to register-args aggregates.
-func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor,
+func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor,
        // For decompose One and Two, the additional offArg provides the offset from the beginning of "source", if it is in memory.
        // offStore is combined to base to obtain a store destionation, like "offset" of decomposeArgOrLoad
-       decomposeOne func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value,
-       decomposeTwo func(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value) *Value {
+       decomposeOne func(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value,
+       decomposeTwo func(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value) *Value {
        u := source.Type
        switch u.Kind() {
        case types.TARRAY:
@@ -540,7 +560,7 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m
                elemRO := x.regWidth(elem)
                for i := int64(0); i < u.NumElem(); i++ {
                        elemOff := i * elem.Size()
-                       mem = decomposeOne(x, pos, b, base, source, mem, elem, elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem))
+                       mem = decomposeOne(x, pos, b, source, mem, elem, elemOff, offset+elemOff, loadRegOffset, storeRc.next(elem))
                        loadRegOffset += elemRO
                        pos = pos.WithNotStmt()
                }
@@ -548,7 +568,7 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m
        case types.TSTRUCT:
                for i := 0; i < u.NumFields(); i++ {
                        fld := u.Field(i)
-                       mem = decomposeOne(x, pos, b, base, source, mem, fld.Type, fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type))
+                       mem = decomposeOne(x, pos, b, source, mem, fld.Type, fld.Offset, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type))
                        loadRegOffset += x.regWidth(fld.Type)
                        pos = pos.WithNotStmt()
                }
@@ -558,80 +578,78 @@ func (x *expandState) decomposeArgOrLoad(pos src.XPos, b *Block, base, source, m
                        break
                }
                tHi, tLo := x.intPairTypes(t.Kind())
-               mem = decomposeOne(x, pos, b, base, source, mem, tHi, x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo))
+               mem = decomposeOne(x, pos, b, source, mem, tHi, x.hiOffset, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo))
                pos = pos.WithNotStmt()
-               return decomposeOne(x, pos, b, base, source, mem, tLo, x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo))
+               return decomposeOne(x, pos, b, source, mem, tLo, x.lowOffset, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo))
        case types.TINTER:
-               return decomposeTwo(x, pos, b, base, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc)
+               return decomposeTwo(x, pos, b, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc)
        case types.TSTRING:
-               return decomposeTwo(x, pos, b, base, source, mem, x.typs.BytePtr, x.typs.Int, 0, offset, loadRegOffset, storeRc)
+               return decomposeTwo(x, pos, b, source, mem, x.typs.BytePtr, x.typs.Int, 0, offset, loadRegOffset, storeRc)
        case types.TCOMPLEX64:
-               return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float32, x.typs.Float32, 0, offset, loadRegOffset, storeRc)
+               return decomposeTwo(x, pos, b, source, mem, x.typs.Float32, x.typs.Float32, 0, offset, loadRegOffset, storeRc)
        case types.TCOMPLEX128:
-               return decomposeTwo(x, pos, b, base, source, mem, x.typs.Float64, x.typs.Float64, 0, offset, loadRegOffset, storeRc)
+               return decomposeTwo(x, pos, b, source, mem, x.typs.Float64, x.typs.Float64, 0, offset, loadRegOffset, storeRc)
        case types.TSLICE:
-               mem = decomposeOne(x, pos, b, base, source, mem, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc.next(x.typs.BytePtr))
-               return decomposeTwo(x, pos, b, base, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc)
+               mem = decomposeOne(x, pos, b, source, mem, x.typs.BytePtr, 0, offset, loadRegOffset, storeRc.next(x.typs.BytePtr))
+               return decomposeTwo(x, pos, b, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc)
        }
        return nil
 }
 
 // storeOneArg creates a decomposed (one step) arg that is then stored.
-// pos and b locate the store instruction, base is the base of the store target, source is the "base" of the value input,
+// pos and b locate the store instruction, source is the "base" of the value input,
 // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases.
-func storeOneArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
+func storeOneArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
        w := x.commonArgs[selKey{source, offArg, t.Width, t}]
        if w == nil {
-               // w = source.Block.NewValue0IA(source.Pos, OpArg, t, offArg, source.Aux)
                w = x.newArgToMemOrRegs(source, w, offArg, loadRegOffset, t, pos)
-               // x.commonArgs[selKey{source, offArg, t.Width, t}] = w
        }
-       return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore, loadRegOffset, storeRc)
+       return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc)
 }
 
 // storeOneLoad creates a decomposed (one step) load that is then stored.
-func storeOneLoad(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
+func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
        from := x.offsetFrom(source.Args[0], offArg, types.NewPtr(t))
        w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem)
-       return x.storeArgOrLoad(pos, b, base, w, mem, t, offStore, loadRegOffset, storeRc)
+       return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc)
 }
 
-func storeTwoArg(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
-       mem = storeOneArg(x, pos, b, base, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
+func storeTwoArg(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
+       mem = storeOneArg(x, pos, b, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
        pos = pos.WithNotStmt()
        t1Size := t1.Size()
-       return storeOneArg(x, pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc)
+       return storeOneArg(x, pos, b, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc)
 }
 
 // storeTwoLoad creates a pair of decomposed (one step) loads that are then stored.
 // the elements of the pair must not require any additional alignment.
-func storeTwoLoad(x *expandState, pos src.XPos, b *Block, base, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
-       mem = storeOneLoad(x, pos, b, base, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
+func storeTwoLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
+       mem = storeOneLoad(x, pos, b, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
        pos = pos.WithNotStmt()
        t1Size := t1.Size()
-       return storeOneLoad(x, pos, b, base, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc)
+       return storeOneLoad(x, pos, b, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc)
 }
 
 // storeArgOrLoad converts stores of SSA-able potentially aggregatable arguments (passed to a call) into a series of primitive-typed
 // stores of non-aggregate types.  It recursively walks up a chain of selectors until it reaches a Load or an Arg.
 // If it does not reach a Load or an Arg, nothing happens; this allows a little freedom in phase ordering.
-func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
+func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, offset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
        if x.debug {
-               fmt.Printf("\tstoreArgOrLoad(%s;  %s;  %s;  %s; %d)\n", base.LongString(), source.LongString(), mem.String(), t.String(), offset)
+               fmt.Printf("\tstoreArgOrLoad(%s;  %s;  %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), offset, storeRc.String())
        }
 
        switch source.Op {
        case OpCopy:
-               return x.storeArgOrLoad(pos, b, base, source.Args[0], mem, t, offset, loadRegOffset, storeRc)
+               return x.storeArgOrLoad(pos, b, source.Args[0], mem, t, offset, loadRegOffset, storeRc)
 
        case OpLoad:
-               ret := x.decomposeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc, storeOneLoad, storeTwoLoad)
+               ret := x.decomposeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc, storeOneLoad, storeTwoLoad)
                if ret != nil {
                        return ret
                }
 
        case OpArg:
-               ret := x.decomposeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc, storeOneArg, storeTwoArg)
+               ret := x.decomposeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc, storeOneArg, storeTwoArg)
                if ret != nil {
                        return ret
                }
@@ -643,19 +661,19 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *
        case OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4:
                for i := 0; i < t.NumFields(); i++ {
                        fld := t.Field(i)
-                       mem = x.storeArgOrLoad(pos, b, base, source.Args[i], mem, fld.Type, offset+fld.Offset, 0, storeRc.next(fld.Type))
+                       mem = x.storeArgOrLoad(pos, b, source.Args[i], mem, fld.Type, offset+fld.Offset, 0, storeRc.next(fld.Type))
                        pos = pos.WithNotStmt()
                }
                return mem
 
        case OpArrayMake1:
-               return x.storeArgOrLoad(pos, b, base, source.Args[0], mem, t.Elem(), offset, 0, storeRc.at(t, 0))
+               return x.storeArgOrLoad(pos, b, source.Args[0], mem, t.Elem(), offset, 0, storeRc.at(t, 0))
 
        case OpInt64Make:
                tHi, tLo := x.intPairTypes(t.Kind())
-               mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, tHi, offset+x.hiOffset, 0, storeRc.next(tHi))
+               mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tHi, offset+x.hiOffset, 0, storeRc.next(tHi))
                pos = pos.WithNotStmt()
-               return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, tLo, offset+x.lowOffset, 0, storeRc)
+               return x.storeArgOrLoad(pos, b, source.Args[1], mem, tLo, offset+x.lowOffset, 0, storeRc)
 
        case OpComplexMake:
                tPart := x.typs.Float32
@@ -663,25 +681,25 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *
                if wPart == 8 {
                        tPart = x.typs.Float64
                }
-               mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, tPart, offset, 0, storeRc.next(tPart))
+               mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tPart, offset, 0, storeRc.next(tPart))
                pos = pos.WithNotStmt()
-               return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, tPart, offset+wPart, 0, storeRc)
+               return x.storeArgOrLoad(pos, b, source.Args[1], mem, tPart, offset+wPart, 0, storeRc)
 
        case OpIMake:
-               mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.Uintptr, offset, 0, storeRc.next(x.typs.Uintptr))
+               mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.Uintptr, offset, 0, storeRc.next(x.typs.Uintptr))
                pos = pos.WithNotStmt()
-               return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.BytePtr, offset+x.ptrSize, 0, storeRc)
+               return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.BytePtr, offset+x.ptrSize, 0, storeRc)
 
        case OpStringMake:
-               mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr))
+               mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr))
                pos = pos.WithNotStmt()
-               return x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc)
+               return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc)
 
        case OpSliceMake:
-               mem = x.storeArgOrLoad(pos, b, base, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr))
+               mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, offset, 0, storeRc.next(x.typs.BytePtr))
                pos = pos.WithNotStmt()
-               mem = x.storeArgOrLoad(pos, b, base, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc.next(x.typs.Int))
-               return x.storeArgOrLoad(pos, b, base, source.Args[2], mem, x.typs.Int, offset+2*x.ptrSize, 0, storeRc)
+               mem = x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, offset+x.ptrSize, 0, storeRc.next(x.typs.Int))
+               return x.storeArgOrLoad(pos, b, source.Args[2], mem, x.typs.Int, offset+2*x.ptrSize, 0, storeRc)
        }
 
        // For nodes that cannot be taken apart -- OpSelectN, other structure selectors.
@@ -691,12 +709,12 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *
                if source.Type != t && t.NumElem() == 1 && elt.Width == t.Width && t.Width == x.regSize {
                        t = removeTrivialWrapperTypes(t)
                        // it could be a leaf type, but the "leaf" could be complex64 (for example)
-                       return x.storeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc)
+                       return x.storeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc)
                }
                eltRO := x.regWidth(elt)
                for i := int64(0); i < t.NumElem(); i++ {
                        sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source)
-                       mem = x.storeArgOrLoad(pos, b, base, sel, mem, elt, offset+i*elt.Width, loadRegOffset, storeRc.at(t, 0))
+                       mem = x.storeArgOrLoad(pos, b, sel, mem, elt, offset+i*elt.Width, loadRegOffset, storeRc.at(t, 0))
                        loadRegOffset += eltRO
                        pos = pos.WithNotStmt()
                }
@@ -724,13 +742,13 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *
                        // of a *uint8, which does not succeed.
                        t = removeTrivialWrapperTypes(t)
                        // it could be a leaf type, but the "leaf" could be complex64 (for example)
-                       return x.storeArgOrLoad(pos, b, base, source, mem, t, offset, loadRegOffset, storeRc)
+                       return x.storeArgOrLoad(pos, b, source, mem, t, offset, loadRegOffset, storeRc)
                }
 
                for i := 0; i < t.NumFields(); i++ {
                        fld := t.Field(i)
                        sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source)
-                       mem = x.storeArgOrLoad(pos, b, base, sel, mem, fld.Type, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type))
+                       mem = x.storeArgOrLoad(pos, b, sel, mem, fld.Type, offset+fld.Offset, loadRegOffset, storeRc.next(fld.Type))
                        loadRegOffset += x.regWidth(fld.Type)
                        pos = pos.WithNotStmt()
                }
@@ -742,48 +760,48 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *
                }
                tHi, tLo := x.intPairTypes(t.Kind())
                sel := source.Block.NewValue1(pos, OpInt64Hi, tHi, source)
-               mem = x.storeArgOrLoad(pos, b, base, sel, mem, tHi, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo))
+               mem = x.storeArgOrLoad(pos, b, sel, mem, tHi, offset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo))
                pos = pos.WithNotStmt()
                sel = source.Block.NewValue1(pos, OpInt64Lo, tLo, source)
-               return x.storeArgOrLoad(pos, b, base, sel, mem, tLo, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.hiRo))
+               return x.storeArgOrLoad(pos, b, sel, mem, tLo, offset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.hiRo))
 
        case types.TINTER:
                sel := source.Block.NewValue1(pos, OpITab, x.typs.BytePtr, source)
-               mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr))
+               mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr))
                pos = pos.WithNotStmt()
                sel = source.Block.NewValue1(pos, OpIData, x.typs.BytePtr, source)
-               return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset+x.ptrSize, loadRegOffset+RO_iface_data, storeRc)
+               return x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset+x.ptrSize, loadRegOffset+RO_iface_data, storeRc)
 
        case types.TSTRING:
                sel := source.Block.NewValue1(pos, OpStringPtr, x.typs.BytePtr, source)
-               mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr))
+               mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, offset, loadRegOffset, storeRc.next(x.typs.BytePtr))
                pos = pos.WithNotStmt()
                sel = source.Block.NewValue1(pos, OpStringLen, x.typs.Int, source)
-               return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_string_len, storeRc)
+               return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_string_len, storeRc)
 
        case types.TSLICE:
                et := types.NewPtr(t.Elem())
                sel := source.Block.NewValue1(pos, OpSlicePtr, et, source)
-               mem = x.storeArgOrLoad(pos, b, base, sel, mem, et, offset, loadRegOffset, storeRc.next(et))
+               mem = x.storeArgOrLoad(pos, b, sel, mem, et, offset, loadRegOffset, storeRc.next(et))
                pos = pos.WithNotStmt()
                sel = source.Block.NewValue1(pos, OpSliceLen, x.typs.Int, source)
-               mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc.next(x.typs.Int))
+               mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc.next(x.typs.Int))
                sel = source.Block.NewValue1(pos, OpSliceCap, x.typs.Int, source)
-               return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Int, offset+2*x.ptrSize, loadRegOffset+RO_slice_cap, storeRc)
+               return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, offset+2*x.ptrSize, loadRegOffset+RO_slice_cap, storeRc)
 
        case types.TCOMPLEX64:
                sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float32, source)
-               mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float32, offset, loadRegOffset, storeRc.next(x.typs.Float32))
+               mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, offset, loadRegOffset, storeRc.next(x.typs.Float32))
                pos = pos.WithNotStmt()
                sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float32, source)
-               return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float32, offset+4, loadRegOffset+RO_complex_imag, storeRc)
+               return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, offset+4, loadRegOffset+RO_complex_imag, storeRc)
 
        case types.TCOMPLEX128:
                sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float64, source)
-               mem = x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float64, offset, loadRegOffset, storeRc.next(x.typs.Float64))
+               mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, offset, loadRegOffset, storeRc.next(x.typs.Float64))
                pos = pos.WithNotStmt()
                sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float64, source)
-               return x.storeArgOrLoad(pos, b, base, sel, mem, x.typs.Float64, offset+8, loadRegOffset+RO_complex_imag, storeRc)
+               return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, offset+8, loadRegOffset+RO_complex_imag, storeRc)
        }
 
        s := mem
@@ -791,7 +809,7 @@ func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, base, source, mem *
                // TODO(register args)
                storeRc.addArg(source)
        } else {
-               dst := x.offsetFrom(base, offset, types.NewPtr(t))
+               dst := x.offsetFrom(storeRc.storeDest, offset, types.NewPtr(t))
                s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem)
        }
        if x.debug {
@@ -843,8 +861,8 @@ func (x *expandState) rewriteArgs(v *Value, firstArg int) *Value {
                        if x.debug {
                                fmt.Printf("storeArg %s, %v, %d\n", a.LongString(), aType, aOffset)
                        }
-                       rc.init(aRegs, aux.abiInfo, result)
-                       mem = x.storeArgOrLoad(pos, v.Block, x.sp, a, mem, aType, aOffset, 0, rc)
+                       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
                }
        }
@@ -959,9 +977,9 @@ func expandCalls(f *Func) {
                                        if len(aRegs) > 0 {
                                                result = &allResults
                                        }
-                                       rc.init(aRegs, aux.abiInfo, result)
-                                       // TODO(register args)
-                                       mem = x.storeArgOrLoad(v.Pos, b, auxBase, a, mem, aux.TypeOfResult(i), auxOffset, 0, rc)
+                                       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
                                }
                        }
@@ -1005,7 +1023,7 @@ func expandCalls(f *Func) {
                                                fmt.Printf("Splitting store %s\n", v.LongString())
                                        }
                                        dst, mem := v.Args[0], v.Args[2]
-                                       mem = x.storeArgOrLoad(v.Pos, b, dst, source, mem, t, 0, 0, registerCursor{})
+                                       mem = x.storeArgOrLoad(v.Pos, b, source, mem, t, 0, 0, registerCursor{storeDest: dst})
                                        v.copyOf(mem)
                                }
                        }