1// Copyright 2013 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 5package ir 6 7// This file implements the Function and BasicBlock types. 8 9import ( 10 "bytes" 11 "fmt" 12 "go/ast" 13 "go/constant" 14 "go/format" 15 "go/token" 16 "go/types" 17 "io" 18 "os" 19 "strings" 20) 21 22// addEdge adds a control-flow graph edge from from to to. 23func addEdge(from, to *BasicBlock) { 24 from.Succs = append(from.Succs, to) 25 to.Preds = append(to.Preds, from) 26} 27 28// Control returns the last instruction in the block. 29func (b *BasicBlock) Control() Instruction { 30 if len(b.Instrs) == 0 { 31 return nil 32 } 33 return b.Instrs[len(b.Instrs)-1] 34} 35 36// SIgmaFor returns the sigma node for v coming from pred. 37func (b *BasicBlock) SigmaFor(v Value, pred *BasicBlock) *Sigma { 38 for _, instr := range b.Instrs { 39 sigma, ok := instr.(*Sigma) 40 if !ok { 41 // no more sigmas 42 return nil 43 } 44 if sigma.From == pred && sigma.X == v { 45 return sigma 46 } 47 } 48 return nil 49} 50 51// Parent returns the function that contains block b. 52func (b *BasicBlock) Parent() *Function { return b.parent } 53 54// String returns a human-readable label of this block. 55// It is not guaranteed unique within the function. 56// 57func (b *BasicBlock) String() string { 58 return fmt.Sprintf("%d", b.Index) 59} 60 61// emit appends an instruction to the current basic block. 62// If the instruction defines a Value, it is returned. 63// 64func (b *BasicBlock) emit(i Instruction, source ast.Node) Value { 65 i.setSource(source) 66 i.setBlock(b) 67 b.Instrs = append(b.Instrs, i) 68 v, _ := i.(Value) 69 return v 70} 71 72// predIndex returns the i such that b.Preds[i] == c or panics if 73// there is none. 74func (b *BasicBlock) predIndex(c *BasicBlock) int { 75 for i, pred := range b.Preds { 76 if pred == c { 77 return i 78 } 79 } 80 panic(fmt.Sprintf("no edge %s -> %s", c, b)) 81} 82 83// succIndex returns the i such that b.Succs[i] == c or -1 if there is none. 84func (b *BasicBlock) succIndex(c *BasicBlock) int { 85 for i, succ := range b.Succs { 86 if succ == c { 87 return i 88 } 89 } 90 return -1 91} 92 93// hasPhi returns true if b.Instrs contains φ-nodes. 94func (b *BasicBlock) hasPhi() bool { 95 _, ok := b.Instrs[0].(*Phi) 96 return ok 97} 98 99func (b *BasicBlock) Phis() []Instruction { 100 return b.phis() 101} 102 103// phis returns the prefix of b.Instrs containing all the block's φ-nodes. 104func (b *BasicBlock) phis() []Instruction { 105 for i, instr := range b.Instrs { 106 if _, ok := instr.(*Phi); !ok { 107 return b.Instrs[:i] 108 } 109 } 110 return nil // unreachable in well-formed blocks 111} 112 113// replacePred replaces all occurrences of p in b's predecessor list with q. 114// Ordinarily there should be at most one. 115// 116func (b *BasicBlock) replacePred(p, q *BasicBlock) { 117 for i, pred := range b.Preds { 118 if pred == p { 119 b.Preds[i] = q 120 } 121 } 122} 123 124// replaceSucc replaces all occurrences of p in b's successor list with q. 125// Ordinarily there should be at most one. 126// 127func (b *BasicBlock) replaceSucc(p, q *BasicBlock) { 128 for i, succ := range b.Succs { 129 if succ == p { 130 b.Succs[i] = q 131 } 132 } 133} 134 135// removePred removes all occurrences of p in b's 136// predecessor list and φ-nodes. 137// Ordinarily there should be at most one. 138// 139func (b *BasicBlock) removePred(p *BasicBlock) { 140 phis := b.phis() 141 142 // We must preserve edge order for φ-nodes. 143 j := 0 144 for i, pred := range b.Preds { 145 if pred != p { 146 b.Preds[j] = b.Preds[i] 147 // Strike out φ-edge too. 148 for _, instr := range phis { 149 phi := instr.(*Phi) 150 phi.Edges[j] = phi.Edges[i] 151 } 152 j++ 153 } 154 } 155 // Nil out b.Preds[j:] and φ-edges[j:] to aid GC. 156 for i := j; i < len(b.Preds); i++ { 157 b.Preds[i] = nil 158 for _, instr := range phis { 159 instr.(*Phi).Edges[i] = nil 160 } 161 } 162 b.Preds = b.Preds[:j] 163 for _, instr := range phis { 164 phi := instr.(*Phi) 165 phi.Edges = phi.Edges[:j] 166 } 167} 168 169// Destinations associated with unlabelled for/switch/select stmts. 170// We push/pop one of these as we enter/leave each construct and for 171// each BranchStmt we scan for the innermost target of the right type. 172// 173type targets struct { 174 tail *targets // rest of stack 175 _break *BasicBlock 176 _continue *BasicBlock 177 _fallthrough *BasicBlock 178} 179 180// Destinations associated with a labelled block. 181// We populate these as labels are encountered in forward gotos or 182// labelled statements. 183// 184type lblock struct { 185 _goto *BasicBlock 186 _break *BasicBlock 187 _continue *BasicBlock 188} 189 190// labelledBlock returns the branch target associated with the 191// specified label, creating it if needed. 192// 193func (f *Function) labelledBlock(label *ast.Ident) *lblock { 194 lb := f.lblocks[label.Obj] 195 if lb == nil { 196 lb = &lblock{_goto: f.newBasicBlock(label.Name)} 197 if f.lblocks == nil { 198 f.lblocks = make(map[*ast.Object]*lblock) 199 } 200 f.lblocks[label.Obj] = lb 201 } 202 return lb 203} 204 205// addParam adds a (non-escaping) parameter to f.Params of the 206// specified name, type and source position. 207// 208func (f *Function) addParam(name string, typ types.Type, source ast.Node) *Parameter { 209 var b *BasicBlock 210 if len(f.Blocks) > 0 { 211 b = f.Blocks[0] 212 } 213 v := &Parameter{ 214 name: name, 215 } 216 v.setBlock(b) 217 v.setType(typ) 218 v.setSource(source) 219 f.Params = append(f.Params, v) 220 if b != nil { 221 // There may be no blocks if this function has no body. We 222 // still create params, but aren't interested in the 223 // instruction. 224 f.Blocks[0].Instrs = append(f.Blocks[0].Instrs, v) 225 } 226 return v 227} 228 229func (f *Function) addParamObj(obj types.Object, source ast.Node) *Parameter { 230 name := obj.Name() 231 if name == "" { 232 name = fmt.Sprintf("arg%d", len(f.Params)) 233 } 234 param := f.addParam(name, obj.Type(), source) 235 param.object = obj 236 return param 237} 238 239// addSpilledParam declares a parameter that is pre-spilled to the 240// stack; the function body will load/store the spilled location. 241// Subsequent lifting will eliminate spills where possible. 242// 243func (f *Function) addSpilledParam(obj types.Object, source ast.Node) { 244 param := f.addParamObj(obj, source) 245 spill := &Alloc{} 246 spill.setType(types.NewPointer(obj.Type())) 247 spill.source = source 248 f.objects[obj] = spill 249 f.Locals = append(f.Locals, spill) 250 f.emit(spill, source) 251 emitStore(f, spill, param, source) 252 // f.emit(&Store{Addr: spill, Val: param}) 253} 254 255// startBody initializes the function prior to generating IR code for its body. 256// Precondition: f.Type() already set. 257// 258func (f *Function) startBody() { 259 entry := f.newBasicBlock("entry") 260 f.currentBlock = entry 261 f.objects = make(map[types.Object]Value) // needed for some synthetics, e.g. init 262} 263 264func (f *Function) blockset(i int) *BlockSet { 265 bs := &f.blocksets[i] 266 if len(bs.values) != len(f.Blocks) { 267 if cap(bs.values) >= len(f.Blocks) { 268 bs.values = bs.values[:len(f.Blocks)] 269 bs.Clear() 270 } else { 271 bs.values = make([]bool, len(f.Blocks)) 272 } 273 } else { 274 bs.Clear() 275 } 276 return bs 277} 278 279func (f *Function) exitBlock() { 280 old := f.currentBlock 281 282 f.Exit = f.newBasicBlock("exit") 283 f.currentBlock = f.Exit 284 285 ret := f.results() 286 results := make([]Value, len(ret)) 287 // Run function calls deferred in this 288 // function when explicitly returning from it. 289 f.emit(new(RunDefers), nil) 290 for i, r := range ret { 291 results[i] = emitLoad(f, r, nil) 292 } 293 294 f.emit(&Return{Results: results}, nil) 295 f.currentBlock = old 296} 297 298// createSyntacticParams populates f.Params and generates code (spills 299// and named result locals) for all the parameters declared in the 300// syntax. In addition it populates the f.objects mapping. 301// 302// Preconditions: 303// f.startBody() was called. 304// Postcondition: 305// len(f.Params) == len(f.Signature.Params) + (f.Signature.Recv() ? 1 : 0) 306// 307func (f *Function) createSyntacticParams(recv *ast.FieldList, functype *ast.FuncType) { 308 // Receiver (at most one inner iteration). 309 if recv != nil { 310 for _, field := range recv.List { 311 for _, n := range field.Names { 312 f.addSpilledParam(f.Pkg.info.Defs[n], n) 313 } 314 // Anonymous receiver? No need to spill. 315 if field.Names == nil { 316 f.addParamObj(f.Signature.Recv(), field) 317 } 318 } 319 } 320 321 // Parameters. 322 if functype.Params != nil { 323 n := len(f.Params) // 1 if has recv, 0 otherwise 324 for _, field := range functype.Params.List { 325 for _, n := range field.Names { 326 f.addSpilledParam(f.Pkg.info.Defs[n], n) 327 } 328 // Anonymous parameter? No need to spill. 329 if field.Names == nil { 330 f.addParamObj(f.Signature.Params().At(len(f.Params)-n), field) 331 } 332 } 333 } 334 335 // Named results. 336 if functype.Results != nil { 337 for _, field := range functype.Results.List { 338 // Implicit "var" decl of locals for named results. 339 for _, n := range field.Names { 340 f.namedResults = append(f.namedResults, f.addLocalForIdent(n)) 341 } 342 } 343 344 if len(f.namedResults) == 0 { 345 sig := f.Signature.Results() 346 for i := 0; i < sig.Len(); i++ { 347 // XXX position information 348 v := f.addLocal(sig.At(i).Type(), nil) 349 f.implicitResults = append(f.implicitResults, v) 350 } 351 } 352 } 353} 354 355func numberNodes(f *Function) { 356 var base ID 357 for _, b := range f.Blocks { 358 for _, instr := range b.Instrs { 359 if instr == nil { 360 continue 361 } 362 base++ 363 instr.setID(base) 364 } 365 } 366} 367 368// buildReferrers populates the def/use information in all non-nil 369// Value.Referrers slice. 370// Precondition: all such slices are initially empty. 371func buildReferrers(f *Function) { 372 var rands []*Value 373 for _, b := range f.Blocks { 374 for _, instr := range b.Instrs { 375 rands = instr.Operands(rands[:0]) // recycle storage 376 for _, rand := range rands { 377 if r := *rand; r != nil { 378 if ref := r.Referrers(); ref != nil { 379 *ref = append(*ref, instr) 380 } 381 } 382 } 383 } 384 } 385} 386 387func (f *Function) emitConsts() { 388 if len(f.Blocks) == 0 { 389 f.consts = nil 390 return 391 } 392 393 // TODO(dh): our deduplication only works on booleans and 394 // integers. other constants are represented as pointers to 395 // things. 396 if len(f.consts) == 0 { 397 return 398 } else if len(f.consts) <= 32 { 399 f.emitConstsFew() 400 } else { 401 f.emitConstsMany() 402 } 403} 404 405func (f *Function) emitConstsFew() { 406 dedup := make([]*Const, 0, 32) 407 for _, c := range f.consts { 408 if len(*c.Referrers()) == 0 { 409 continue 410 } 411 found := false 412 for _, d := range dedup { 413 if c.typ == d.typ && c.Value == d.Value { 414 replaceAll(c, d) 415 found = true 416 break 417 } 418 } 419 if !found { 420 dedup = append(dedup, c) 421 } 422 } 423 424 instrs := make([]Instruction, len(f.Blocks[0].Instrs)+len(dedup)) 425 for i, c := range dedup { 426 instrs[i] = c 427 c.setBlock(f.Blocks[0]) 428 } 429 copy(instrs[len(dedup):], f.Blocks[0].Instrs) 430 f.Blocks[0].Instrs = instrs 431 f.consts = nil 432} 433 434func (f *Function) emitConstsMany() { 435 type constKey struct { 436 typ types.Type 437 value constant.Value 438 } 439 440 m := make(map[constKey]Value, len(f.consts)) 441 areNil := 0 442 for i, c := range f.consts { 443 if len(*c.Referrers()) == 0 { 444 f.consts[i] = nil 445 areNil++ 446 continue 447 } 448 449 k := constKey{ 450 typ: c.typ, 451 value: c.Value, 452 } 453 if dup, ok := m[k]; !ok { 454 m[k] = c 455 } else { 456 f.consts[i] = nil 457 areNil++ 458 replaceAll(c, dup) 459 } 460 } 461 462 instrs := make([]Instruction, len(f.Blocks[0].Instrs)+len(f.consts)-areNil) 463 i := 0 464 for _, c := range f.consts { 465 if c != nil { 466 instrs[i] = c 467 c.setBlock(f.Blocks[0]) 468 i++ 469 } 470 } 471 copy(instrs[i:], f.Blocks[0].Instrs) 472 f.Blocks[0].Instrs = instrs 473 f.consts = nil 474} 475 476// buildFakeExits ensures that every block in the function is 477// reachable in reverse from the Exit block. This is required to build 478// a full post-dominator tree, and to ensure the exit block's 479// inclusion in the dominator tree. 480func buildFakeExits(fn *Function) { 481 // Find back-edges via forward DFS 482 fn.fakeExits = BlockSet{values: make([]bool, len(fn.Blocks))} 483 seen := fn.blockset(0) 484 backEdges := fn.blockset(1) 485 486 var dfs func(b *BasicBlock) 487 dfs = func(b *BasicBlock) { 488 if !seen.Add(b) { 489 backEdges.Add(b) 490 return 491 } 492 for _, pred := range b.Succs { 493 dfs(pred) 494 } 495 } 496 dfs(fn.Blocks[0]) 497buildLoop: 498 for { 499 seen := fn.blockset(2) 500 var dfs func(b *BasicBlock) 501 dfs = func(b *BasicBlock) { 502 if !seen.Add(b) { 503 return 504 } 505 for _, pred := range b.Preds { 506 dfs(pred) 507 } 508 if b == fn.Exit { 509 for _, b := range fn.Blocks { 510 if fn.fakeExits.Has(b) { 511 dfs(b) 512 } 513 } 514 } 515 } 516 dfs(fn.Exit) 517 518 for _, b := range fn.Blocks { 519 if !seen.Has(b) && backEdges.Has(b) { 520 // Block b is not reachable from the exit block. Add a 521 // fake jump from b to exit, then try again. Note that we 522 // only add one fake edge at a time, as it may make 523 // multiple blocks reachable. 524 // 525 // We only consider those blocks that have back edges. 526 // Any unreachable block that doesn't have a back edge 527 // must flow into a loop, which by definition has a 528 // back edge. Thus, by looking for loops, we should 529 // need fewer fake edges overall. 530 fn.fakeExits.Add(b) 531 continue buildLoop 532 } 533 } 534 535 break 536 } 537} 538 539// finishBody() finalizes the function after IR code generation of its body. 540func (f *Function) finishBody() { 541 f.objects = nil 542 f.currentBlock = nil 543 f.lblocks = nil 544 545 // Remove from f.Locals any Allocs that escape to the heap. 546 j := 0 547 for _, l := range f.Locals { 548 if !l.Heap { 549 f.Locals[j] = l 550 j++ 551 } 552 } 553 // Nil out f.Locals[j:] to aid GC. 554 for i := j; i < len(f.Locals); i++ { 555 f.Locals[i] = nil 556 } 557 f.Locals = f.Locals[:j] 558 559 optimizeBlocks(f) 560 buildReferrers(f) 561 buildDomTree(f) 562 buildPostDomTree(f) 563 564 if f.Prog.mode&NaiveForm == 0 { 565 lift(f) 566 } 567 568 // emit constants after lifting, because lifting may produce new constants. 569 f.emitConsts() 570 571 f.namedResults = nil // (used by lifting) 572 f.implicitResults = nil 573 574 numberNodes(f) 575 576 defer f.wr.Close() 577 f.wr.WriteFunc("start", "start", f) 578 579 if f.Prog.mode&PrintFunctions != 0 { 580 printMu.Lock() 581 f.WriteTo(os.Stdout) 582 printMu.Unlock() 583 } 584 585 if f.Prog.mode&SanityCheckFunctions != 0 { 586 mustSanityCheck(f, nil) 587 } 588} 589 590func isUselessPhi(phi *Phi) (Value, bool) { 591 var v0 Value 592 for _, e := range phi.Edges { 593 if e == phi { 594 continue 595 } 596 if v0 == nil { 597 v0 = e 598 } 599 if v0 != e { 600 if v0, ok := v0.(*Const); ok { 601 if e, ok := e.(*Const); ok { 602 if v0.typ == e.typ && v0.Value == e.Value { 603 continue 604 } 605 } 606 } 607 return nil, false 608 } 609 } 610 return v0, true 611} 612 613func (f *Function) RemoveNilBlocks() { 614 f.removeNilBlocks() 615} 616 617// removeNilBlocks eliminates nils from f.Blocks and updates each 618// BasicBlock.Index. Use this after any pass that may delete blocks. 619// 620func (f *Function) removeNilBlocks() { 621 j := 0 622 for _, b := range f.Blocks { 623 if b != nil { 624 b.Index = j 625 f.Blocks[j] = b 626 j++ 627 } 628 } 629 // Nil out f.Blocks[j:] to aid GC. 630 for i := j; i < len(f.Blocks); i++ { 631 f.Blocks[i] = nil 632 } 633 f.Blocks = f.Blocks[:j] 634} 635 636// SetDebugMode sets the debug mode for package pkg. If true, all its 637// functions will include full debug info. This greatly increases the 638// size of the instruction stream, and causes Functions to depend upon 639// the ASTs, potentially keeping them live in memory for longer. 640// 641func (pkg *Package) SetDebugMode(debug bool) { 642 // TODO(adonovan): do we want ast.File granularity? 643 pkg.debug = debug 644} 645 646// debugInfo reports whether debug info is wanted for this function. 647func (f *Function) debugInfo() bool { 648 return f.Pkg != nil && f.Pkg.debug 649} 650 651// addNamedLocal creates a local variable, adds it to function f and 652// returns it. Its name and type are taken from obj. Subsequent 653// calls to f.lookup(obj) will return the same local. 654// 655func (f *Function) addNamedLocal(obj types.Object, source ast.Node) *Alloc { 656 l := f.addLocal(obj.Type(), source) 657 f.objects[obj] = l 658 return l 659} 660 661func (f *Function) addLocalForIdent(id *ast.Ident) *Alloc { 662 return f.addNamedLocal(f.Pkg.info.Defs[id], id) 663} 664 665// addLocal creates an anonymous local variable of type typ, adds it 666// to function f and returns it. pos is the optional source location. 667// 668func (f *Function) addLocal(typ types.Type, source ast.Node) *Alloc { 669 v := &Alloc{} 670 v.setType(types.NewPointer(typ)) 671 f.Locals = append(f.Locals, v) 672 f.emit(v, source) 673 return v 674} 675 676// lookup returns the address of the named variable identified by obj 677// that is local to function f or one of its enclosing functions. 678// If escaping, the reference comes from a potentially escaping pointer 679// expression and the referent must be heap-allocated. 680// 681func (f *Function) lookup(obj types.Object, escaping bool) Value { 682 if v, ok := f.objects[obj]; ok { 683 if alloc, ok := v.(*Alloc); ok && escaping { 684 alloc.Heap = true 685 } 686 return v // function-local var (address) 687 } 688 689 // Definition must be in an enclosing function; 690 // plumb it through intervening closures. 691 if f.parent == nil { 692 panic("no ir.Value for " + obj.String()) 693 } 694 outer := f.parent.lookup(obj, true) // escaping 695 v := &FreeVar{ 696 name: obj.Name(), 697 typ: outer.Type(), 698 outer: outer, 699 parent: f, 700 } 701 f.objects[obj] = v 702 f.FreeVars = append(f.FreeVars, v) 703 return v 704} 705 706// emit emits the specified instruction to function f. 707func (f *Function) emit(instr Instruction, source ast.Node) Value { 708 return f.currentBlock.emit(instr, source) 709} 710 711// RelString returns the full name of this function, qualified by 712// package name, receiver type, etc. 713// 714// The specific formatting rules are not guaranteed and may change. 715// 716// Examples: 717// "math.IsNaN" // a package-level function 718// "(*bytes.Buffer).Bytes" // a declared method or a wrapper 719// "(*bytes.Buffer).Bytes$thunk" // thunk (func wrapping method; receiver is param 0) 720// "(*bytes.Buffer).Bytes$bound" // bound (func wrapping method; receiver supplied by closure) 721// "main.main$1" // an anonymous function in main 722// "main.init#1" // a declared init function 723// "main.init" // the synthesized package initializer 724// 725// When these functions are referred to from within the same package 726// (i.e. from == f.Pkg.Object), they are rendered without the package path. 727// For example: "IsNaN", "(*Buffer).Bytes", etc. 728// 729// All non-synthetic functions have distinct package-qualified names. 730// (But two methods may have the same name "(T).f" if one is a synthetic 731// wrapper promoting a non-exported method "f" from another package; in 732// that case, the strings are equal but the identifiers "f" are distinct.) 733// 734func (f *Function) RelString(from *types.Package) string { 735 // Anonymous? 736 if f.parent != nil { 737 // An anonymous function's Name() looks like "parentName$1", 738 // but its String() should include the type/package/etc. 739 parent := f.parent.RelString(from) 740 for i, anon := range f.parent.AnonFuncs { 741 if anon == f { 742 return fmt.Sprintf("%s$%d", parent, 1+i) 743 } 744 } 745 746 return f.name // should never happen 747 } 748 749 // Method (declared or wrapper)? 750 if recv := f.Signature.Recv(); recv != nil { 751 return f.relMethod(from, recv.Type()) 752 } 753 754 // Thunk? 755 if f.method != nil { 756 return f.relMethod(from, f.method.Recv()) 757 } 758 759 // Bound? 760 if len(f.FreeVars) == 1 && strings.HasSuffix(f.name, "$bound") { 761 return f.relMethod(from, f.FreeVars[0].Type()) 762 } 763 764 // Package-level function? 765 // Prefix with package name for cross-package references only. 766 if p := f.pkg(); p != nil && p != from { 767 return fmt.Sprintf("%s.%s", p.Path(), f.name) 768 } 769 770 // Unknown. 771 return f.name 772} 773 774func (f *Function) relMethod(from *types.Package, recv types.Type) string { 775 return fmt.Sprintf("(%s).%s", relType(recv, from), f.name) 776} 777 778// writeSignature writes to buf the signature sig in declaration syntax. 779func writeSignature(buf *bytes.Buffer, from *types.Package, name string, sig *types.Signature, params []*Parameter) { 780 buf.WriteString("func ") 781 if recv := sig.Recv(); recv != nil { 782 buf.WriteString("(") 783 if n := params[0].Name(); n != "" { 784 buf.WriteString(n) 785 buf.WriteString(" ") 786 } 787 types.WriteType(buf, params[0].Type(), types.RelativeTo(from)) 788 buf.WriteString(") ") 789 } 790 buf.WriteString(name) 791 types.WriteSignature(buf, sig, types.RelativeTo(from)) 792} 793 794func (f *Function) pkg() *types.Package { 795 if f.Pkg != nil { 796 return f.Pkg.Pkg 797 } 798 return nil 799} 800 801var _ io.WriterTo = (*Function)(nil) // *Function implements io.Writer 802 803func (f *Function) WriteTo(w io.Writer) (int64, error) { 804 var buf bytes.Buffer 805 WriteFunction(&buf, f) 806 n, err := w.Write(buf.Bytes()) 807 return int64(n), err 808} 809 810// WriteFunction writes to buf a human-readable "disassembly" of f. 811func WriteFunction(buf *bytes.Buffer, f *Function) { 812 fmt.Fprintf(buf, "# Name: %s\n", f.String()) 813 if f.Pkg != nil { 814 fmt.Fprintf(buf, "# Package: %s\n", f.Pkg.Pkg.Path()) 815 } 816 if syn := f.Synthetic; syn != "" { 817 fmt.Fprintln(buf, "# Synthetic:", syn) 818 } 819 if pos := f.Pos(); pos.IsValid() { 820 fmt.Fprintf(buf, "# Location: %s\n", f.Prog.Fset.Position(pos)) 821 } 822 823 if f.parent != nil { 824 fmt.Fprintf(buf, "# Parent: %s\n", f.parent.Name()) 825 } 826 827 from := f.pkg() 828 829 if f.FreeVars != nil { 830 buf.WriteString("# Free variables:\n") 831 for i, fv := range f.FreeVars { 832 fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, fv.Name(), relType(fv.Type(), from)) 833 } 834 } 835 836 if len(f.Locals) > 0 { 837 buf.WriteString("# Locals:\n") 838 for i, l := range f.Locals { 839 fmt.Fprintf(buf, "# % 3d:\t%s %s\n", i, l.Name(), relType(deref(l.Type()), from)) 840 } 841 } 842 writeSignature(buf, from, f.Name(), f.Signature, f.Params) 843 buf.WriteString(":\n") 844 845 if f.Blocks == nil { 846 buf.WriteString("\t(external)\n") 847 } 848 849 for _, b := range f.Blocks { 850 if b == nil { 851 // Corrupt CFG. 852 fmt.Fprintf(buf, ".nil:\n") 853 continue 854 } 855 fmt.Fprintf(buf, "b%d:", b.Index) 856 if len(b.Preds) > 0 { 857 fmt.Fprint(buf, " ←") 858 for _, pred := range b.Preds { 859 fmt.Fprintf(buf, " b%d", pred.Index) 860 } 861 } 862 if b.Comment != "" { 863 fmt.Fprintf(buf, " # %s", b.Comment) 864 } 865 buf.WriteByte('\n') 866 867 if false { // CFG debugging 868 fmt.Fprintf(buf, "\t# CFG: %s --> %s --> %s\n", b.Preds, b, b.Succs) 869 } 870 871 buf2 := &bytes.Buffer{} 872 for _, instr := range b.Instrs { 873 buf.WriteString("\t") 874 switch v := instr.(type) { 875 case Value: 876 // Left-align the instruction. 877 if name := v.Name(); name != "" { 878 fmt.Fprintf(buf, "%s = ", name) 879 } 880 buf.WriteString(instr.String()) 881 case nil: 882 // Be robust against bad transforms. 883 buf.WriteString("<deleted>") 884 default: 885 buf.WriteString(instr.String()) 886 } 887 buf.WriteString("\n") 888 889 if f.Prog.mode&PrintSource != 0 { 890 if s := instr.Source(); s != nil { 891 buf2.Reset() 892 format.Node(buf2, f.Prog.Fset, s) 893 for { 894 line, err := buf2.ReadString('\n') 895 if len(line) == 0 { 896 break 897 } 898 buf.WriteString("\t\t> ") 899 buf.WriteString(line) 900 if line[len(line)-1] != '\n' { 901 buf.WriteString("\n") 902 } 903 if err != nil { 904 break 905 } 906 } 907 } 908 } 909 } 910 buf.WriteString("\n") 911 } 912} 913 914// newBasicBlock adds to f a new basic block and returns it. It does 915// not automatically become the current block for subsequent calls to emit. 916// comment is an optional string for more readable debugging output. 917// 918func (f *Function) newBasicBlock(comment string) *BasicBlock { 919 b := &BasicBlock{ 920 Index: len(f.Blocks), 921 Comment: comment, 922 parent: f, 923 } 924 b.Succs = b.succs2[:0] 925 f.Blocks = append(f.Blocks, b) 926 return b 927} 928 929// NewFunction returns a new synthetic Function instance belonging to 930// prog, with its name and signature fields set as specified. 931// 932// The caller is responsible for initializing the remaining fields of 933// the function object, e.g. Pkg, Params, Blocks. 934// 935// It is practically impossible for clients to construct well-formed 936// IR functions/packages/programs directly, so we assume this is the 937// job of the Builder alone. NewFunction exists to provide clients a 938// little flexibility. For example, analysis tools may wish to 939// construct fake Functions for the root of the callgraph, a fake 940// "reflect" package, etc. 941// 942// TODO(adonovan): think harder about the API here. 943// 944func (prog *Program) NewFunction(name string, sig *types.Signature, provenance string) *Function { 945 return &Function{Prog: prog, name: name, Signature: sig, Synthetic: provenance} 946} 947 948//lint:ignore U1000 we may make use of this for functions loaded from export data 949type extentNode [2]token.Pos 950 951func (n extentNode) Pos() token.Pos { return n[0] } 952func (n extentNode) End() token.Pos { return n[1] } 953 954func (f *Function) initHTML(name string) { 955 if name == "" { 956 return 957 } 958 if rel := f.RelString(nil); rel == name { 959 f.wr = NewHTMLWriter("ir.html", rel, "") 960 } 961} 962