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