]> Cypherpunks.ru repositories - gostls13.git/blob - src/cmd/compile/internal/gc/popt.go
001a715f7b7aa13d8ed7bb5b251bb330a5c1ab93
[gostls13.git] / src / cmd / compile / internal / gc / popt.go
1 // Derived from Inferno utils/6c/gc.h
2 // http://code.google.com/p/inferno-os/source/browse/utils/6c/gc.h
3 //
4 //      Copyright © 1994-1999 Lucent Technologies Inc.  All rights reserved.
5 //      Portions Copyright © 1995-1997 C H Forsyth (forsyth@terzarima.net)
6 //      Portions Copyright © 1997-1999 Vita Nuova Limited
7 //      Portions Copyright © 2000-2007 Vita Nuova Holdings Limited (www.vitanuova.com)
8 //      Portions Copyright © 2004,2006 Bruce Ellis
9 //      Portions Copyright © 2005-2007 C H Forsyth (forsyth@terzarima.net)
10 //      Revisions Copyright © 2000-2007 Lucent Technologies Inc. and others
11 //      Portions Copyright © 2009 The Go Authors.  All rights reserved.
12 //
13 // Permission is hereby granted, free of charge, to any person obtaining a copy
14 // of this software and associated documentation files (the "Software"), to deal
15 // in the Software without restriction, including without limitation the rights
16 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
17 // copies of the Software, and to permit persons to whom the Software is
18 // furnished to do so, subject to the following conditions:
19 //
20 // The above copyright notice and this permission notice shall be included in
21 // all copies or substantial portions of the Software.
22 //
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
24 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
25 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
26 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
27 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
28 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
29 // THE SOFTWARE.
30
31 // "Portable" optimizations.
32
33 package gc
34
35 import (
36         "cmd/internal/obj"
37         "fmt"
38         "sort"
39         "strings"
40 )
41
42 type OptStats struct {
43         Ncvtreg int32
44         Nspill  int32
45         Nreload int32
46         Ndelmov int32
47         Nvar    int32
48         Naddr   int32
49 }
50
51 var Ostats OptStats
52
53 var noreturn_symlist [10]*Sym
54
55 // p is a call instruction. Does the call fail to return?
56 func Noreturn(p *obj.Prog) bool {
57         if noreturn_symlist[0] == nil {
58                 noreturn_symlist[0] = Pkglookup("panicindex", Runtimepkg)
59                 noreturn_symlist[1] = Pkglookup("panicslice", Runtimepkg)
60                 noreturn_symlist[2] = Pkglookup("throwinit", Runtimepkg)
61                 noreturn_symlist[3] = Pkglookup("gopanic", Runtimepkg)
62                 noreturn_symlist[4] = Pkglookup("panicwrap", Runtimepkg)
63                 noreturn_symlist[5] = Pkglookup("throwreturn", Runtimepkg)
64                 noreturn_symlist[6] = Pkglookup("selectgo", Runtimepkg)
65                 noreturn_symlist[7] = Pkglookup("block", Runtimepkg)
66         }
67
68         if p.To.Node == nil {
69                 return false
70         }
71         s := ((p.To.Node).(*Node)).Sym
72         if s == nil {
73                 return false
74         }
75         for i := 0; noreturn_symlist[i] != nil; i++ {
76                 if s == noreturn_symlist[i] {
77                         return true
78                 }
79         }
80         return false
81 }
82
83 // JMP chasing and removal.
84 //
85 // The code generator depends on being able to write out jump
86 // instructions that it can jump to now but fill in later.
87 // the linker will resolve them nicely, but they make the code
88 // longer and more difficult to follow during debugging.
89 // Remove them.
90
91 // what instruction does a JMP to p eventually land on?
92 func chasejmp(p *obj.Prog, jmploop *int) *obj.Prog {
93         n := 0
94         for p != nil && p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH {
95                 n++
96                 if n > 10 {
97                         *jmploop = 1
98                         break
99                 }
100
101                 p = p.To.Val.(*obj.Prog)
102         }
103
104         return p
105 }
106
107 // reuse reg pointer for mark/sweep state.
108 // leave reg==nil at end because alive==nil.
109 var alive interface{} = nil
110 var dead interface{} = 1
111
112 // mark all code reachable from firstp as alive
113 func mark(firstp *obj.Prog) {
114         for p := firstp; p != nil; p = p.Link {
115                 if p.Opt != dead {
116                         break
117                 }
118                 p.Opt = alive
119                 if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil {
120                         mark(p.To.Val.(*obj.Prog))
121                 }
122                 if p.As == obj.AJMP || p.As == obj.ARET || p.As == obj.AUNDEF {
123                         break
124                 }
125         }
126 }
127
128 func fixjmp(firstp *obj.Prog) {
129         if Debug['R'] != 0 && Debug['v'] != 0 {
130                 fmt.Printf("\nfixjmp\n")
131         }
132
133         // pass 1: resolve jump to jump, mark all code as dead.
134         jmploop := 0
135
136         for p := firstp; p != nil; p = p.Link {
137                 if Debug['R'] != 0 && Debug['v'] != 0 {
138                         fmt.Printf("%v\n", p)
139                 }
140                 if p.As != obj.ACALL && p.To.Type == obj.TYPE_BRANCH && p.To.Val.(*obj.Prog) != nil && p.To.Val.(*obj.Prog).As == obj.AJMP {
141                         if Debug['N'] == 0 {
142                                 p.To.Val = chasejmp(p.To.Val.(*obj.Prog), &jmploop)
143                                 if Debug['R'] != 0 && Debug['v'] != 0 {
144                                         fmt.Printf("->%v\n", p)
145                                 }
146                         }
147                 }
148
149                 p.Opt = dead
150         }
151         if Debug['R'] != 0 && Debug['v'] != 0 {
152                 fmt.Printf("\n")
153         }
154
155         // pass 2: mark all reachable code alive
156         mark(firstp)
157
158         // pass 3: delete dead code (mostly JMPs).
159         var last *obj.Prog
160
161         for p := firstp; p != nil; p = p.Link {
162                 if p.Opt == dead {
163                         if p.Link == nil && p.As == obj.ARET && last != nil && last.As != obj.ARET {
164                                 // This is the final ARET, and the code so far doesn't have one.
165                                 // Let it stay. The register allocator assumes that all live code in
166                                 // the function can be traversed by starting at all the RET instructions
167                                 // and following predecessor links. If we remove the final RET,
168                                 // this assumption will not hold in the case of an infinite loop
169                                 // at the end of a function.
170                                 // Keep the RET but mark it dead for the liveness analysis.
171                                 p.Mode = 1
172                         } else {
173                                 if Debug['R'] != 0 && Debug['v'] != 0 {
174                                         fmt.Printf("del %v\n", p)
175                                 }
176                                 continue
177                         }
178                 }
179
180                 if last != nil {
181                         last.Link = p
182                 }
183                 last = p
184         }
185
186         last.Link = nil
187
188         // pass 4: elide JMP to next instruction.
189         // only safe if there are no jumps to JMPs anymore.
190         if jmploop == 0 && Debug['N'] == 0 {
191                 var last *obj.Prog
192                 for p := firstp; p != nil; p = p.Link {
193                         if p.As == obj.AJMP && p.To.Type == obj.TYPE_BRANCH && p.To.Val == p.Link {
194                                 if Debug['R'] != 0 && Debug['v'] != 0 {
195                                         fmt.Printf("del %v\n", p)
196                                 }
197                                 continue
198                         }
199
200                         if last != nil {
201                                 last.Link = p
202                         }
203                         last = p
204                 }
205
206                 last.Link = nil
207         }
208
209         if Debug['R'] != 0 && Debug['v'] != 0 {
210                 fmt.Printf("\n")
211                 for p := firstp; p != nil; p = p.Link {
212                         fmt.Printf("%v\n", p)
213                 }
214                 fmt.Printf("\n")
215         }
216 }
217
218 // Control flow analysis. The Flow structures hold predecessor and successor
219 // information as well as basic loop analysis.
220 //
221 //      graph = Flowstart(firstp, nil)
222 //      ... use flow graph ...
223 //      Flowend(graph) // free graph
224 //
225 // Typical uses of the flow graph are to iterate over all the flow-relevant instructions:
226 //
227 //      for f := graph.Start; f != nil; f = f.Link {}
228 //
229 // or, given an instruction f, to iterate over all the predecessors, which is
230 // f.P1 and this list:
231 //
232 //      for f2 := f.P2; f2 != nil; f2 = f2.P2link {}
233 //
234 // The second argument (newData) to Flowstart specifies a func to create object
235 // for every f.Data field, for use by the client.
236 // If newData is nil, f.Data will be nil.
237
238 type Graph struct {
239         Start *Flow
240         Num   int
241
242         // After calling flowrpo, rpo lists the flow nodes in reverse postorder,
243         // and each non-dead Flow node f has g->rpo[f->rpo] == f.
244         Rpo []*Flow
245 }
246
247 type Flow struct {
248         Prog   *obj.Prog // actual instruction
249         P1     *Flow     // predecessors of this instruction: p1,
250         P2     *Flow     // and then p2 linked though p2link.
251         P2link *Flow
252         S1     *Flow // successors of this instruction (at most two: s1 and s2).
253         S2     *Flow
254         Link   *Flow // next instruction in function code
255
256         Active int32 // usable by client
257
258         Id     int32  // sequence number in flow graph
259         Rpo    int32  // reverse post ordering
260         Loop   uint16 // x5 for every loop
261         Refset bool   // diagnostic generated
262
263         Data interface{} // for use by client
264 }
265
266 var flowmark int
267
268 // MaxFlowProg is the maximum size program (counted in instructions)
269 // for which the flow code will build a graph. Functions larger than this limit
270 // will not have flow graphs and consequently will not be optimized.
271 const MaxFlowProg = 50000
272
273 var ffcache []Flow // reusable []Flow, to reduce allocation
274
275 func growffcache(n int) {
276         if n > cap(ffcache) {
277                 n = (n * 5) / 4
278                 if n > MaxFlowProg {
279                         n = MaxFlowProg
280                 }
281                 ffcache = make([]Flow, n)
282         }
283         ffcache = ffcache[:n]
284 }
285
286 func Flowstart(firstp *obj.Prog, newData func() interface{}) *Graph {
287         // Count and mark instructions to annotate.
288         nf := 0
289
290         for p := firstp; p != nil; p = p.Link {
291                 p.Opt = nil // should be already, but just in case
292                 Thearch.Proginfo(p)
293                 if p.Info.Flags&Skip != 0 {
294                         continue
295                 }
296                 p.Opt = &flowmark
297                 nf++
298         }
299
300         if nf == 0 {
301                 return nil
302         }
303
304         if nf >= MaxFlowProg {
305                 if Debug['v'] != 0 {
306                         Warn("%v is too big (%d instructions)", Curfn.Func.Nname.Sym, nf)
307                 }
308                 return nil
309         }
310
311         // Allocate annotations and assign to instructions.
312         graph := new(Graph)
313
314         growffcache(nf)
315         ff := ffcache
316         start := &ff[0]
317         id := 0
318         var last *Flow
319         for p := firstp; p != nil; p = p.Link {
320                 if p.Opt == nil {
321                         continue
322                 }
323                 f := &ff[0]
324                 ff = ff[1:]
325                 p.Opt = f
326                 f.Prog = p
327                 if last != nil {
328                         last.Link = f
329                 }
330                 last = f
331                 if newData != nil {
332                         f.Data = newData()
333                 }
334                 f.Id = int32(id)
335                 id++
336         }
337
338         // Fill in pred/succ information.
339         var f1 *Flow
340         var p *obj.Prog
341         for f := start; f != nil; f = f.Link {
342                 p = f.Prog
343                 if p.Info.Flags&Break == 0 {
344                         f1 = f.Link
345                         f.S1 = f1
346                         f1.P1 = f
347                 }
348
349                 if p.To.Type == obj.TYPE_BRANCH {
350                         if p.To.Val == nil {
351                                 Fatalf("pnil %v", p)
352                         }
353                         f1 = p.To.Val.(*obj.Prog).Opt.(*Flow)
354                         if f1 == nil {
355                                 Fatalf("fnil %v / %v", p, p.To.Val.(*obj.Prog))
356                         }
357                         if f1 == f {
358                                 //fatal("self loop %v", p);
359                                 continue
360                         }
361
362                         f.S2 = f1
363                         f.P2link = f1.P2
364                         f1.P2 = f
365                 }
366         }
367
368         graph.Start = start
369         graph.Num = nf
370         return graph
371 }
372
373 func Flowend(graph *Graph) {
374         for f := graph.Start; f != nil; f = f.Link {
375                 f.Prog.Info.Flags = 0 // drop cached proginfo
376                 f.Prog.Opt = nil
377         }
378         clear := ffcache[:graph.Num]
379         for i := range clear {
380                 clear[i] = Flow{}
381         }
382 }
383
384 // find looping structure
385 //
386 // 1) find reverse postordering
387 // 2) find approximate dominators,
388 //      the actual dominators if the flow graph is reducible
389 //      otherwise, dominators plus some other non-dominators.
390 //      See Matthew S. Hecht and Jeffrey D. Ullman,
391 //      "Analysis of a Simple Algorithm for Global Data Flow Problems",
392 //      Conf.  Record of ACM Symp. on Principles of Prog. Langs, Boston, Massachusetts,
393 //      Oct. 1-3, 1973, pp.  207-217.
394 // 3) find all nodes with a predecessor dominated by the current node.
395 //      such a node is a loop head.
396 //      recursively, all preds with a greater rpo number are in the loop
397 func postorder(r *Flow, rpo2r []*Flow, n int32) int32 {
398         r.Rpo = 1
399         r1 := r.S1
400         if r1 != nil && r1.Rpo == 0 {
401                 n = postorder(r1, rpo2r, n)
402         }
403         r1 = r.S2
404         if r1 != nil && r1.Rpo == 0 {
405                 n = postorder(r1, rpo2r, n)
406         }
407         rpo2r[n] = r
408         n++
409         return n
410 }
411
412 func rpolca(idom []int32, rpo1 int32, rpo2 int32) int32 {
413         if rpo1 == -1 {
414                 return rpo2
415         }
416         var t int32
417         for rpo1 != rpo2 {
418                 if rpo1 > rpo2 {
419                         t = rpo2
420                         rpo2 = rpo1
421                         rpo1 = t
422                 }
423
424                 for rpo1 < rpo2 {
425                         t = idom[rpo2]
426                         if t >= rpo2 {
427                                 Fatalf("bad idom")
428                         }
429                         rpo2 = t
430                 }
431         }
432
433         return rpo1
434 }
435
436 func doms(idom []int32, r int32, s int32) bool {
437         for s > r {
438                 s = idom[s]
439         }
440         return s == r
441 }
442
443 func loophead(idom []int32, r *Flow) bool {
444         src := r.Rpo
445         if r.P1 != nil && doms(idom, src, r.P1.Rpo) {
446                 return true
447         }
448         for r = r.P2; r != nil; r = r.P2link {
449                 if doms(idom, src, r.Rpo) {
450                         return true
451                 }
452         }
453         return false
454 }
455
456 func loopmark(rpo2r **Flow, head int32, r *Flow) {
457         if r.Rpo < head || r.Active == head {
458                 return
459         }
460         r.Active = head
461         r.Loop += LOOP
462         if r.P1 != nil {
463                 loopmark(rpo2r, head, r.P1)
464         }
465         for r = r.P2; r != nil; r = r.P2link {
466                 loopmark(rpo2r, head, r)
467         }
468 }
469
470 func flowrpo(g *Graph) {
471         g.Rpo = make([]*Flow, g.Num)
472         idom := make([]int32, g.Num)
473
474         for r1 := g.Start; r1 != nil; r1 = r1.Link {
475                 r1.Active = 0
476         }
477
478         rpo2r := g.Rpo
479         d := postorder(g.Start, rpo2r, 0)
480         nr := int32(g.Num)
481         if d > nr {
482                 Fatalf("too many reg nodes %d %d", d, nr)
483         }
484         nr = d
485         var r1 *Flow
486         for i := int32(0); i < nr/2; i++ {
487                 r1 = rpo2r[i]
488                 rpo2r[i] = rpo2r[nr-1-i]
489                 rpo2r[nr-1-i] = r1
490         }
491
492         for i := int32(0); i < nr; i++ {
493                 rpo2r[i].Rpo = i
494         }
495
496         idom[0] = 0
497         var me int32
498         for i := int32(0); i < nr; i++ {
499                 r1 = rpo2r[i]
500                 me = r1.Rpo
501                 d = -1
502
503                 // rpo2r[r.Rpo] == r protects against considering dead code,
504                 // which has r.Rpo == 0.
505                 if r1.P1 != nil && rpo2r[r1.P1.Rpo] == r1.P1 && r1.P1.Rpo < me {
506                         d = r1.P1.Rpo
507                 }
508                 for r1 = r1.P2; r1 != nil; r1 = r1.P2link {
509                         if rpo2r[r1.Rpo] == r1 && r1.Rpo < me {
510                                 d = rpolca(idom, d, r1.Rpo)
511                         }
512                 }
513                 idom[i] = d
514         }
515
516         for i := int32(0); i < nr; i++ {
517                 r1 = rpo2r[i]
518                 r1.Loop++
519                 if r1.P2 != nil && loophead(idom, r1) {
520                         loopmark(&rpo2r[0], i, r1)
521                 }
522         }
523
524         for r1 := g.Start; r1 != nil; r1 = r1.Link {
525                 r1.Active = 0
526         }
527 }
528
529 func Uniqp(r *Flow) *Flow {
530         r1 := r.P1
531         if r1 == nil {
532                 r1 = r.P2
533                 if r1 == nil || r1.P2link != nil {
534                         return nil
535                 }
536         } else if r.P2 != nil {
537                 return nil
538         }
539         return r1
540 }
541
542 func Uniqs(r *Flow) *Flow {
543         r1 := r.S1
544         if r1 == nil {
545                 r1 = r.S2
546                 if r1 == nil {
547                         return nil
548                 }
549         } else if r.S2 != nil {
550                 return nil
551         }
552         return r1
553 }
554
555 // The compilers assume they can generate temporary variables
556 // as needed to preserve the right semantics or simplify code
557 // generation and the back end will still generate good code.
558 // This results in a large number of ephemeral temporary variables.
559 // Merge temps with non-overlapping lifetimes and equal types using the
560 // greedy algorithm in Poletto and Sarkar, "Linear Scan Register Allocation",
561 // ACM TOPLAS 1999.
562
563 type TempVar struct {
564         node    *Node
565         def     *Flow    // definition of temp var
566         use     *Flow    // use list, chained through Flow.data
567         merge   *TempVar // merge var with this one
568         start   int64    // smallest Prog.pc in live range
569         end     int64    // largest Prog.pc in live range
570         addr    bool     // address taken - no accurate end
571         removed bool     // removed from program
572 }
573
574 // startcmp sorts TempVars by start, then id, then symbol name.
575 type startcmp []*TempVar
576
577 func (x startcmp) Len() int      { return len(x) }
578 func (x startcmp) Swap(i, j int) { x[i], x[j] = x[j], x[i] }
579 func (x startcmp) Less(i, j int) bool {
580         a := x[i]
581         b := x[j]
582
583         if a.start < b.start {
584                 return true
585         }
586         if a.start > b.start {
587                 return false
588         }
589
590         // Order what's left by id or symbol name,
591         // just so that sort is forced into a specific ordering,
592         // so that the result of the sort does not depend on
593         // the sort implementation.
594         if a.def != b.def {
595                 return int(a.def.Id-b.def.Id) < 0
596         }
597         if a.node != b.node {
598                 return a.node.Sym.Name < b.node.Sym.Name
599         }
600         return false
601 }
602
603 // Is n available for merging?
604 func canmerge(n *Node) bool {
605         return n.Class == PAUTO && strings.HasPrefix(n.Sym.Name, "autotmp")
606 }
607
608 func mergetemp(firstp *obj.Prog) {
609         const (
610                 debugmerge = 0
611         )
612
613         g := Flowstart(firstp, nil)
614         if g == nil {
615                 return
616         }
617
618         // Build list of all mergeable variables.
619         var vars []*TempVar
620         for _, n := range Curfn.Func.Dcl {
621                 if canmerge(n) {
622                         v := &TempVar{}
623                         vars = append(vars, v)
624                         n.SetOpt(v)
625                         v.node = n
626                 }
627         }
628
629         // Build list of uses.
630         // We assume that the earliest reference to a temporary is its definition.
631         // This is not true of variables in general but our temporaries are all
632         // single-use (that's why we have so many!).
633         for f := g.Start; f != nil; f = f.Link {
634                 p := f.Prog
635                 if p.From.Node != nil && ((p.From.Node).(*Node)).Opt() != nil && p.To.Node != nil && ((p.To.Node).(*Node)).Opt() != nil {
636                         Fatalf("double node %v", p)
637                 }
638                 var v *TempVar
639                 n, _ := p.From.Node.(*Node)
640                 if n != nil {
641                         v, _ = n.Opt().(*TempVar)
642                 }
643                 if v == nil {
644                         n, _ = p.To.Node.(*Node)
645                         if n != nil {
646                                 v, _ = n.Opt().(*TempVar)
647                         }
648                 }
649                 if v != nil {
650                         if v.def == nil {
651                                 v.def = f
652                         }
653                         f.Data = v.use
654                         v.use = f
655                         if n == p.From.Node && (p.Info.Flags&LeftAddr != 0) {
656                                 v.addr = true
657                         }
658                 }
659         }
660
661         if debugmerge > 1 && Debug['v'] != 0 {
662                 Dumpit("before", g.Start, 0)
663         }
664
665         nkill := 0
666
667         // Special case.
668         for _, v := range vars {
669                 if v.addr {
670                         continue
671                 }
672
673                 // Used in only one instruction, which had better be a write.
674                 f := v.use
675                 if f != nil && f.Data.(*Flow) == nil {
676                         p := f.Prog
677                         if p.To.Node == v.node && (p.Info.Flags&RightWrite != 0) && p.Info.Flags&RightRead == 0 {
678                                 p.As = obj.ANOP
679                                 p.To = obj.Addr{}
680                                 v.removed = true
681                                 if debugmerge > 0 && Debug['v'] != 0 {
682                                         fmt.Printf("drop write-only %v\n", v.node.Sym)
683                                 }
684                         } else {
685                                 Fatalf("temp used and not set: %v", p)
686                         }
687                         nkill++
688                         continue
689                 }
690
691                 // Written in one instruction, read in the next, otherwise unused,
692                 // no jumps to the next instruction. Happens mainly in 386 compiler.
693                 f = v.use
694                 if f != nil && f.Link == f.Data.(*Flow) && (f.Data.(*Flow)).Data.(*Flow) == nil && Uniqp(f.Link) == f {
695                         p := f.Prog
696                         p1 := f.Link.Prog
697                         const (
698                                 SizeAny = SizeB | SizeW | SizeL | SizeQ | SizeF | SizeD
699                         )
700                         if p.From.Node == v.node && p1.To.Node == v.node && (p.Info.Flags&Move != 0) && (p.Info.Flags|p1.Info.Flags)&(LeftAddr|RightAddr) == 0 && p.Info.Flags&SizeAny == p1.Info.Flags&SizeAny {
701                                 p1.From = p.From
702                                 Thearch.Excise(f)
703                                 v.removed = true
704                                 if debugmerge > 0 && Debug['v'] != 0 {
705                                         fmt.Printf("drop immediate-use %v\n", v.node.Sym)
706                                 }
707                         }
708
709                         nkill++
710                         continue
711                 }
712         }
713
714         // Traverse live range of each variable to set start, end.
715         // Each flood uses a new value of gen so that we don't have
716         // to clear all the r.Active words after each variable.
717         gen := uint32(0)
718
719         for _, v := range vars {
720                 gen++
721                 for f := v.use; f != nil; f = f.Data.(*Flow) {
722                         mergewalk(v, f, gen)
723                 }
724                 if v.addr {
725                         gen++
726                         for f := v.use; f != nil; f = f.Data.(*Flow) {
727                                 varkillwalk(v, f, gen)
728                         }
729                 }
730         }
731
732         // Sort variables by start.
733         bystart := make([]*TempVar, len(vars))
734         copy(bystart, vars)
735         sort.Sort(startcmp(bystart))
736
737         // List of in-use variables, sorted by end, so that the ones that
738         // will last the longest are the earliest ones in the array.
739         // The tail inuse[nfree:] holds no-longer-used variables.
740         // In theory we should use a sorted tree so that insertions are
741         // guaranteed O(log n) and then the loop is guaranteed O(n log n).
742         // In practice, it doesn't really matter.
743         inuse := make([]*TempVar, len(bystart))
744
745         ninuse := 0
746         nfree := len(bystart)
747         for _, v := range bystart {
748                 if debugmerge > 0 && Debug['v'] != 0 {
749                         fmt.Printf("consider %v: removed=%t\n", Nconv(v.node, FmtSharp), v.removed)
750                 }
751
752                 if v.removed {
753                         continue
754                 }
755
756                 // Expire no longer in use.
757                 for ninuse > 0 && inuse[ninuse-1].end < v.start {
758                         ninuse--
759                         nfree--
760                         inuse[nfree] = inuse[ninuse]
761                 }
762
763                 if debugmerge > 0 && Debug['v'] != 0 {
764                         fmt.Printf("consider %v: removed=%t nfree=%d nvar=%d\n", Nconv(v.node, FmtSharp), v.removed, nfree, len(bystart))
765                 }
766
767                 // Find old temp to reuse if possible.
768                 t := v.node.Type
769
770                 for j := nfree; j < len(inuse); j++ {
771                         v1 := inuse[j]
772                         if debugmerge > 0 && Debug['v'] != 0 {
773                                 fmt.Printf("consider %v: maybe %v: type=%v,%v addrtaken=%v,%v\n", Nconv(v.node, FmtSharp), Nconv(v1.node, FmtSharp), t, v1.node.Type, v.node.Addrtaken, v1.node.Addrtaken)
774                         }
775
776                         // Require the types to match but also require the addrtaken bits to match.
777                         // If a variable's address is taken, that disables registerization for the individual
778                         // words of the variable (for example, the base,len,cap of a slice).
779                         // We don't want to merge a non-addressed var with an addressed one and
780                         // inhibit registerization of the former.
781                         if Eqtype(t, v1.node.Type) && v.node.Addrtaken == v1.node.Addrtaken {
782                                 inuse[j] = inuse[nfree]
783                                 nfree++
784                                 if v1.merge != nil {
785                                         v.merge = v1.merge
786                                 } else {
787                                         v.merge = v1
788                                 }
789                                 nkill++
790                                 break
791                         }
792                 }
793
794                 // Sort v into inuse.
795                 j := ninuse
796                 ninuse++
797
798                 for j > 0 && inuse[j-1].end < v.end {
799                         inuse[j] = inuse[j-1]
800                         j--
801                 }
802
803                 inuse[j] = v
804         }
805
806         if debugmerge > 0 && Debug['v'] != 0 {
807                 fmt.Printf("%v [%d - %d]\n", Curfn.Func.Nname.Sym, len(vars), nkill)
808                 for _, v := range vars {
809                         fmt.Printf("var %v %v %d-%d", Nconv(v.node, FmtSharp), v.node.Type, v.start, v.end)
810                         if v.addr {
811                                 fmt.Printf(" addr=true")
812                         }
813                         if v.removed {
814                                 fmt.Printf(" removed=true")
815                         }
816                         if v.merge != nil {
817                                 fmt.Printf(" merge %v", Nconv(v.merge.node, FmtSharp))
818                         }
819                         if v.start == v.end && v.def != nil {
820                                 fmt.Printf(" %v", v.def.Prog)
821                         }
822                         fmt.Printf("\n")
823                 }
824
825                 if debugmerge > 1 && Debug['v'] != 0 {
826                         Dumpit("after", g.Start, 0)
827                 }
828         }
829
830         // Update node references to use merged temporaries.
831         for f := g.Start; f != nil; f = f.Link {
832                 p := f.Prog
833                 n, _ := p.From.Node.(*Node)
834                 if n != nil {
835                         v, _ := n.Opt().(*TempVar)
836                         if v != nil && v.merge != nil {
837                                 p.From.Node = v.merge.node
838                         }
839                 }
840                 n, _ = p.To.Node.(*Node)
841                 if n != nil {
842                         v, _ := n.Opt().(*TempVar)
843                         if v != nil && v.merge != nil {
844                                 p.To.Node = v.merge.node
845                         }
846                 }
847         }
848
849         // Delete merged nodes from declaration list.
850         dcl := make([]*Node, 0, len(Curfn.Func.Dcl)-nkill)
851         for _, n := range Curfn.Func.Dcl {
852                 v, _ := n.Opt().(*TempVar)
853                 if v != nil && (v.merge != nil || v.removed) {
854                         continue
855                 }
856                 dcl = append(dcl, n)
857         }
858         Curfn.Func.Dcl = dcl
859
860         // Clear aux structures.
861         for _, v := range vars {
862                 v.node.SetOpt(nil)
863         }
864
865         Flowend(g)
866 }
867
868 func mergewalk(v *TempVar, f0 *Flow, gen uint32) {
869         var p *obj.Prog
870         var f1 *Flow
871
872         for f1 = f0; f1 != nil; f1 = f1.P1 {
873                 if uint32(f1.Active) == gen {
874                         break
875                 }
876                 f1.Active = int32(gen)
877                 p = f1.Prog
878                 if v.end < p.Pc {
879                         v.end = p.Pc
880                 }
881                 if f1 == v.def {
882                         v.start = p.Pc
883                         break
884                 }
885         }
886
887         var f2 *Flow
888         for f := f0; f != f1; f = f.P1 {
889                 for f2 = f.P2; f2 != nil; f2 = f2.P2link {
890                         mergewalk(v, f2, gen)
891                 }
892         }
893 }
894
895 func varkillwalk(v *TempVar, f0 *Flow, gen uint32) {
896         var p *obj.Prog
897         var f1 *Flow
898
899         for f1 = f0; f1 != nil; f1 = f1.S1 {
900                 if uint32(f1.Active) == gen {
901                         break
902                 }
903                 f1.Active = int32(gen)
904                 p = f1.Prog
905                 if v.end < p.Pc {
906                         v.end = p.Pc
907                 }
908                 if v.start > p.Pc {
909                         v.start = p.Pc
910                 }
911                 if p.As == obj.ARET || (p.As == obj.AVARKILL && p.To.Node == v.node) {
912                         break
913                 }
914         }
915
916         for f := f0; f != f1; f = f.S1 {
917                 varkillwalk(v, f.S2, gen)
918         }
919 }
920
921 // Eliminate redundant nil pointer checks.
922 //
923 // The code generation pass emits a CHECKNIL for every possibly nil pointer.
924 // This pass removes a CHECKNIL if every predecessor path has already
925 // checked this value for nil.
926 //
927 // Simple backwards flood from check to definition.
928 // Run prog loop backward from end of program to beginning to avoid quadratic
929 // behavior removing a run of checks.
930 //
931 // Assume that stack variables with address not taken can be loaded multiple times
932 // from memory without being rechecked. Other variables need to be checked on
933 // each load.
934
935 var killed int // f.Data is either nil or &killed
936
937 func nilopt(firstp *obj.Prog) {
938         g := Flowstart(firstp, nil)
939         if g == nil {
940                 return
941         }
942
943         if Debug_checknil > 1 { // || strcmp(curfn->nname->sym->name, "f1") == 0
944                 Dumpit("nilopt", g.Start, 0)
945         }
946
947         ncheck := 0
948         nkill := 0
949         var p *obj.Prog
950         for f := g.Start; f != nil; f = f.Link {
951                 p = f.Prog
952                 if p.As != obj.ACHECKNIL || !Thearch.Regtyp(&p.From) {
953                         continue
954                 }
955                 ncheck++
956                 if Thearch.Stackaddr(&p.From) {
957                         if Debug_checknil != 0 && p.Lineno > 1 {
958                                 Warnl(p.Lineno, "removed nil check of SP address")
959                         }
960                         f.Data = &killed
961                         continue
962                 }
963
964                 nilwalkfwd(f)
965                 if f.Data != nil {
966                         if Debug_checknil != 0 && p.Lineno > 1 {
967                                 Warnl(p.Lineno, "removed nil check before indirect")
968                         }
969                         continue
970                 }
971
972                 nilwalkback(f)
973                 if f.Data != nil {
974                         if Debug_checknil != 0 && p.Lineno > 1 {
975                                 Warnl(p.Lineno, "removed repeated nil check")
976                         }
977                         continue
978                 }
979         }
980
981         for f := g.Start; f != nil; f = f.Link {
982                 if f.Data != nil {
983                         nkill++
984                         Thearch.Excise(f)
985                 }
986         }
987
988         Flowend(g)
989
990         if Debug_checknil > 1 {
991                 fmt.Printf("%v: removed %d of %d nil checks\n", Curfn.Func.Nname.Sym, nkill, ncheck)
992         }
993 }
994
995 func nilwalkback(fcheck *Flow) {
996         for f := fcheck; f != nil; f = Uniqp(f) {
997                 p := f.Prog
998                 if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
999                         // Found initialization of value we're checking for nil.
1000                         // without first finding the check, so this one is unchecked.
1001                         return
1002                 }
1003
1004                 if f != fcheck && p.As == obj.ACHECKNIL && Thearch.Sameaddr(&p.From, &fcheck.Prog.From) {
1005                         fcheck.Data = &killed
1006                         return
1007                 }
1008         }
1009 }
1010
1011 // Here is a more complex version that scans backward across branches.
1012 // It assumes fcheck->kill = 1 has been set on entry, and its job is to find a reason
1013 // to keep the check (setting fcheck->kill = 0).
1014 // It doesn't handle copying of aggregates as well as I would like,
1015 // nor variables with their address taken,
1016 // and it's too subtle to turn on this late in Go 1.2. Perhaps for Go 1.3.
1017 /*
1018 for(f1 = f0; f1 != nil; f1 = f1->p1) {
1019         if(f1->active == gen)
1020                 break;
1021         f1->active = gen;
1022         p = f1->prog;
1023
1024         // If same check, stop this loop but still check
1025         // alternate predecessors up to this point.
1026         if(f1 != fcheck && p->as == ACHECKNIL && thearch.sameaddr(&p->from, &fcheck->prog->from))
1027                 break;
1028
1029         if((p.Info.flags & RightWrite) && thearch.sameaddr(&p->to, &fcheck->prog->from)) {
1030                 // Found initialization of value we're checking for nil.
1031                 // without first finding the check, so this one is unchecked.
1032                 fcheck->kill = 0;
1033                 return;
1034         }
1035
1036         if(f1->p1 == nil && f1->p2 == nil) {
1037                 print("lost pred for %v\n", fcheck->prog);
1038                 for(f1=f0; f1!=nil; f1=f1->p1) {
1039                         thearch.proginfo(&info, f1->prog);
1040                         print("\t%v %d %d %D %D\n", r1->prog, info.flags&RightWrite, thearch.sameaddr(&f1->prog->to, &fcheck->prog->from), &f1->prog->to, &fcheck->prog->from);
1041                 }
1042                 fatal("lost pred trail");
1043         }
1044 }
1045
1046 for(f = f0; f != f1; f = f->p1)
1047         for(f2 = f->p2; f2 != nil; f2 = f2->p2link)
1048                 nilwalkback(fcheck, f2, gen);
1049 */
1050
1051 func nilwalkfwd(fcheck *Flow) {
1052         // If the path down from rcheck dereferences the address
1053         // (possibly with a small offset) before writing to memory
1054         // and before any subsequent checks, it's okay to wait for
1055         // that implicit check. Only consider this basic block to
1056         // avoid problems like:
1057         //      _ = *x // should panic
1058         //      for {} // no writes but infinite loop may be considered visible
1059
1060         var last *Flow
1061         for f := Uniqs(fcheck); f != nil; f = Uniqs(f) {
1062                 p := f.Prog
1063                 if (p.Info.Flags&LeftRead != 0) && Thearch.Smallindir(&p.From, &fcheck.Prog.From) {
1064                         fcheck.Data = &killed
1065                         return
1066                 }
1067
1068                 if (p.Info.Flags&(RightRead|RightWrite) != 0) && Thearch.Smallindir(&p.To, &fcheck.Prog.From) {
1069                         fcheck.Data = &killed
1070                         return
1071                 }
1072
1073                 // Stop if another nil check happens.
1074                 if p.As == obj.ACHECKNIL {
1075                         return
1076                 }
1077
1078                 // Stop if value is lost.
1079                 if (p.Info.Flags&RightWrite != 0) && Thearch.Sameaddr(&p.To, &fcheck.Prog.From) {
1080                         return
1081                 }
1082
1083                 // Stop if memory write.
1084                 if (p.Info.Flags&RightWrite != 0) && !Thearch.Regtyp(&p.To) {
1085                         return
1086                 }
1087
1088                 // Stop if we jump backward.
1089                 if last != nil && f.Id <= last.Id {
1090                         return
1091                 }
1092                 last = f
1093         }
1094 }