]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/ssa/expand_calls.go
26a944dfaeb8c5779142cad588c2247d201440f8
[gostls13.git] / src / cmd / compile / internal / ssa / expand_calls.go
1 // Copyright 2020 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
4
5 package ssa
6
7 import (
8         "cmd/compile/internal/abi"
9         "cmd/compile/internal/base"
10         "cmd/compile/internal/ir"
11         "cmd/compile/internal/types"
12         "cmd/internal/src"
13         "fmt"
14         "sort"
15 )
16
17 type selKey struct {
18         from          *Value // what is selected from
19         offsetOrIndex int64  // whatever is appropriate for the selector
20         size          int64
21         typ           *types.Type
22 }
23
24 type Abi1RO uint8 // An offset within a parameter's slice of register indices, for abi1.
25
26 func isBlockMultiValueExit(b *Block) bool {
27         return (b.Kind == BlockRet || b.Kind == BlockRetJmp) && b.Controls[0] != nil && b.Controls[0].Op == OpMakeResult
28 }
29
30 func badVal(s string, v *Value) error {
31         return fmt.Errorf("%s %s", s, v.LongString())
32 }
33
34 // removeTrivialWrapperTypes unwraps layers of
35 // struct { singleField SomeType } and [1]SomeType
36 // until a non-wrapper type is reached.  This is useful
37 // for working with assignments to/from interface data
38 // fields (either second operand to OpIMake or OpIData)
39 // where the wrapping or type conversion can be elided
40 // because of type conversions/assertions in source code
41 // that do not appear in SSA.
42 func removeTrivialWrapperTypes(t *types.Type) *types.Type {
43         for {
44                 if t.IsStruct() && t.NumFields() == 1 {
45                         t = t.Field(0).Type
46                         continue
47                 }
48                 if t.IsArray() && t.NumElem() == 1 {
49                         t = t.Elem()
50                         continue
51                 }
52                 break
53         }
54         return t
55 }
56
57 // A registerCursor tracks which register is used for an Arg or regValues, or a piece of such.
58 type registerCursor struct {
59         // TODO(register args) convert this to a generalized target cursor.
60         storeDest *Value // if there are no register targets, then this is the base of the store.
61         regsLen   int    // the number of registers available for this Arg/result (which is all in registers or not at all)
62         nextSlice Abi1RO // the next register/register-slice offset
63         config    *abi.ABIConfig
64         regValues *[]*Value // values assigned to registers accumulate here
65 }
66
67 func (rc *registerCursor) String() string {
68         dest := "<none>"
69         if rc.storeDest != nil {
70                 dest = rc.storeDest.String()
71         }
72         regs := "<none>"
73         if rc.regValues != nil {
74                 regs = ""
75                 for i, x := range *rc.regValues {
76                         if i > 0 {
77                                 regs = regs + "; "
78                         }
79                         regs = regs + x.LongString()
80                 }
81         }
82         // not printing the config because that has not been useful
83         return fmt.Sprintf("RCSR{storeDest=%v, regsLen=%d, nextSlice=%d, regValues=[%s]}", dest, rc.regsLen, rc.nextSlice, regs)
84 }
85
86 // next effectively post-increments the register cursor; the receiver is advanced,
87 // the old value is returned.
88 func (c *registerCursor) next(t *types.Type) registerCursor {
89         rc := *c
90         if int(c.nextSlice) < c.regsLen {
91                 w := c.config.NumParamRegs(t)
92                 c.nextSlice += Abi1RO(w)
93         }
94         return rc
95 }
96
97 // plus returns a register cursor offset from the original, without modifying the original.
98 func (c *registerCursor) plus(regWidth Abi1RO) registerCursor {
99         rc := *c
100         rc.nextSlice += regWidth
101         return rc
102 }
103
104 const (
105         // Register offsets for fields of built-in aggregate types; the ones not listed are zero.
106         RO_complex_imag = 1
107         RO_string_len   = 1
108         RO_slice_len    = 1
109         RO_slice_cap    = 2
110         RO_iface_data   = 1
111 )
112
113 func (x *expandState) regWidth(t *types.Type) Abi1RO {
114         return Abi1RO(x.abi1.NumParamRegs(t))
115 }
116
117 // regOffset returns the register offset of the i'th element of type t
118 func (x *expandState) regOffset(t *types.Type, i int) Abi1RO {
119         // TODO maybe cache this in a map if profiling recommends.
120         if i == 0 {
121                 return 0
122         }
123         if t.IsArray() {
124                 return Abi1RO(i) * x.regWidth(t.Elem())
125         }
126         if t.IsStruct() {
127                 k := Abi1RO(0)
128                 for j := 0; j < i; j++ {
129                         k += x.regWidth(t.FieldType(j))
130                 }
131                 return k
132         }
133         panic("Haven't implemented this case yet, do I need to?")
134 }
135
136 // at returns the register cursor for component i of t, where the first
137 // component is numbered 0.
138 func (c *registerCursor) at(t *types.Type, i int) registerCursor {
139         rc := *c
140         if i == 0 || c.regsLen == 0 {
141                 return rc
142         }
143         if t.IsArray() {
144                 w := c.config.NumParamRegs(t.Elem())
145                 rc.nextSlice += Abi1RO(i * w)
146                 return rc
147         }
148         if t.IsStruct() {
149                 for j := 0; j < i; j++ {
150                         rc.next(t.FieldType(j))
151                 }
152                 return rc
153         }
154         panic("Haven't implemented this case yet, do I need to?")
155 }
156
157 func (c *registerCursor) init(regs []abi.RegIndex, info *abi.ABIParamResultInfo, result *[]*Value, storeDest *Value) {
158         c.regsLen = len(regs)
159         c.nextSlice = 0
160         if len(regs) == 0 {
161                 c.storeDest = storeDest // only save this if there are no registers, will explode if misused.
162                 return
163         }
164         c.config = info.Config()
165         c.regValues = result
166 }
167
168 func (c *registerCursor) addArg(v *Value) {
169         *c.regValues = append(*c.regValues, v)
170 }
171
172 func (c *registerCursor) hasRegs() bool {
173         return c.regsLen > 0
174 }
175
176 type expandState struct {
177         f                  *Func
178         abi1               *abi.ABIConfig
179         debug              int // odd values log lost statement markers, so likely settings are 1 (stmts), 2 (expansion), and 3 (both)
180         canSSAType         func(*types.Type) bool
181         regSize            int64
182         sp                 *Value
183         typs               *Types
184         ptrSize            int64
185         hiOffset           int64
186         lowOffset          int64
187         hiRo               Abi1RO
188         loRo               Abi1RO
189         namedSelects       map[*Value][]namedVal
190         sdom               SparseTree
191         commonSelectors    map[selKey]*Value // used to de-dupe selectors
192         commonArgs         map[selKey]*Value // used to de-dupe OpArg/OpArgIntReg/OpArgFloatReg
193         memForCall         map[ID]*Value     // For a call, need to know the unique selector that gets the mem.
194         transformedSelects map[ID]bool       // OpSelectN after rewriting, either created or renumbered.
195         indentLevel        int               // Indentation for debugging recursion
196 }
197
198 // intPairTypes returns the pair of 32-bit int types needed to encode a 64-bit integer type on a target
199 // that has no 64-bit integer registers.
200 func (x *expandState) intPairTypes(et types.Kind) (tHi, tLo *types.Type) {
201         tHi = x.typs.UInt32
202         if et == types.TINT64 {
203                 tHi = x.typs.Int32
204         }
205         tLo = x.typs.UInt32
206         return
207 }
208
209 // isAlreadyExpandedAggregateType returns whether a type is an SSA-able "aggregate" (multiple register) type
210 // that was expanded in an earlier phase (currently, expand_calls is intended to run after decomposeBuiltin,
211 // so this is all aggregate types -- small struct and array, complex, interface, string, slice, and 64-bit
212 // integer on 32-bit).
213 func (x *expandState) isAlreadyExpandedAggregateType(t *types.Type) bool {
214         if !x.canSSAType(t) {
215                 return false
216         }
217         return t.IsStruct() || t.IsArray() || t.IsComplex() || t.IsInterface() || t.IsString() || t.IsSlice() ||
218                 (t.Size() > x.regSize && (t.IsInteger() || (x.f.Config.SoftFloat && t.IsFloat())))
219 }
220
221 // offsetFrom creates an offset from a pointer, simplifying chained offsets and offsets from SP
222 // TODO should also optimize offsets from SB?
223 func (x *expandState) offsetFrom(b *Block, from *Value, offset int64, pt *types.Type) *Value {
224         ft := from.Type
225         if offset == 0 {
226                 if ft == pt {
227                         return from
228                 }
229                 // This captures common, (apparently) safe cases.  The unsafe cases involve ft == uintptr
230                 if (ft.IsPtr() || ft.IsUnsafePtr()) && pt.IsPtr() {
231                         return from
232                 }
233         }
234         // Simplify, canonicalize
235         for from.Op == OpOffPtr {
236                 offset += from.AuxInt
237                 from = from.Args[0]
238         }
239         if from == x.sp {
240                 return x.f.ConstOffPtrSP(pt, offset, x.sp)
241         }
242         return b.NewValue1I(from.Pos.WithNotStmt(), OpOffPtr, pt, offset, from)
243 }
244
245 // splitSlots splits one "field" (specified by sfx, offset, and ty) out of the LocalSlots in ls and returns the new LocalSlots this generates.
246 func (x *expandState) splitSlots(ls []*LocalSlot, sfx string, offset int64, ty *types.Type) []*LocalSlot {
247         var locs []*LocalSlot
248         for i := range ls {
249                 locs = append(locs, x.f.SplitSlot(ls[i], sfx, offset, ty))
250         }
251         return locs
252 }
253
254 // prAssignForArg returns the ABIParamAssignment for v, assumed to be an OpArg.
255 func (x *expandState) prAssignForArg(v *Value) *abi.ABIParamAssignment {
256         if v.Op != OpArg {
257                 panic(badVal("Wanted OpArg, instead saw", v))
258         }
259         return ParamAssignmentForArgName(x.f, v.Aux.(*ir.Name))
260 }
261
262 // ParamAssignmentForArgName returns the ABIParamAssignment for f's arg with matching name.
263 func ParamAssignmentForArgName(f *Func, name *ir.Name) *abi.ABIParamAssignment {
264         abiInfo := f.OwnAux.abiInfo
265         ip := abiInfo.InParams()
266         for i, a := range ip {
267                 if a.Name == name {
268                         return &ip[i]
269                 }
270         }
271         panic(fmt.Errorf("Did not match param %v in prInfo %+v", name, abiInfo.InParams()))
272 }
273
274 // indent increments (or decrements) the indentation.
275 func (x *expandState) indent(n int) {
276         x.indentLevel += n
277 }
278
279 // Printf does an indented fmt.Printf on te format and args.
280 func (x *expandState) Printf(format string, a ...interface{}) (n int, err error) {
281         if x.indentLevel > 0 {
282                 fmt.Printf("%[1]*s", x.indentLevel, "")
283         }
284         return fmt.Printf(format, a...)
285 }
286
287 // Calls that need lowering have some number of inputs, including a memory input,
288 // and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able.
289
290 // With the current ABI those inputs need to be converted into stores to memory,
291 // rethreading the call's memory input to the first, and the new call now receiving the last.
292
293 // With the current ABI, the outputs need to be converted to loads, which will all use the call's
294 // memory output as their input.
295
296 // rewriteSelect recursively walks from leaf selector to a root (OpSelectN, OpLoad, OpArg)
297 // through a chain of Struct/Array/builtin Select operations.  If the chain of selectors does not
298 // end in an expected root, it does nothing (this can happen depending on compiler phase ordering).
299 // The "leaf" provides the type, the root supplies the container, and the leaf-to-root path
300 // accumulates the offset.
301 // It emits the code necessary to implement the leaf select operation that leads to the root.
302 //
303 // TODO when registers really arrive, must also decompose anything split across two registers or registers and memory.
304 func (x *expandState) rewriteSelect(leaf *Value, selector *Value, offset int64, regOffset Abi1RO) []*LocalSlot {
305         if x.debug > 1 {
306                 x.indent(3)
307                 defer x.indent(-3)
308                 x.Printf("rewriteSelect(%s; %s; memOff=%d; regOff=%d)\n", leaf.LongString(), selector.LongString(), offset, regOffset)
309         }
310         var locs []*LocalSlot
311         leafType := leaf.Type
312         if len(selector.Args) > 0 {
313                 w := selector.Args[0]
314                 if w.Op == OpCopy {
315                         for w.Op == OpCopy {
316                                 w = w.Args[0]
317                         }
318                         selector.SetArg(0, w)
319                 }
320         }
321         switch selector.Op {
322         case OpArgIntReg, OpArgFloatReg:
323                 if leafType == selector.Type { // OpIData leads us here, sometimes.
324                         leaf.copyOf(selector)
325                 } else {
326                         x.f.Fatalf("Unexpected %s type, selector=%s, leaf=%s\n", selector.Op.String(), selector.LongString(), leaf.LongString())
327                 }
328                 if x.debug > 1 {
329                         x.Printf("---%s, break\n", selector.Op.String())
330                 }
331         case OpArg:
332                 if !x.isAlreadyExpandedAggregateType(selector.Type) {
333                         if leafType == selector.Type { // OpIData leads us here, sometimes.
334                                 x.newArgToMemOrRegs(selector, leaf, offset, regOffset, leafType, leaf.Pos)
335                         } else {
336                                 x.f.Fatalf("Unexpected OpArg type, selector=%s, leaf=%s\n", selector.LongString(), leaf.LongString())
337                         }
338                         if x.debug > 1 {
339                                 x.Printf("---OpArg, break\n")
340                         }
341                         break
342                 }
343                 switch leaf.Op {
344                 case OpIData, OpStructSelect, OpArraySelect:
345                         leafType = removeTrivialWrapperTypes(leaf.Type)
346                 }
347                 x.newArgToMemOrRegs(selector, leaf, offset, regOffset, leafType, leaf.Pos)
348
349                 for _, s := range x.namedSelects[selector] {
350                         locs = append(locs, x.f.Names[s.locIndex])
351                 }
352
353         case OpLoad: // We end up here because of IData of immediate structures.
354                 // Failure case:
355                 // (note the failure case is very rare; w/o this case, make.bash and run.bash both pass, as well as
356                 // the hard cases of building {syscall,math,math/cmplx,math/bits,go/constant} on ppc64le and mips-softfloat).
357                 //
358                 // GOSSAFUNC='(*dumper).dump' go build -gcflags=-l -tags=math_big_pure_go cmd/compile/internal/gc
359                 // cmd/compile/internal/gc/dump.go:136:14: internal compiler error: '(*dumper).dump': not lowered: v827, StructSelect PTR PTR
360                 // b2: ← b1
361                 // v20 (+142) = StaticLECall <interface {},mem> {AuxCall{reflect.Value.Interface([reflect.Value,0])[interface {},24]}} [40] v8 v1
362                 // v21 (142) = SelectN <mem> [1] v20
363                 // v22 (142) = SelectN <interface {}> [0] v20
364                 // b15: ← b8
365                 // v71 (+143) = IData <Nodes> v22 (v[Nodes])
366                 // v73 (+146) = StaticLECall <[]*Node,mem> {AuxCall{"".Nodes.Slice([Nodes,0])[[]*Node,8]}} [32] v71 v21
367                 //
368                 // translates (w/o the "case OpLoad:" above) to:
369                 //
370                 // b2: ← b1
371                 // v20 (+142) = StaticCall <mem> {AuxCall{reflect.Value.Interface([reflect.Value,0])[interface {},24]}} [40] v715
372                 // v23 (142) = Load <*uintptr> v19 v20
373                 // v823 (142) = IsNonNil <bool> v23
374                 // v67 (+143) = Load <*[]*Node> v880 v20
375                 // b15: ← b8
376                 // v827 (146) = StructSelect <*[]*Node> [0] v67
377                 // v846 (146) = Store <mem> {*[]*Node} v769 v827 v20
378                 // v73 (+146) = StaticCall <mem> {AuxCall{"".Nodes.Slice([Nodes,0])[[]*Node,8]}} [32] v846
379                 // i.e., the struct select is generated and remains in because it is not applied to an actual structure.
380                 // The OpLoad was created to load the single field of the IData
381                 // This case removes that StructSelect.
382                 if leafType != selector.Type {
383                         if x.f.Config.SoftFloat && selector.Type.IsFloat() {
384                                 if x.debug > 1 {
385                                         x.Printf("---OpLoad, break\n")
386                                 }
387                                 break // softfloat pass will take care of that
388                         }
389                         x.f.Fatalf("Unexpected Load as selector, leaf=%s, selector=%s\n", leaf.LongString(), selector.LongString())
390                 }
391                 leaf.copyOf(selector)
392                 for _, s := range x.namedSelects[selector] {
393                         locs = append(locs, x.f.Names[s.locIndex])
394                 }
395
396         case OpSelectN:
397                 // TODO(register args) result case
398                 // if applied to Op-mumble-call, the Aux tells us which result, regOffset specifies offset within result.  If a register, should rewrite to OpSelectN for new call.
399                 // TODO these may be duplicated. Should memoize. Intermediate selectors will go dead, no worries there.
400                 call := selector.Args[0]
401                 call0 := call
402                 aux := call.Aux.(*AuxCall)
403                 which := selector.AuxInt
404                 if x.transformedSelects[selector.ID] {
405                         // This is a minor hack.  Either this select has had its operand adjusted (mem) or
406                         // it is some other intermediate node that was rewritten to reference a register (not a generic arg).
407                         // This can occur with chains of selection/indexing from single field/element aggregates.
408                         leaf.copyOf(selector)
409                         break
410                 }
411                 if which == aux.NResults() { // mem is after the results.
412                         // rewrite v as a Copy of call -- the replacement call will produce a mem.
413                         if leaf != selector {
414                                 panic(fmt.Errorf("Unexpected selector of memory, selector=%s, call=%s, leaf=%s", selector.LongString(), call.LongString(), leaf.LongString()))
415                         }
416                         if aux.abiInfo == nil {
417                                 panic(badVal("aux.abiInfo nil for call", call))
418                         }
419                         if existing := x.memForCall[call.ID]; existing == nil {
420                                 selector.AuxInt = int64(aux.abiInfo.OutRegistersUsed())
421                                 x.memForCall[call.ID] = selector
422                                 x.transformedSelects[selector.ID] = true // operand adjusted
423                         } else {
424                                 selector.copyOf(existing)
425                         }
426
427                 } else {
428                         leafType := removeTrivialWrapperTypes(leaf.Type)
429                         if x.canSSAType(leafType) {
430                                 pt := types.NewPtr(leafType)
431                                 // Any selection right out of the arg area/registers has to be same Block as call, use call as mem input.
432                                 // Create a "mem" for any loads that need to occur.
433                                 if mem := x.memForCall[call.ID]; mem != nil {
434                                         if mem.Block != call.Block {
435                                                 panic(fmt.Errorf("selector and call need to be in same block, selector=%s; call=%s", selector.LongString(), call.LongString()))
436                                         }
437                                         call = mem
438                                 } else {
439                                         mem = call.Block.NewValue1I(call.Pos.WithNotStmt(), OpSelectN, types.TypeMem, int64(aux.abiInfo.OutRegistersUsed()), call)
440                                         x.transformedSelects[mem.ID] = true // select uses post-expansion indexing
441                                         x.memForCall[call.ID] = mem
442                                         call = mem
443                                 }
444                                 outParam := aux.abiInfo.OutParam(int(which))
445                                 if len(outParam.Registers) > 0 {
446                                         firstReg := uint32(0)
447                                         for i := 0; i < int(which); i++ {
448                                                 firstReg += uint32(len(aux.abiInfo.OutParam(i).Registers))
449                                         }
450                                         reg := int64(regOffset + Abi1RO(firstReg))
451                                         if leaf.Block == call.Block {
452                                                 leaf.reset(OpSelectN)
453                                                 leaf.SetArgs1(call0)
454                                                 leaf.Type = leafType
455                                                 leaf.AuxInt = reg
456                                                 x.transformedSelects[leaf.ID] = true // leaf, rewritten to use post-expansion indexing.
457                                         } else {
458                                                 w := call.Block.NewValue1I(leaf.Pos, OpSelectN, leafType, reg, call0)
459                                                 x.transformedSelects[w.ID] = true // select, using post-expansion indexing.
460                                                 leaf.copyOf(w)
461                                         }
462                                 } else {
463                                         off := x.offsetFrom(x.f.Entry, x.sp, offset+aux.OffsetOfResult(which), pt)
464                                         if leaf.Block == call.Block {
465                                                 leaf.reset(OpLoad)
466                                                 leaf.SetArgs2(off, call)
467                                                 leaf.Type = leafType
468                                         } else {
469                                                 w := call.Block.NewValue2(leaf.Pos, OpLoad, leafType, off, call)
470                                                 leaf.copyOf(w)
471                                                 if x.debug > 1 {
472                                                         x.Printf("---new %s\n", w.LongString())
473                                                 }
474                                         }
475                                 }
476                                 for _, s := range x.namedSelects[selector] {
477                                         locs = append(locs, x.f.Names[s.locIndex])
478                                 }
479                         } else {
480                                 x.f.Fatalf("Should not have non-SSA-able OpSelectN, selector=%s", selector.LongString())
481                         }
482                 }
483
484         case OpStructSelect:
485                 w := selector.Args[0]
486                 var ls []*LocalSlot
487                 if w.Type.Kind() != types.TSTRUCT { // IData artifact
488                         ls = x.rewriteSelect(leaf, w, offset, regOffset)
489                 } else {
490                         fldi := int(selector.AuxInt)
491                         ls = x.rewriteSelect(leaf, w, offset+w.Type.FieldOff(fldi), regOffset+x.regOffset(w.Type, fldi))
492                         if w.Op != OpIData {
493                                 for _, l := range ls {
494                                         locs = append(locs, x.f.SplitStruct(l, int(selector.AuxInt)))
495                                 }
496                         }
497                 }
498
499         case OpArraySelect:
500                 w := selector.Args[0]
501                 index := selector.AuxInt
502                 x.rewriteSelect(leaf, w, offset+selector.Type.Size()*index, regOffset+x.regOffset(w.Type, int(index)))
503
504         case OpInt64Hi:
505                 w := selector.Args[0]
506                 ls := x.rewriteSelect(leaf, w, offset+x.hiOffset, regOffset+x.hiRo)
507                 locs = x.splitSlots(ls, ".hi", x.hiOffset, leafType)
508
509         case OpInt64Lo:
510                 w := selector.Args[0]
511                 ls := x.rewriteSelect(leaf, w, offset+x.lowOffset, regOffset+x.loRo)
512                 locs = x.splitSlots(ls, ".lo", x.lowOffset, leafType)
513
514         case OpStringPtr:
515                 ls := x.rewriteSelect(leaf, selector.Args[0], offset, regOffset)
516                 locs = x.splitSlots(ls, ".ptr", 0, x.typs.BytePtr)
517
518         case OpSlicePtr, OpSlicePtrUnchecked:
519                 w := selector.Args[0]
520                 ls := x.rewriteSelect(leaf, w, offset, regOffset)
521                 locs = x.splitSlots(ls, ".ptr", 0, types.NewPtr(w.Type.Elem()))
522
523         case OpITab:
524                 w := selector.Args[0]
525                 ls := x.rewriteSelect(leaf, w, offset, regOffset)
526                 sfx := ".itab"
527                 if w.Type.IsEmptyInterface() {
528                         sfx = ".type"
529                 }
530                 locs = x.splitSlots(ls, sfx, 0, x.typs.Uintptr)
531
532         case OpComplexReal:
533                 ls := x.rewriteSelect(leaf, selector.Args[0], offset, regOffset)
534                 locs = x.splitSlots(ls, ".real", 0, selector.Type)
535
536         case OpComplexImag:
537                 ls := x.rewriteSelect(leaf, selector.Args[0], offset+selector.Type.Size(), regOffset+RO_complex_imag) // result is FloatNN, width of result is offset of imaginary part.
538                 locs = x.splitSlots(ls, ".imag", selector.Type.Size(), selector.Type)
539
540         case OpStringLen, OpSliceLen:
541                 ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize, regOffset+RO_slice_len)
542                 locs = x.splitSlots(ls, ".len", x.ptrSize, leafType)
543
544         case OpIData:
545                 ls := x.rewriteSelect(leaf, selector.Args[0], offset+x.ptrSize, regOffset+RO_iface_data)
546                 locs = x.splitSlots(ls, ".data", x.ptrSize, leafType)
547
548         case OpSliceCap:
549                 ls := x.rewriteSelect(leaf, selector.Args[0], offset+2*x.ptrSize, regOffset+RO_slice_cap)
550                 locs = x.splitSlots(ls, ".cap", 2*x.ptrSize, leafType)
551
552         case OpCopy: // If it's an intermediate result, recurse
553                 locs = x.rewriteSelect(leaf, selector.Args[0], offset, regOffset)
554                 for _, s := range x.namedSelects[selector] {
555                         // this copy may have had its own name, preserve that, too.
556                         locs = append(locs, x.f.Names[s.locIndex])
557                 }
558
559         default:
560                 // Ignore dead ends. These can occur if this phase is run before decompose builtin (which is not intended, but allowed).
561         }
562
563         return locs
564 }
565
566 func (x *expandState) rewriteDereference(b *Block, base, a, mem *Value, offset, size int64, typ *types.Type, pos src.XPos) *Value {
567         source := a.Args[0]
568         dst := x.offsetFrom(b, base, offset, source.Type)
569         if a.Uses == 1 && a.Block == b {
570                 a.reset(OpMove)
571                 a.Pos = pos
572                 a.Type = types.TypeMem
573                 a.Aux = typ
574                 a.AuxInt = size
575                 a.SetArgs3(dst, source, mem)
576                 mem = a
577         } else {
578                 mem = b.NewValue3A(pos, OpMove, types.TypeMem, typ, dst, source, mem)
579                 mem.AuxInt = size
580         }
581         return mem
582 }
583
584 var indexNames [1]string = [1]string{"[0]"}
585
586 // pathTo returns the selection path to the leaf type at offset within container.
587 // e.g. len(thing.field[0]) => ".field[0].len"
588 // this is for purposes of generating names ultimately fed to a debugger.
589 func (x *expandState) pathTo(container, leaf *types.Type, offset int64) string {
590         if container == leaf || offset == 0 && container.Size() == leaf.Size() {
591                 return ""
592         }
593         path := ""
594 outer:
595         for {
596                 switch container.Kind() {
597                 case types.TARRAY:
598                         container = container.Elem()
599                         if container.Size() == 0 {
600                                 return path
601                         }
602                         i := offset / container.Size()
603                         offset = offset % container.Size()
604                         // If a future compiler/ABI supports larger SSA/Arg-able arrays, expand indexNames.
605                         path = path + indexNames[i]
606                         continue
607                 case types.TSTRUCT:
608                         for i := 0; i < container.NumFields(); i++ {
609                                 fld := container.Field(i)
610                                 if fld.Offset+fld.Type.Size() > offset {
611                                         offset -= fld.Offset
612                                         path += "." + fld.Sym.Name
613                                         container = fld.Type
614                                         continue outer
615                                 }
616                         }
617                         return path
618                 case types.TINT64, types.TUINT64:
619                         if container.Size() == x.regSize {
620                                 return path
621                         }
622                         if offset == x.hiOffset {
623                                 return path + ".hi"
624                         }
625                         return path + ".lo"
626                 case types.TINTER:
627                         if offset != 0 {
628                                 return path + ".data"
629                         }
630                         if container.IsEmptyInterface() {
631                                 return path + ".type"
632                         }
633                         return path + ".itab"
634
635                 case types.TSLICE:
636                         if offset == 2*x.regSize {
637                                 return path + ".cap"
638                         }
639                         fallthrough
640                 case types.TSTRING:
641                         if offset == 0 {
642                                 return path + ".ptr"
643                         }
644                         return path + ".len"
645                 case types.TCOMPLEX64, types.TCOMPLEX128:
646                         if offset == 0 {
647                                 return path + ".real"
648                         }
649                         return path + ".imag"
650                 }
651                 return path
652         }
653 }
654
655 // decomposeArg is a helper for storeArgOrLoad.
656 // It decomposes a Load or an Arg into smaller parts and returns the new mem.
657 // If the type does not match one of the expected aggregate types, it returns nil instead.
658 // Parameters:
659 //
660 //      pos           -- the location of any generated code.
661 //      b             -- the block into which any generated code should normally be placed
662 //      source        -- the value, possibly an aggregate, to be stored.
663 //      mem           -- the mem flowing into this decomposition (loads depend on it, stores updated it)
664 //      t             -- the type of the value to be stored
665 //      storeOffset   -- if the value is stored in memory, it is stored at base (see storeRc) + storeOffset
666 //      loadRegOffset -- regarding source as a value in registers, the register offset in ABI1.  Meaningful only if source is OpArg.
667 //      storeRc       -- storeRC; if the value is stored in registers, this specifies the registers.
668 //                       StoreRc also identifies whether the target is registers or memory, and has the base for the store operation.
669 func (x *expandState) decomposeArg(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
670
671         pa := x.prAssignForArg(source)
672         var locs []*LocalSlot
673         for _, s := range x.namedSelects[source] {
674                 locs = append(locs, x.f.Names[s.locIndex])
675         }
676
677         if len(pa.Registers) > 0 {
678                 // Handle the in-registers case directly
679                 rts, offs := pa.RegisterTypesAndOffsets()
680                 last := loadRegOffset + x.regWidth(t)
681                 if offs[loadRegOffset] != 0 {
682                         // Document the problem before panicking.
683                         for i := 0; i < len(rts); i++ {
684                                 rt := rts[i]
685                                 off := offs[i]
686                                 fmt.Printf("rt=%s, off=%d, rt.Width=%d, rt.Align=%d\n", rt.String(), off, rt.Size(), uint8(rt.Alignment()))
687                         }
688                         panic(fmt.Errorf("offset %d of requested register %d should be zero, source=%s", offs[loadRegOffset], loadRegOffset, source.LongString()))
689                 }
690
691                 if x.debug > 1 {
692                         x.Printf("decompose arg %s has %d locs\n", source.LongString(), len(locs))
693                 }
694
695                 for i := loadRegOffset; i < last; i++ {
696                         rt := rts[i]
697                         off := offs[i]
698                         w := x.commonArgs[selKey{source, off, rt.Size(), rt}]
699                         if w == nil {
700                                 w = x.newArgToMemOrRegs(source, w, off, i, rt, pos)
701                                 suffix := x.pathTo(source.Type, rt, off)
702                                 if suffix != "" {
703                                         x.splitSlotsIntoNames(locs, suffix, off, rt, w)
704                                 }
705                         }
706                         if t.IsPtrShaped() {
707                                 // Preserve the original store type. This ensures pointer type
708                                 // properties aren't discarded (e.g, notinheap).
709                                 if rt.Size() != t.Size() || len(pa.Registers) != 1 || i != loadRegOffset {
710                                         b.Func.Fatalf("incompatible store type %v and %v, i=%d", t, rt, i)
711                                 }
712                                 rt = t
713                         }
714                         mem = x.storeArgOrLoad(pos, b, w, mem, rt, storeOffset+off, i, storeRc.next(rt))
715                 }
716                 return mem
717         }
718
719         u := source.Type
720         switch u.Kind() {
721         case types.TARRAY:
722                 elem := u.Elem()
723                 elemRO := x.regWidth(elem)
724                 for i := int64(0); i < u.NumElem(); i++ {
725                         elemOff := i * elem.Size()
726                         mem = storeOneArg(x, pos, b, locs, indexNames[i], source, mem, elem, elemOff, storeOffset+elemOff, loadRegOffset, storeRc.next(elem))
727                         loadRegOffset += elemRO
728                         pos = pos.WithNotStmt()
729                 }
730                 return mem
731         case types.TSTRUCT:
732                 for i := 0; i < u.NumFields(); i++ {
733                         fld := u.Field(i)
734                         mem = storeOneArg(x, pos, b, locs, "."+fld.Sym.Name, source, mem, fld.Type, fld.Offset, storeOffset+fld.Offset, loadRegOffset, storeRc.next(fld.Type))
735                         loadRegOffset += x.regWidth(fld.Type)
736                         pos = pos.WithNotStmt()
737                 }
738                 return mem
739         case types.TINT64, types.TUINT64:
740                 if t.Size() == x.regSize {
741                         break
742                 }
743                 tHi, tLo := x.intPairTypes(t.Kind())
744                 mem = storeOneArg(x, pos, b, locs, ".hi", source, mem, tHi, x.hiOffset, storeOffset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo))
745                 pos = pos.WithNotStmt()
746                 return storeOneArg(x, pos, b, locs, ".lo", source, mem, tLo, x.lowOffset, storeOffset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo))
747         case types.TINTER:
748                 sfx := ".itab"
749                 if u.IsEmptyInterface() {
750                         sfx = ".type"
751                 }
752                 return storeTwoArg(x, pos, b, locs, sfx, ".idata", source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, storeOffset, loadRegOffset, storeRc)
753         case types.TSTRING:
754                 return storeTwoArg(x, pos, b, locs, ".ptr", ".len", source, mem, x.typs.BytePtr, x.typs.Int, 0, storeOffset, loadRegOffset, storeRc)
755         case types.TCOMPLEX64:
756                 return storeTwoArg(x, pos, b, locs, ".real", ".imag", source, mem, x.typs.Float32, x.typs.Float32, 0, storeOffset, loadRegOffset, storeRc)
757         case types.TCOMPLEX128:
758                 return storeTwoArg(x, pos, b, locs, ".real", ".imag", source, mem, x.typs.Float64, x.typs.Float64, 0, storeOffset, loadRegOffset, storeRc)
759         case types.TSLICE:
760                 mem = storeOneArg(x, pos, b, locs, ".ptr", source, mem, x.typs.BytePtr, 0, storeOffset, loadRegOffset, storeRc.next(x.typs.BytePtr))
761                 return storeTwoArg(x, pos, b, locs, ".len", ".cap", source, mem, x.typs.Int, x.typs.Int, x.ptrSize, storeOffset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc)
762         }
763         return nil
764 }
765
766 func (x *expandState) splitSlotsIntoNames(locs []*LocalSlot, suffix string, off int64, rt *types.Type, w *Value) {
767         wlocs := x.splitSlots(locs, suffix, off, rt)
768         for _, l := range wlocs {
769                 old, ok := x.f.NamedValues[*l]
770                 x.f.NamedValues[*l] = append(old, w)
771                 if !ok {
772                         x.f.Names = append(x.f.Names, l)
773                 }
774         }
775 }
776
777 // decomposeLoad is a helper for storeArgOrLoad.
778 // It decomposes a Load  into smaller parts and returns the new mem.
779 // If the type does not match one of the expected aggregate types, it returns nil instead.
780 // Parameters:
781 //
782 //      pos           -- the location of any generated code.
783 //      b             -- the block into which any generated code should normally be placed
784 //      source        -- the value, possibly an aggregate, to be stored.
785 //      mem           -- the mem flowing into this decomposition (loads depend on it, stores updated it)
786 //      t             -- the type of the value to be stored
787 //      storeOffset   -- if the value is stored in memory, it is stored at base (see storeRc) + offset
788 //      loadRegOffset -- regarding source as a value in registers, the register offset in ABI1.  Meaningful only if source is OpArg.
789 //      storeRc       -- storeRC; if the value is stored in registers, this specifies the registers.
790 //                       StoreRc also identifies whether the target is registers or memory, and has the base for the store operation.
791 //
792 // TODO -- this needs cleanup; it just works for SSA-able aggregates, and won't fully generalize to register-args aggregates.
793 func (x *expandState) decomposeLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
794         u := source.Type
795         switch u.Kind() {
796         case types.TARRAY:
797                 elem := u.Elem()
798                 elemRO := x.regWidth(elem)
799                 for i := int64(0); i < u.NumElem(); i++ {
800                         elemOff := i * elem.Size()
801                         mem = storeOneLoad(x, pos, b, source, mem, elem, elemOff, storeOffset+elemOff, loadRegOffset, storeRc.next(elem))
802                         loadRegOffset += elemRO
803                         pos = pos.WithNotStmt()
804                 }
805                 return mem
806         case types.TSTRUCT:
807                 for i := 0; i < u.NumFields(); i++ {
808                         fld := u.Field(i)
809                         mem = storeOneLoad(x, pos, b, source, mem, fld.Type, fld.Offset, storeOffset+fld.Offset, loadRegOffset, storeRc.next(fld.Type))
810                         loadRegOffset += x.regWidth(fld.Type)
811                         pos = pos.WithNotStmt()
812                 }
813                 return mem
814         case types.TINT64, types.TUINT64:
815                 if t.Size() == x.regSize {
816                         break
817                 }
818                 tHi, tLo := x.intPairTypes(t.Kind())
819                 mem = storeOneLoad(x, pos, b, source, mem, tHi, x.hiOffset, storeOffset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo))
820                 pos = pos.WithNotStmt()
821                 return storeOneLoad(x, pos, b, source, mem, tLo, x.lowOffset, storeOffset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.loRo))
822         case types.TINTER:
823                 return storeTwoLoad(x, pos, b, source, mem, x.typs.Uintptr, x.typs.BytePtr, 0, storeOffset, loadRegOffset, storeRc)
824         case types.TSTRING:
825                 return storeTwoLoad(x, pos, b, source, mem, x.typs.BytePtr, x.typs.Int, 0, storeOffset, loadRegOffset, storeRc)
826         case types.TCOMPLEX64:
827                 return storeTwoLoad(x, pos, b, source, mem, x.typs.Float32, x.typs.Float32, 0, storeOffset, loadRegOffset, storeRc)
828         case types.TCOMPLEX128:
829                 return storeTwoLoad(x, pos, b, source, mem, x.typs.Float64, x.typs.Float64, 0, storeOffset, loadRegOffset, storeRc)
830         case types.TSLICE:
831                 mem = storeOneLoad(x, pos, b, source, mem, x.typs.BytePtr, 0, storeOffset, loadRegOffset, storeRc.next(x.typs.BytePtr))
832                 return storeTwoLoad(x, pos, b, source, mem, x.typs.Int, x.typs.Int, x.ptrSize, storeOffset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc)
833         }
834         return nil
835 }
836
837 // storeOneArg creates a decomposed (one step) arg that is then stored.
838 // pos and b locate the store instruction, source is the "base" of the value input,
839 // mem is the input mem, t is the type in question, and offArg and offStore are the offsets from the respective bases.
840 func storeOneArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix string, source, mem *Value, t *types.Type, argOffset, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
841         if x.debug > 1 {
842                 x.indent(3)
843                 defer x.indent(-3)
844                 x.Printf("storeOneArg(%s;  %s;  %s; aO=%d; sO=%d; lrO=%d; %s)\n", source.LongString(), mem.String(), t.String(), argOffset, storeOffset, loadRegOffset, storeRc.String())
845         }
846
847         w := x.commonArgs[selKey{source, argOffset, t.Size(), t}]
848         if w == nil {
849                 w = x.newArgToMemOrRegs(source, w, argOffset, loadRegOffset, t, pos)
850                 x.splitSlotsIntoNames(locs, suffix, argOffset, t, w)
851         }
852         return x.storeArgOrLoad(pos, b, w, mem, t, storeOffset, loadRegOffset, storeRc)
853 }
854
855 // storeOneLoad creates a decomposed (one step) load that is then stored.
856 func storeOneLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
857         from := x.offsetFrom(source.Block, source.Args[0], offArg, types.NewPtr(t))
858         w := source.Block.NewValue2(source.Pos, OpLoad, t, from, mem)
859         return x.storeArgOrLoad(pos, b, w, mem, t, offStore, loadRegOffset, storeRc)
860 }
861
862 func storeTwoArg(x *expandState, pos src.XPos, b *Block, locs []*LocalSlot, suffix1 string, suffix2 string, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
863         mem = storeOneArg(x, pos, b, locs, suffix1, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
864         pos = pos.WithNotStmt()
865         t1Size := t1.Size()
866         return storeOneArg(x, pos, b, locs, suffix2, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc)
867 }
868
869 // storeTwoLoad creates a pair of decomposed (one step) loads that are then stored.
870 // the elements of the pair must not require any additional alignment.
871 func storeTwoLoad(x *expandState, pos src.XPos, b *Block, source, mem *Value, t1, t2 *types.Type, offArg, offStore int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
872         mem = storeOneLoad(x, pos, b, source, mem, t1, offArg, offStore, loadRegOffset, storeRc.next(t1))
873         pos = pos.WithNotStmt()
874         t1Size := t1.Size()
875         return storeOneLoad(x, pos, b, source, mem, t2, offArg+t1Size, offStore+t1Size, loadRegOffset+1, storeRc)
876 }
877
878 // storeArgOrLoad converts stores of SSA-able potentially aggregatable arguments (passed to a call) into a series of primitive-typed
879 // stores of non-aggregate types.  It recursively walks up a chain of selectors until it reaches a Load or an Arg.
880 // If it does not reach a Load or an Arg, nothing happens; this allows a little freedom in phase ordering.
881 func (x *expandState) storeArgOrLoad(pos src.XPos, b *Block, source, mem *Value, t *types.Type, storeOffset int64, loadRegOffset Abi1RO, storeRc registerCursor) *Value {
882         if x.debug > 1 {
883                 x.indent(3)
884                 defer x.indent(-3)
885                 x.Printf("storeArgOrLoad(%s;  %s;  %s; %d; %s)\n", source.LongString(), mem.String(), t.String(), storeOffset, storeRc.String())
886         }
887
888         // Start with Opcodes that can be disassembled
889         switch source.Op {
890         case OpCopy:
891                 return x.storeArgOrLoad(pos, b, source.Args[0], mem, t, storeOffset, loadRegOffset, storeRc)
892
893         case OpLoad, OpDereference:
894                 ret := x.decomposeLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
895                 if ret != nil {
896                         return ret
897                 }
898
899         case OpArg:
900                 ret := x.decomposeArg(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
901                 if ret != nil {
902                         return ret
903                 }
904
905         case OpArrayMake0, OpStructMake0:
906                 // TODO(register args) is this correct for registers?
907                 return mem
908
909         case OpStructMake1, OpStructMake2, OpStructMake3, OpStructMake4:
910                 for i := 0; i < t.NumFields(); i++ {
911                         fld := t.Field(i)
912                         mem = x.storeArgOrLoad(pos, b, source.Args[i], mem, fld.Type, storeOffset+fld.Offset, 0, storeRc.next(fld.Type))
913                         pos = pos.WithNotStmt()
914                 }
915                 return mem
916
917         case OpArrayMake1:
918                 return x.storeArgOrLoad(pos, b, source.Args[0], mem, t.Elem(), storeOffset, 0, storeRc.at(t, 0))
919
920         case OpInt64Make:
921                 tHi, tLo := x.intPairTypes(t.Kind())
922                 mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tHi, storeOffset+x.hiOffset, 0, storeRc.next(tHi))
923                 pos = pos.WithNotStmt()
924                 return x.storeArgOrLoad(pos, b, source.Args[1], mem, tLo, storeOffset+x.lowOffset, 0, storeRc)
925
926         case OpComplexMake:
927                 tPart := x.typs.Float32
928                 wPart := t.Size() / 2
929                 if wPart == 8 {
930                         tPart = x.typs.Float64
931                 }
932                 mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, tPart, storeOffset, 0, storeRc.next(tPart))
933                 pos = pos.WithNotStmt()
934                 return x.storeArgOrLoad(pos, b, source.Args[1], mem, tPart, storeOffset+wPart, 0, storeRc)
935
936         case OpIMake:
937                 mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.Uintptr, storeOffset, 0, storeRc.next(x.typs.Uintptr))
938                 pos = pos.WithNotStmt()
939                 return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.BytePtr, storeOffset+x.ptrSize, 0, storeRc)
940
941         case OpStringMake:
942                 mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, storeOffset, 0, storeRc.next(x.typs.BytePtr))
943                 pos = pos.WithNotStmt()
944                 return x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, storeOffset+x.ptrSize, 0, storeRc)
945
946         case OpSliceMake:
947                 mem = x.storeArgOrLoad(pos, b, source.Args[0], mem, x.typs.BytePtr, storeOffset, 0, storeRc.next(x.typs.BytePtr))
948                 pos = pos.WithNotStmt()
949                 mem = x.storeArgOrLoad(pos, b, source.Args[1], mem, x.typs.Int, storeOffset+x.ptrSize, 0, storeRc.next(x.typs.Int))
950                 return x.storeArgOrLoad(pos, b, source.Args[2], mem, x.typs.Int, storeOffset+2*x.ptrSize, 0, storeRc)
951         }
952
953         // For nodes that cannot be taken apart -- OpSelectN, other structure selectors.
954         switch t.Kind() {
955         case types.TARRAY:
956                 elt := t.Elem()
957                 if source.Type != t && t.NumElem() == 1 && elt.Size() == t.Size() && t.Size() == x.regSize {
958                         t = removeTrivialWrapperTypes(t)
959                         // it could be a leaf type, but the "leaf" could be complex64 (for example)
960                         return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
961                 }
962                 eltRO := x.regWidth(elt)
963                 source.Type = t
964                 for i := int64(0); i < t.NumElem(); i++ {
965                         sel := source.Block.NewValue1I(pos, OpArraySelect, elt, i, source)
966                         mem = x.storeArgOrLoad(pos, b, sel, mem, elt, storeOffset+i*elt.Size(), loadRegOffset, storeRc.at(t, 0))
967                         loadRegOffset += eltRO
968                         pos = pos.WithNotStmt()
969                 }
970                 return mem
971
972         case types.TSTRUCT:
973                 if source.Type != t && t.NumFields() == 1 && t.Field(0).Type.Size() == t.Size() && t.Size() == x.regSize {
974                         // This peculiar test deals with accesses to immediate interface data.
975                         // It works okay because everything is the same size.
976                         // Example code that triggers this can be found in go/constant/value.go, function ToComplex
977                         // v119 (+881) = IData <intVal> v6
978                         // v121 (+882) = StaticLECall <floatVal,mem> {AuxCall{"".itof([intVal,0])[floatVal,8]}} [16] v119 v1
979                         // This corresponds to the generic rewrite rule "(StructSelect [0] (IData x)) => (IData x)"
980                         // Guard against "struct{struct{*foo}}"
981                         // Other rewriting phases create minor glitches when they transform IData, for instance the
982                         // interface-typed Arg "x" of ToFloat in go/constant/value.go
983                         //   v6 (858) = Arg <Value> {x} (x[Value], x[Value])
984                         // is rewritten by decomposeArgs into
985                         //   v141 (858) = Arg <uintptr> {x}
986                         //   v139 (858) = Arg <*uint8> {x} [8]
987                         // because of a type case clause on line 862 of go/constant/value.go
988                         //      case intVal:
989                         //                 return itof(x)
990                         // v139 is later stored as an intVal == struct{val *big.Int} which naively requires the fields of
991                         // of a *uint8, which does not succeed.
992                         t = removeTrivialWrapperTypes(t)
993                         // it could be a leaf type, but the "leaf" could be complex64 (for example)
994                         return x.storeArgOrLoad(pos, b, source, mem, t, storeOffset, loadRegOffset, storeRc)
995                 }
996
997                 source.Type = t
998                 for i := 0; i < t.NumFields(); i++ {
999                         fld := t.Field(i)
1000                         sel := source.Block.NewValue1I(pos, OpStructSelect, fld.Type, int64(i), source)
1001                         mem = x.storeArgOrLoad(pos, b, sel, mem, fld.Type, storeOffset+fld.Offset, loadRegOffset, storeRc.next(fld.Type))
1002                         loadRegOffset += x.regWidth(fld.Type)
1003                         pos = pos.WithNotStmt()
1004                 }
1005                 return mem
1006
1007         case types.TINT64, types.TUINT64:
1008                 if t.Size() == x.regSize {
1009                         break
1010                 }
1011                 tHi, tLo := x.intPairTypes(t.Kind())
1012                 sel := source.Block.NewValue1(pos, OpInt64Hi, tHi, source)
1013                 mem = x.storeArgOrLoad(pos, b, sel, mem, tHi, storeOffset+x.hiOffset, loadRegOffset+x.hiRo, storeRc.plus(x.hiRo))
1014                 pos = pos.WithNotStmt()
1015                 sel = source.Block.NewValue1(pos, OpInt64Lo, tLo, source)
1016                 return x.storeArgOrLoad(pos, b, sel, mem, tLo, storeOffset+x.lowOffset, loadRegOffset+x.loRo, storeRc.plus(x.hiRo))
1017
1018         case types.TINTER:
1019                 sel := source.Block.NewValue1(pos, OpITab, x.typs.BytePtr, source)
1020                 mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, storeOffset, loadRegOffset, storeRc.next(x.typs.BytePtr))
1021                 pos = pos.WithNotStmt()
1022                 sel = source.Block.NewValue1(pos, OpIData, x.typs.BytePtr, source)
1023                 return x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, storeOffset+x.ptrSize, loadRegOffset+RO_iface_data, storeRc)
1024
1025         case types.TSTRING:
1026                 sel := source.Block.NewValue1(pos, OpStringPtr, x.typs.BytePtr, source)
1027                 mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.BytePtr, storeOffset, loadRegOffset, storeRc.next(x.typs.BytePtr))
1028                 pos = pos.WithNotStmt()
1029                 sel = source.Block.NewValue1(pos, OpStringLen, x.typs.Int, source)
1030                 return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, storeOffset+x.ptrSize, loadRegOffset+RO_string_len, storeRc)
1031
1032         case types.TSLICE:
1033                 et := types.NewPtr(t.Elem())
1034                 sel := source.Block.NewValue1(pos, OpSlicePtr, et, source)
1035                 mem = x.storeArgOrLoad(pos, b, sel, mem, et, storeOffset, loadRegOffset, storeRc.next(et))
1036                 pos = pos.WithNotStmt()
1037                 sel = source.Block.NewValue1(pos, OpSliceLen, x.typs.Int, source)
1038                 mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, storeOffset+x.ptrSize, loadRegOffset+RO_slice_len, storeRc.next(x.typs.Int))
1039                 sel = source.Block.NewValue1(pos, OpSliceCap, x.typs.Int, source)
1040                 return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Int, storeOffset+2*x.ptrSize, loadRegOffset+RO_slice_cap, storeRc)
1041
1042         case types.TCOMPLEX64:
1043                 sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float32, source)
1044                 mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, storeOffset, loadRegOffset, storeRc.next(x.typs.Float32))
1045                 pos = pos.WithNotStmt()
1046                 sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float32, source)
1047                 return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float32, storeOffset+4, loadRegOffset+RO_complex_imag, storeRc)
1048
1049         case types.TCOMPLEX128:
1050                 sel := source.Block.NewValue1(pos, OpComplexReal, x.typs.Float64, source)
1051                 mem = x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, storeOffset, loadRegOffset, storeRc.next(x.typs.Float64))
1052                 pos = pos.WithNotStmt()
1053                 sel = source.Block.NewValue1(pos, OpComplexImag, x.typs.Float64, source)
1054                 return x.storeArgOrLoad(pos, b, sel, mem, x.typs.Float64, storeOffset+8, loadRegOffset+RO_complex_imag, storeRc)
1055         }
1056
1057         s := mem
1058         if source.Op == OpDereference {
1059                 source.Op = OpLoad // For purposes of parameter passing expansion, a Dereference is a Load.
1060         }
1061         if storeRc.hasRegs() {
1062                 storeRc.addArg(source)
1063         } else {
1064                 dst := x.offsetFrom(b, storeRc.storeDest, storeOffset, types.NewPtr(t))
1065                 s = b.NewValue3A(pos, OpStore, types.TypeMem, t, dst, source, mem)
1066         }
1067         if x.debug > 1 {
1068                 x.Printf("-->storeArg returns %s, storeRc=%s\n", s.LongString(), storeRc.String())
1069         }
1070         return s
1071 }
1072
1073 // rewriteArgs replaces all the call-parameter Args to a call with their register translation (if any).
1074 // Preceding parameters (code pointers, closure pointer) are preserved, and the memory input is modified
1075 // to account for any parameter stores required.
1076 // Any of the old Args that have their use count fall to zero are marked OpInvalid.
1077 func (x *expandState) rewriteArgs(v *Value, firstArg int) {
1078         if x.debug > 1 {
1079                 x.indent(3)
1080                 defer x.indent(-3)
1081                 x.Printf("rewriteArgs(%s; %d)\n", v.LongString(), firstArg)
1082         }
1083         // Thread the stores on the memory arg
1084         aux := v.Aux.(*AuxCall)
1085         m0 := v.MemoryArg()
1086         mem := m0
1087         newArgs := []*Value{}
1088         oldArgs := []*Value{}
1089         sp := x.sp
1090         if v.Op == OpTailLECall {
1091                 // For tail call, we unwind the frame before the call so we'll use the caller's
1092                 // SP.
1093                 sp = x.f.Entry.NewValue1(src.NoXPos, OpGetCallerSP, x.typs.Uintptr, mem)
1094         }
1095         for i, a := range v.Args[firstArg : len(v.Args)-1] { // skip leading non-parameter SSA Args and trailing mem SSA Arg.
1096                 oldArgs = append(oldArgs, a)
1097                 auxI := int64(i)
1098                 aRegs := aux.RegsOfArg(auxI)
1099                 aType := aux.TypeOfArg(auxI)
1100                 if len(aRegs) == 0 && a.Op == OpDereference {
1101                         aOffset := aux.OffsetOfArg(auxI)
1102                         if a.MemoryArg() != m0 {
1103                                 x.f.Fatalf("Op...LECall and OpDereference have mismatched mem, %s and %s", v.LongString(), a.LongString())
1104                         }
1105                         if v.Op == OpTailLECall {
1106                                 // It's common for a tail call passing the same arguments (e.g. method wrapper),
1107                                 // so this would be a self copy. Detect this and optimize it out.
1108                                 a0 := a.Args[0]
1109                                 if a0.Op == OpLocalAddr {
1110                                         n := a0.Aux.(*ir.Name)
1111                                         if n.Class == ir.PPARAM && n.FrameOffset()+x.f.Config.ctxt.Arch.FixedFrameSize == aOffset {
1112                                                 continue
1113                                         }
1114                                 }
1115                         }
1116                         // "Dereference" of addressed (probably not-SSA-eligible) value becomes Move
1117                         // TODO(register args) this will be more complicated with registers in the picture.
1118                         mem = x.rewriteDereference(v.Block, sp, a, mem, aOffset, aux.SizeOfArg(auxI), aType, a.Pos)
1119                 } else {
1120                         var rc registerCursor
1121                         var result *[]*Value
1122                         var aOffset int64
1123                         if len(aRegs) > 0 {
1124                                 result = &newArgs
1125                         } else {
1126                                 aOffset = aux.OffsetOfArg(auxI)
1127                         }
1128                         if v.Op == OpTailLECall && a.Op == OpArg && a.AuxInt == 0 {
1129                                 // It's common for a tail call passing the same arguments (e.g. method wrapper),
1130                                 // so this would be a self copy. Detect this and optimize it out.
1131                                 n := a.Aux.(*ir.Name)
1132                                 if n.Class == ir.PPARAM && n.FrameOffset()+x.f.Config.ctxt.Arch.FixedFrameSize == aOffset {
1133                                         continue
1134                                 }
1135                         }
1136                         if x.debug > 1 {
1137                                 x.Printf("...storeArg %s, %v, %d\n", a.LongString(), aType, aOffset)
1138                         }
1139                         rc.init(aRegs, aux.abiInfo, result, sp)
1140                         mem = x.storeArgOrLoad(a.Pos, v.Block, a, mem, aType, aOffset, 0, rc)
1141                 }
1142         }
1143         var preArgStore [2]*Value
1144         preArgs := append(preArgStore[:0], v.Args[0:firstArg]...)
1145         v.resetArgs()
1146         v.AddArgs(preArgs...)
1147         v.AddArgs(newArgs...)
1148         v.AddArg(mem)
1149         for _, a := range oldArgs {
1150                 if a.Uses == 0 {
1151                         x.invalidateRecursively(a)
1152                 }
1153         }
1154
1155         return
1156 }
1157
1158 func (x *expandState) invalidateRecursively(a *Value) {
1159         var s string
1160         if x.debug > 0 {
1161                 plus := " "
1162                 if a.Pos.IsStmt() == src.PosIsStmt {
1163                         plus = " +"
1164                 }
1165                 s = a.String() + plus + a.Pos.LineNumber() + " " + a.LongString()
1166                 if x.debug > 1 {
1167                         x.Printf("...marking %v unused\n", s)
1168                 }
1169         }
1170         lost := a.invalidateRecursively()
1171         if x.debug&1 != 0 && lost { // For odd values of x.debug, do this.
1172                 x.Printf("Lost statement marker in %s on former %s\n", base.Ctxt.Pkgpath+"."+x.f.Name, s)
1173         }
1174 }
1175
1176 // expandCalls converts LE (Late Expansion) calls that act like they receive value args into a lower-level form
1177 // that is more oriented to a platform's ABI.  The SelectN operations that extract results are rewritten into
1178 // more appropriate forms, and any StructMake or ArrayMake inputs are decomposed until non-struct values are
1179 // reached.  On the callee side, OpArg nodes are not decomposed until this phase is run.
1180 // TODO results should not be lowered until this phase.
1181 func expandCalls(f *Func) {
1182         // Calls that need lowering have some number of inputs, including a memory input,
1183         // and produce a tuple of (value1, value2, ..., mem) where valueK may or may not be SSA-able.
1184
1185         // With the current ABI those inputs need to be converted into stores to memory,
1186         // rethreading the call's memory input to the first, and the new call now receiving the last.
1187
1188         // With the current ABI, the outputs need to be converted to loads, which will all use the call's
1189         // memory output as their input.
1190         sp, _ := f.spSb()
1191         x := &expandState{
1192                 f:                  f,
1193                 abi1:               f.ABI1,
1194                 debug:              f.pass.debug,
1195                 canSSAType:         f.fe.CanSSA,
1196                 regSize:            f.Config.RegSize,
1197                 sp:                 sp,
1198                 typs:               &f.Config.Types,
1199                 ptrSize:            f.Config.PtrSize,
1200                 namedSelects:       make(map[*Value][]namedVal),
1201                 sdom:               f.Sdom(),
1202                 commonArgs:         make(map[selKey]*Value),
1203                 memForCall:         make(map[ID]*Value),
1204                 transformedSelects: make(map[ID]bool),
1205         }
1206
1207         // For 32-bit, need to deal with decomposition of 64-bit integers, which depends on endianness.
1208         if f.Config.BigEndian {
1209                 x.lowOffset, x.hiOffset = 4, 0
1210                 x.loRo, x.hiRo = 1, 0
1211         } else {
1212                 x.lowOffset, x.hiOffset = 0, 4
1213                 x.loRo, x.hiRo = 0, 1
1214         }
1215
1216         if x.debug > 1 {
1217                 x.Printf("\nexpandsCalls(%s)\n", f.Name)
1218         }
1219
1220         for i, name := range f.Names {
1221                 t := name.Type
1222                 if x.isAlreadyExpandedAggregateType(t) {
1223                         for j, v := range f.NamedValues[*name] {
1224                                 if v.Op == OpSelectN || v.Op == OpArg && x.isAlreadyExpandedAggregateType(v.Type) {
1225                                         ns := x.namedSelects[v]
1226                                         x.namedSelects[v] = append(ns, namedVal{locIndex: i, valIndex: j})
1227                                 }
1228                         }
1229                 }
1230         }
1231
1232         // TODO if too slow, whole program iteration can be replaced w/ slices of appropriate values, accumulated in first loop here.
1233
1234         // Step 0: rewrite the calls to convert args to calls into stores/register movement.
1235         for _, b := range f.Blocks {
1236                 for _, v := range b.Values {
1237                         firstArg := 0
1238                         switch v.Op {
1239                         case OpStaticLECall, OpTailLECall:
1240                         case OpInterLECall:
1241                                 firstArg = 1
1242                         case OpClosureLECall:
1243                                 firstArg = 2
1244                         default:
1245                                 continue
1246                         }
1247                         x.rewriteArgs(v, firstArg)
1248                 }
1249                 if isBlockMultiValueExit(b) {
1250                         x.indent(3)
1251                         // Very similar to code in rewriteArgs, but results instead of args.
1252                         v := b.Controls[0]
1253                         m0 := v.MemoryArg()
1254                         mem := m0
1255                         aux := f.OwnAux
1256                         allResults := []*Value{}
1257                         if x.debug > 1 {
1258                                 x.Printf("multiValueExit rewriting %s\n", v.LongString())
1259                         }
1260                         var oldArgs []*Value
1261                         for j, a := range v.Args[:len(v.Args)-1] {
1262                                 oldArgs = append(oldArgs, a)
1263                                 i := int64(j)
1264                                 auxType := aux.TypeOfResult(i)
1265                                 auxBase := b.NewValue2A(v.Pos, OpLocalAddr, types.NewPtr(auxType), aux.NameOfResult(i), x.sp, mem)
1266                                 auxOffset := int64(0)
1267                                 auxSize := aux.SizeOfResult(i)
1268                                 aRegs := aux.RegsOfResult(int64(j))
1269                                 if len(aRegs) == 0 && a.Op == OpDereference {
1270                                         // Avoid a self-move, and if one is detected try to remove the already-inserted VarDef for the assignment that won't happen.
1271                                         if dAddr, dMem := a.Args[0], a.Args[1]; dAddr.Op == OpLocalAddr && dAddr.Args[0].Op == OpSP &&
1272                                                 dAddr.Args[1] == dMem && dAddr.Aux == aux.NameOfResult(i) {
1273                                                 if dMem.Op == OpVarDef && dMem.Aux == dAddr.Aux {
1274                                                         dMem.copyOf(dMem.MemoryArg()) // elide the VarDef
1275                                                 }
1276                                                 continue
1277                                         }
1278                                         mem = x.rewriteDereference(v.Block, auxBase, a, mem, auxOffset, auxSize, auxType, a.Pos)
1279                                 } else {
1280                                         if a.Op == OpLoad && a.Args[0].Op == OpLocalAddr {
1281                                                 addr := a.Args[0] // This is a self-move. // TODO(register args) do what here for registers?
1282                                                 if addr.MemoryArg() == a.MemoryArg() && addr.Aux == aux.NameOfResult(i) {
1283                                                         continue
1284                                                 }
1285                                         }
1286                                         var rc registerCursor
1287                                         var result *[]*Value
1288                                         if len(aRegs) > 0 {
1289                                                 result = &allResults
1290                                         }
1291                                         rc.init(aRegs, aux.abiInfo, result, auxBase)
1292                                         mem = x.storeArgOrLoad(v.Pos, b, a, mem, aux.TypeOfResult(i), auxOffset, 0, rc)
1293                                 }
1294                         }
1295                         v.resetArgs()
1296                         v.AddArgs(allResults...)
1297                         v.AddArg(mem)
1298                         v.Type = types.NewResults(append(abi.RegisterTypes(aux.abiInfo.OutParams()), types.TypeMem))
1299                         b.SetControl(v)
1300                         for _, a := range oldArgs {
1301                                 if a.Uses == 0 {
1302                                         if x.debug > 1 {
1303                                                 x.Printf("...marking %v unused\n", a.LongString())
1304                                         }
1305                                         x.invalidateRecursively(a)
1306                                 }
1307                         }
1308                         if x.debug > 1 {
1309                                 x.Printf("...multiValueExit new result %s\n", v.LongString())
1310                         }
1311                         x.indent(-3)
1312                 }
1313         }
1314
1315         // Step 1: any stores of aggregates remaining are believed to be sourced from call results or args.
1316         // Decompose those stores into a series of smaller stores, adding selection ops as necessary.
1317         for _, b := range f.Blocks {
1318                 for _, v := range b.Values {
1319                         if v.Op == OpStore {
1320                                 t := v.Aux.(*types.Type)
1321                                 source := v.Args[1]
1322                                 tSrc := source.Type
1323                                 iAEATt := x.isAlreadyExpandedAggregateType(t)
1324
1325                                 if !iAEATt {
1326                                         // guarding against store immediate struct into interface data field -- store type is *uint8
1327                                         // TODO can this happen recursively?
1328                                         iAEATt = x.isAlreadyExpandedAggregateType(tSrc)
1329                                         if iAEATt {
1330                                                 t = tSrc
1331                                         }
1332                                 }
1333                                 dst, mem := v.Args[0], v.Args[2]
1334                                 mem = x.storeArgOrLoad(v.Pos, b, source, mem, t, 0, 0, registerCursor{storeDest: dst})
1335                                 v.copyOf(mem)
1336                         }
1337                 }
1338         }
1339
1340         val2Preds := make(map[*Value]int32) // Used to accumulate dependency graph of selection operations for topological ordering.
1341
1342         // Step 2: transform or accumulate selection operations for rewrite in topological order.
1343         //
1344         // Aggregate types that have already (in earlier phases) been transformed must be lowered comprehensively to finish
1345         // the transformation (user-defined structs and arrays, slices, strings, interfaces, complex, 64-bit on 32-bit architectures),
1346         //
1347         // Any select-for-addressing applied to call results can be transformed directly.
1348         for _, b := range f.Blocks {
1349                 for _, v := range b.Values {
1350                         // Accumulate chains of selectors for processing in topological order
1351                         switch v.Op {
1352                         case OpStructSelect, OpArraySelect,
1353                                 OpIData, OpITab,
1354                                 OpStringPtr, OpStringLen,
1355                                 OpSlicePtr, OpSliceLen, OpSliceCap, OpSlicePtrUnchecked,
1356                                 OpComplexReal, OpComplexImag,
1357                                 OpInt64Hi, OpInt64Lo:
1358                                 w := v.Args[0]
1359                                 switch w.Op {
1360                                 case OpStructSelect, OpArraySelect, OpSelectN, OpArg:
1361                                         val2Preds[w] += 1
1362                                         if x.debug > 1 {
1363                                                 x.Printf("v2p[%s] = %d\n", w.LongString(), val2Preds[w])
1364                                         }
1365                                 }
1366                                 fallthrough
1367
1368                         case OpSelectN:
1369                                 if _, ok := val2Preds[v]; !ok {
1370                                         val2Preds[v] = 0
1371                                         if x.debug > 1 {
1372                                                 x.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v])
1373                                         }
1374                                 }
1375
1376                         case OpArg:
1377                                 if !x.isAlreadyExpandedAggregateType(v.Type) {
1378                                         continue
1379                                 }
1380                                 if _, ok := val2Preds[v]; !ok {
1381                                         val2Preds[v] = 0
1382                                         if x.debug > 1 {
1383                                                 x.Printf("v2p[%s] = %d\n", v.LongString(), val2Preds[v])
1384                                         }
1385                                 }
1386
1387                         case OpSelectNAddr:
1388                                 // Do these directly, there are no chains of selectors.
1389                                 call := v.Args[0]
1390                                 which := v.AuxInt
1391                                 aux := call.Aux.(*AuxCall)
1392                                 pt := v.Type
1393                                 off := x.offsetFrom(x.f.Entry, x.sp, aux.OffsetOfResult(which), pt)
1394                                 v.copyOf(off)
1395                         }
1396                 }
1397         }
1398
1399         // Step 3: Compute topological order of selectors,
1400         // then process it in reverse to eliminate duplicates,
1401         // then forwards to rewrite selectors.
1402         //
1403         // All chains of selectors end up in same block as the call.
1404
1405         // Compilation must be deterministic, so sort after extracting first zeroes from map.
1406         // Sorting allows dominators-last order within each batch,
1407         // so that the backwards scan for duplicates will most often find copies from dominating blocks (it is best-effort).
1408         var toProcess []*Value
1409         less := func(i, j int) bool {
1410                 vi, vj := toProcess[i], toProcess[j]
1411                 bi, bj := vi.Block, vj.Block
1412                 if bi == bj {
1413                         return vi.ID < vj.ID
1414                 }
1415                 return x.sdom.domorder(bi) > x.sdom.domorder(bj) // reverse the order to put dominators last.
1416         }
1417
1418         // Accumulate order in allOrdered
1419         var allOrdered []*Value
1420         for v, n := range val2Preds {
1421                 if n == 0 {
1422                         allOrdered = append(allOrdered, v)
1423                 }
1424         }
1425         last := 0 // allOrdered[0:last] has been top-sorted and processed
1426         for len(val2Preds) > 0 {
1427                 toProcess = allOrdered[last:]
1428                 last = len(allOrdered)
1429                 sort.SliceStable(toProcess, less)
1430                 for _, v := range toProcess {
1431                         delete(val2Preds, v)
1432                         if v.Op == OpArg {
1433                                 continue // no Args[0], hence done.
1434                         }
1435                         w := v.Args[0]
1436                         n, ok := val2Preds[w]
1437                         if !ok {
1438                                 continue
1439                         }
1440                         if n == 1 {
1441                                 allOrdered = append(allOrdered, w)
1442                                 delete(val2Preds, w)
1443                                 continue
1444                         }
1445                         val2Preds[w] = n - 1
1446                 }
1447         }
1448
1449         x.commonSelectors = make(map[selKey]*Value)
1450         // Rewrite duplicate selectors as copies where possible.
1451         for i := len(allOrdered) - 1; i >= 0; i-- {
1452                 v := allOrdered[i]
1453                 if v.Op == OpArg {
1454                         continue
1455                 }
1456                 w := v.Args[0]
1457                 if w.Op == OpCopy {
1458                         for w.Op == OpCopy {
1459                                 w = w.Args[0]
1460                         }
1461                         v.SetArg(0, w)
1462                 }
1463                 typ := v.Type
1464                 if typ.IsMemory() {
1465                         continue // handled elsewhere, not an indexable result
1466                 }
1467                 size := typ.Size()
1468                 offset := int64(0)
1469                 switch v.Op {
1470                 case OpStructSelect:
1471                         if w.Type.Kind() == types.TSTRUCT {
1472                                 offset = w.Type.FieldOff(int(v.AuxInt))
1473                         } else { // Immediate interface data artifact, offset is zero.
1474                                 f.Fatalf("Expand calls interface data problem, func %s, v=%s, w=%s\n", f.Name, v.LongString(), w.LongString())
1475                         }
1476                 case OpArraySelect:
1477                         offset = size * v.AuxInt
1478                 case OpSelectN:
1479                         offset = v.AuxInt // offset is just a key, really.
1480                 case OpInt64Hi:
1481                         offset = x.hiOffset
1482                 case OpInt64Lo:
1483                         offset = x.lowOffset
1484                 case OpStringLen, OpSliceLen, OpIData:
1485                         offset = x.ptrSize
1486                 case OpSliceCap:
1487                         offset = 2 * x.ptrSize
1488                 case OpComplexImag:
1489                         offset = size
1490                 }
1491                 sk := selKey{from: w, size: size, offsetOrIndex: offset, typ: typ}
1492                 dupe := x.commonSelectors[sk]
1493                 if dupe == nil {
1494                         x.commonSelectors[sk] = v
1495                 } else if x.sdom.IsAncestorEq(dupe.Block, v.Block) {
1496                         if x.debug > 1 {
1497                                 x.Printf("Duplicate, make %s copy of %s\n", v, dupe)
1498                         }
1499                         v.copyOf(dupe)
1500                 } else {
1501                         // Because values are processed in dominator order, the old common[s] will never dominate after a miss is seen.
1502                         // Installing the new value might match some future values.
1503                         x.commonSelectors[sk] = v
1504                 }
1505         }
1506
1507         // Indices of entries in f.Names that need to be deleted.
1508         var toDelete []namedVal
1509
1510         // Rewrite selectors.
1511         for i, v := range allOrdered {
1512                 if x.debug > 1 {
1513                         b := v.Block
1514                         x.Printf("allOrdered[%d] = b%d, %s, uses=%d\n", i, b.ID, v.LongString(), v.Uses)
1515                 }
1516                 if v.Uses == 0 {
1517                         x.invalidateRecursively(v)
1518                         continue
1519                 }
1520                 if v.Op == OpCopy {
1521                         continue
1522                 }
1523                 locs := x.rewriteSelect(v, v, 0, 0)
1524                 // Install new names.
1525                 if v.Type.IsMemory() {
1526                         continue
1527                 }
1528                 // Leaf types may have debug locations
1529                 if !x.isAlreadyExpandedAggregateType(v.Type) {
1530                         for _, l := range locs {
1531                                 if _, ok := f.NamedValues[*l]; !ok {
1532                                         f.Names = append(f.Names, l)
1533                                 }
1534                                 f.NamedValues[*l] = append(f.NamedValues[*l], v)
1535                         }
1536                         continue
1537                 }
1538                 if ns, ok := x.namedSelects[v]; ok {
1539                         // Not-leaf types that had debug locations need to lose them.
1540
1541                         toDelete = append(toDelete, ns...)
1542                 }
1543         }
1544
1545         deleteNamedVals(f, toDelete)
1546
1547         // Step 4: rewrite the calls themselves, correcting the type.
1548         for _, b := range f.Blocks {
1549                 for _, v := range b.Values {
1550                         switch v.Op {
1551                         case OpArg:
1552                                 x.rewriteArgToMemOrRegs(v)
1553                         case OpStaticLECall:
1554                                 v.Op = OpStaticCall
1555                                 rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams())
1556                                 v.Type = types.NewResults(append(rts, types.TypeMem))
1557                         case OpTailLECall:
1558                                 v.Op = OpTailCall
1559                                 rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams())
1560                                 v.Type = types.NewResults(append(rts, types.TypeMem))
1561                         case OpClosureLECall:
1562                                 v.Op = OpClosureCall
1563                                 rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams())
1564                                 v.Type = types.NewResults(append(rts, types.TypeMem))
1565                         case OpInterLECall:
1566                                 v.Op = OpInterCall
1567                                 rts := abi.RegisterTypes(v.Aux.(*AuxCall).abiInfo.OutParams())
1568                                 v.Type = types.NewResults(append(rts, types.TypeMem))
1569                         }
1570                 }
1571         }
1572
1573         // Step 5: dedup OpArgXXXReg values. Mostly it is already dedup'd by commonArgs,
1574         // but there are cases that we have same OpArgXXXReg values with different types.
1575         // E.g. string is sometimes decomposed as { *int8, int }, sometimes as { unsafe.Pointer, uintptr }.
1576         // (Can we avoid that?)
1577         var IArg, FArg [32]*Value
1578         for _, v := range f.Entry.Values {
1579                 switch v.Op {
1580                 case OpArgIntReg:
1581                         i := v.AuxInt
1582                         if w := IArg[i]; w != nil {
1583                                 if w.Type.Size() != v.Type.Size() {
1584                                         f.Fatalf("incompatible OpArgIntReg [%d]: %s and %s", i, v.LongString(), w.LongString())
1585                                 }
1586                                 if w.Type.IsUnsafePtr() && !v.Type.IsUnsafePtr() {
1587                                         // Update unsafe.Pointer type if we know the actual pointer type.
1588                                         w.Type = v.Type
1589                                 }
1590                                 // TODO: don't dedup pointer and scalar? Rewrite to OpConvert? Can it happen?
1591                                 v.copyOf(w)
1592                         } else {
1593                                 IArg[i] = v
1594                         }
1595                 case OpArgFloatReg:
1596                         i := v.AuxInt
1597                         if w := FArg[i]; w != nil {
1598                                 if w.Type.Size() != v.Type.Size() {
1599                                         f.Fatalf("incompatible OpArgFloatReg [%d]: %v and %v", i, v, w)
1600                                 }
1601                                 v.copyOf(w)
1602                         } else {
1603                                 FArg[i] = v
1604                         }
1605                 }
1606         }
1607
1608         // Step 6: elide any copies introduced.
1609         // Update named values.
1610         for _, name := range f.Names {
1611                 values := f.NamedValues[*name]
1612                 for i, v := range values {
1613                         if v.Op == OpCopy {
1614                                 a := v.Args[0]
1615                                 for a.Op == OpCopy {
1616                                         a = a.Args[0]
1617                                 }
1618                                 values[i] = a
1619                         }
1620                 }
1621         }
1622         for _, b := range f.Blocks {
1623                 for _, v := range b.Values {
1624                         for i, a := range v.Args {
1625                                 if a.Op != OpCopy {
1626                                         continue
1627                                 }
1628                                 aa := copySource(a)
1629                                 v.SetArg(i, aa)
1630                                 for a.Uses == 0 {
1631                                         b := a.Args[0]
1632                                         x.invalidateRecursively(a)
1633                                         a = b
1634                                 }
1635                         }
1636                 }
1637         }
1638
1639         // Rewriting can attach lines to values that are unlikely to survive code generation, so move them to a use.
1640         for _, b := range f.Blocks {
1641                 for _, v := range b.Values {
1642                         for _, a := range v.Args {
1643                                 if a.Pos.IsStmt() != src.PosIsStmt {
1644                                         continue
1645                                 }
1646                                 if a.Type.IsMemory() {
1647                                         continue
1648                                 }
1649                                 if a.Pos.Line() != v.Pos.Line() {
1650                                         continue
1651                                 }
1652                                 if !a.Pos.SameFile(v.Pos) {
1653                                         continue
1654                                 }
1655                                 switch a.Op {
1656                                 case OpArgIntReg, OpArgFloatReg, OpSelectN:
1657                                         v.Pos = v.Pos.WithIsStmt()
1658                                         a.Pos = a.Pos.WithDefaultStmt()
1659                                 }
1660                         }
1661                 }
1662         }
1663 }
1664
1665 // rewriteArgToMemOrRegs converts OpArg v in-place into the register version of v,
1666 // if that is appropriate.
1667 func (x *expandState) rewriteArgToMemOrRegs(v *Value) *Value {
1668         if x.debug > 1 {
1669                 x.indent(3)
1670                 defer x.indent(-3)
1671                 x.Printf("rewriteArgToMemOrRegs(%s)\n", v.LongString())
1672         }
1673         pa := x.prAssignForArg(v)
1674         switch len(pa.Registers) {
1675         case 0:
1676                 frameOff := v.Aux.(*ir.Name).FrameOffset()
1677                 if pa.Offset() != int32(frameOff+x.f.ABISelf.LocalsOffset()) {
1678                         panic(fmt.Errorf("Parameter assignment %d and OpArg.Aux frameOffset %d disagree, op=%s",
1679                                 pa.Offset(), frameOff, v.LongString()))
1680                 }
1681         case 1:
1682                 t := v.Type
1683                 key := selKey{v, 0, t.Size(), t}
1684                 w := x.commonArgs[key]
1685                 if w != nil && w.Uses != 0 { // do not reuse dead value
1686                         v.copyOf(w)
1687                         break
1688                 }
1689                 r := pa.Registers[0]
1690                 var i int64
1691                 v.Op, i = ArgOpAndRegisterFor(r, x.f.ABISelf)
1692                 v.Aux = &AuxNameOffset{v.Aux.(*ir.Name), 0}
1693                 v.AuxInt = i
1694                 x.commonArgs[key] = v
1695
1696         default:
1697                 panic(badVal("Saw unexpanded OpArg", v))
1698         }
1699         if x.debug > 1 {
1700                 x.Printf("-->%s\n", v.LongString())
1701         }
1702         return v
1703 }
1704
1705 // newArgToMemOrRegs either rewrites toReplace into an OpArg referencing memory or into an OpArgXXXReg to a register,
1706 // or rewrites it into a copy of the appropriate OpArgXXX.  The actual OpArgXXX is determined by combining baseArg (an OpArg)
1707 // with offset, regOffset, and t to determine which portion of it to reference (either all or a part, in memory or in registers).
1708 func (x *expandState) newArgToMemOrRegs(baseArg, toReplace *Value, offset int64, regOffset Abi1RO, t *types.Type, pos src.XPos) *Value {
1709         if x.debug > 1 {
1710                 x.indent(3)
1711                 defer x.indent(-3)
1712                 x.Printf("newArgToMemOrRegs(base=%s; toReplace=%s; t=%s; memOff=%d; regOff=%d)\n", baseArg.String(), toReplace.LongString(), t.String(), offset, regOffset)
1713         }
1714         key := selKey{baseArg, offset, t.Size(), t}
1715         w := x.commonArgs[key]
1716         if w != nil && w.Uses != 0 { // do not reuse dead value
1717                 if toReplace != nil {
1718                         toReplace.copyOf(w)
1719                         if x.debug > 1 {
1720                                 x.Printf("...replace %s\n", toReplace.LongString())
1721                         }
1722                 }
1723                 if x.debug > 1 {
1724                         x.Printf("-->%s\n", w.LongString())
1725                 }
1726                 return w
1727         }
1728
1729         pa := x.prAssignForArg(baseArg)
1730         if len(pa.Registers) == 0 { // Arg is on stack
1731                 frameOff := baseArg.Aux.(*ir.Name).FrameOffset()
1732                 if pa.Offset() != int32(frameOff+x.f.ABISelf.LocalsOffset()) {
1733                         panic(fmt.Errorf("Parameter assignment %d and OpArg.Aux frameOffset %d disagree, op=%s",
1734                                 pa.Offset(), frameOff, baseArg.LongString()))
1735                 }
1736                 aux := baseArg.Aux
1737                 auxInt := baseArg.AuxInt + offset
1738                 if toReplace != nil && toReplace.Block == baseArg.Block {
1739                         toReplace.reset(OpArg)
1740                         toReplace.Aux = aux
1741                         toReplace.AuxInt = auxInt
1742                         toReplace.Type = t
1743                         w = toReplace
1744                 } else {
1745                         w = baseArg.Block.NewValue0IA(baseArg.Pos, OpArg, t, auxInt, aux)
1746                 }
1747                 x.commonArgs[key] = w
1748                 if toReplace != nil {
1749                         toReplace.copyOf(w)
1750                 }
1751                 if x.debug > 1 {
1752                         x.Printf("-->%s\n", w.LongString())
1753                 }
1754                 return w
1755         }
1756         // Arg is in registers
1757         r := pa.Registers[regOffset]
1758         op, auxInt := ArgOpAndRegisterFor(r, x.f.ABISelf)
1759         if op == OpArgIntReg && t.IsFloat() || op == OpArgFloatReg && t.IsInteger() {
1760                 fmt.Printf("pa=%v\nx.f.OwnAux.abiInfo=%s\n",
1761                         pa.ToString(x.f.ABISelf, true),
1762                         x.f.OwnAux.abiInfo.String())
1763                 panic(fmt.Errorf("Op/Type mismatch, op=%s, type=%s", op.String(), t.String()))
1764         }
1765         if baseArg.AuxInt != 0 {
1766                 base.Fatalf("BaseArg %s bound to registers has non-zero AuxInt", baseArg.LongString())
1767         }
1768         aux := &AuxNameOffset{baseArg.Aux.(*ir.Name), offset}
1769         if toReplace != nil && toReplace.Block == baseArg.Block {
1770                 toReplace.reset(op)
1771                 toReplace.Aux = aux
1772                 toReplace.AuxInt = auxInt
1773                 toReplace.Type = t
1774                 w = toReplace
1775         } else {
1776                 w = baseArg.Block.NewValue0IA(baseArg.Pos, op, t, auxInt, aux)
1777         }
1778         x.commonArgs[key] = w
1779         if toReplace != nil {
1780                 toReplace.copyOf(w)
1781         }
1782         if x.debug > 1 {
1783                 x.Printf("-->%s\n", w.LongString())
1784         }
1785         return w
1786
1787 }
1788
1789 // ArgOpAndRegisterFor converts an abi register index into an ssa Op and corresponding
1790 // arg register index.
1791 func ArgOpAndRegisterFor(r abi.RegIndex, abiConfig *abi.ABIConfig) (Op, int64) {
1792         i := abiConfig.FloatIndexFor(r)
1793         if i >= 0 { // float PR
1794                 return OpArgFloatReg, i
1795         }
1796         return OpArgIntReg, int64(r)
1797 }