github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/gc/phi.go (about)

     1  // Copyright 2016 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package gc
     6  
     7  import (
     8  	"github.com/gagliardetto/golang-go/cmd/compile/internal/ssa"
     9  	"github.com/gagliardetto/golang-go/cmd/compile/internal/types"
    10  	"github.com/gagliardetto/golang-go/cmd/internal/src"
    11  	"container/heap"
    12  	"fmt"
    13  )
    14  
    15  // This file contains the algorithm to place phi nodes in a function.
    16  // For small functions, we use Braun, Buchwald, Hack, Leißa, Mallon, and Zwinkau.
    17  // https://pp.info.uni-karlsruhe.de/uploads/publikationen/braun13cc.pdf
    18  // For large functions, we use Sreedhar & Gao: A Linear Time Algorithm for Placing Φ-Nodes.
    19  // http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.8.1979&rep=rep1&type=pdf
    20  
    21  const smallBlocks = 500
    22  
    23  const debugPhi = false
    24  
    25  // insertPhis finds all the places in the function where a phi is
    26  // necessary and inserts them.
    27  // Uses FwdRef ops to find all uses of variables, and s.defvars to find
    28  // all definitions.
    29  // Phi values are inserted, and all FwdRefs are changed to a Copy
    30  // of the appropriate phi or definition.
    31  // TODO: make this part of cmd/compile/internal/ssa somehow?
    32  func (s *state) insertPhis() {
    33  	if len(s.f.Blocks) <= smallBlocks {
    34  		sps := simplePhiState{s: s, f: s.f, defvars: s.defvars}
    35  		sps.insertPhis()
    36  		return
    37  	}
    38  	ps := phiState{s: s, f: s.f, defvars: s.defvars}
    39  	ps.insertPhis()
    40  }
    41  
    42  type phiState struct {
    43  	s       *state                 // SSA state
    44  	f       *ssa.Func              // function to work on
    45  	defvars []map[*Node]*ssa.Value // defined variables at end of each block
    46  
    47  	varnum map[*Node]int32 // variable numbering
    48  
    49  	// properties of the dominator tree
    50  	idom  []*ssa.Block // dominator parents
    51  	tree  []domBlock   // dominator child+sibling
    52  	level []int32      // level in dominator tree (0 = root or unreachable, 1 = children of root, ...)
    53  
    54  	// scratch locations
    55  	priq   blockHeap    // priority queue of blocks, higher level (toward leaves) = higher priority
    56  	q      []*ssa.Block // inner loop queue
    57  	queued *sparseSet   // has been put in q
    58  	hasPhi *sparseSet   // has a phi
    59  	hasDef *sparseSet   // has a write of the variable we're processing
    60  
    61  	// miscellaneous
    62  	placeholder *ssa.Value // dummy value to use as a "not set yet" placeholder.
    63  }
    64  
    65  func (s *phiState) insertPhis() {
    66  	if debugPhi {
    67  		fmt.Println(s.f.String())
    68  	}
    69  
    70  	// Find all the variables for which we need to match up reads & writes.
    71  	// This step prunes any basic-block-only variables from consideration.
    72  	// Generate a numbering for these variables.
    73  	s.varnum = map[*Node]int32{}
    74  	var vars []*Node
    75  	var vartypes []*types.Type
    76  	for _, b := range s.f.Blocks {
    77  		for _, v := range b.Values {
    78  			if v.Op != ssa.OpFwdRef {
    79  				continue
    80  			}
    81  			var_ := v.Aux.(*Node)
    82  
    83  			// Optimization: look back 1 block for the definition.
    84  			if len(b.Preds) == 1 {
    85  				c := b.Preds[0].Block()
    86  				if w := s.defvars[c.ID][var_]; w != nil {
    87  					v.Op = ssa.OpCopy
    88  					v.Aux = nil
    89  					v.AddArg(w)
    90  					continue
    91  				}
    92  			}
    93  
    94  			if _, ok := s.varnum[var_]; ok {
    95  				continue
    96  			}
    97  			s.varnum[var_] = int32(len(vartypes))
    98  			if debugPhi {
    99  				fmt.Printf("var%d = %v\n", len(vartypes), var_)
   100  			}
   101  			vars = append(vars, var_)
   102  			vartypes = append(vartypes, v.Type)
   103  		}
   104  	}
   105  
   106  	if len(vartypes) == 0 {
   107  		return
   108  	}
   109  
   110  	// Find all definitions of the variables we need to process.
   111  	// defs[n] contains all the blocks in which variable number n is assigned.
   112  	defs := make([][]*ssa.Block, len(vartypes))
   113  	for _, b := range s.f.Blocks {
   114  		for var_ := range s.defvars[b.ID] { // TODO: encode defvars some other way (explicit ops)? make defvars[n] a slice instead of a map.
   115  			if n, ok := s.varnum[var_]; ok {
   116  				defs[n] = append(defs[n], b)
   117  			}
   118  		}
   119  	}
   120  
   121  	// Make dominator tree.
   122  	s.idom = s.f.Idom()
   123  	s.tree = make([]domBlock, s.f.NumBlocks())
   124  	for _, b := range s.f.Blocks {
   125  		p := s.idom[b.ID]
   126  		if p != nil {
   127  			s.tree[b.ID].sibling = s.tree[p.ID].firstChild
   128  			s.tree[p.ID].firstChild = b
   129  		}
   130  	}
   131  	// Compute levels in dominator tree.
   132  	// With parent pointers we can do a depth-first walk without
   133  	// any auxiliary storage.
   134  	s.level = make([]int32, s.f.NumBlocks())
   135  	b := s.f.Entry
   136  levels:
   137  	for {
   138  		if p := s.idom[b.ID]; p != nil {
   139  			s.level[b.ID] = s.level[p.ID] + 1
   140  			if debugPhi {
   141  				fmt.Printf("level %s = %d\n", b, s.level[b.ID])
   142  			}
   143  		}
   144  		if c := s.tree[b.ID].firstChild; c != nil {
   145  			b = c
   146  			continue
   147  		}
   148  		for {
   149  			if c := s.tree[b.ID].sibling; c != nil {
   150  				b = c
   151  				continue levels
   152  			}
   153  			b = s.idom[b.ID]
   154  			if b == nil {
   155  				break levels
   156  			}
   157  		}
   158  	}
   159  
   160  	// Allocate scratch locations.
   161  	s.priq.level = s.level
   162  	s.q = make([]*ssa.Block, 0, s.f.NumBlocks())
   163  	s.queued = newSparseSet(s.f.NumBlocks())
   164  	s.hasPhi = newSparseSet(s.f.NumBlocks())
   165  	s.hasDef = newSparseSet(s.f.NumBlocks())
   166  	s.placeholder = s.s.entryNewValue0(ssa.OpUnknown, types.TypeInvalid)
   167  
   168  	// Generate phi ops for each variable.
   169  	for n := range vartypes {
   170  		s.insertVarPhis(n, vars[n], defs[n], vartypes[n])
   171  	}
   172  
   173  	// Resolve FwdRefs to the correct write or phi.
   174  	s.resolveFwdRefs()
   175  
   176  	// Erase variable numbers stored in AuxInt fields of phi ops. They are no longer needed.
   177  	for _, b := range s.f.Blocks {
   178  		for _, v := range b.Values {
   179  			if v.Op == ssa.OpPhi {
   180  				v.AuxInt = 0
   181  			}
   182  		}
   183  	}
   184  }
   185  
   186  func (s *phiState) insertVarPhis(n int, var_ *Node, defs []*ssa.Block, typ *types.Type) {
   187  	priq := &s.priq
   188  	q := s.q
   189  	queued := s.queued
   190  	queued.clear()
   191  	hasPhi := s.hasPhi
   192  	hasPhi.clear()
   193  	hasDef := s.hasDef
   194  	hasDef.clear()
   195  
   196  	// Add defining blocks to priority queue.
   197  	for _, b := range defs {
   198  		priq.a = append(priq.a, b)
   199  		hasDef.add(b.ID)
   200  		if debugPhi {
   201  			fmt.Printf("def of var%d in %s\n", n, b)
   202  		}
   203  	}
   204  	heap.Init(priq)
   205  
   206  	// Visit blocks defining variable n, from deepest to shallowest.
   207  	for len(priq.a) > 0 {
   208  		currentRoot := heap.Pop(priq).(*ssa.Block)
   209  		if debugPhi {
   210  			fmt.Printf("currentRoot %s\n", currentRoot)
   211  		}
   212  		// Walk subtree below definition.
   213  		// Skip subtrees we've done in previous iterations.
   214  		// Find edges exiting tree dominated by definition (the dominance frontier).
   215  		// Insert phis at target blocks.
   216  		if queued.contains(currentRoot.ID) {
   217  			s.s.Fatalf("root already in queue")
   218  		}
   219  		q = append(q, currentRoot)
   220  		queued.add(currentRoot.ID)
   221  		for len(q) > 0 {
   222  			b := q[len(q)-1]
   223  			q = q[:len(q)-1]
   224  			if debugPhi {
   225  				fmt.Printf("  processing %s\n", b)
   226  			}
   227  
   228  			currentRootLevel := s.level[currentRoot.ID]
   229  			for _, e := range b.Succs {
   230  				c := e.Block()
   231  				// TODO: if the variable is dead at c, skip it.
   232  				if s.level[c.ID] > currentRootLevel {
   233  					// a D-edge, or an edge whose target is in currentRoot's subtree.
   234  					continue
   235  				}
   236  				if hasPhi.contains(c.ID) {
   237  					continue
   238  				}
   239  				// Add a phi to block c for variable n.
   240  				hasPhi.add(c.ID)
   241  				v := c.NewValue0I(currentRoot.Pos, ssa.OpPhi, typ, int64(n)) // TODO: line number right?
   242  				// Note: we store the variable number in the phi's AuxInt field. Used temporarily by phi building.
   243  				s.s.addNamedValue(var_, v)
   244  				for range c.Preds {
   245  					v.AddArg(s.placeholder) // Actual args will be filled in by resolveFwdRefs.
   246  				}
   247  				if debugPhi {
   248  					fmt.Printf("new phi for var%d in %s: %s\n", n, c, v)
   249  				}
   250  				if !hasDef.contains(c.ID) {
   251  					// There's now a new definition of this variable in block c.
   252  					// Add it to the priority queue to explore.
   253  					heap.Push(priq, c)
   254  					hasDef.add(c.ID)
   255  				}
   256  			}
   257  
   258  			// Visit children if they have not been visited yet.
   259  			for c := s.tree[b.ID].firstChild; c != nil; c = s.tree[c.ID].sibling {
   260  				if !queued.contains(c.ID) {
   261  					q = append(q, c)
   262  					queued.add(c.ID)
   263  				}
   264  			}
   265  		}
   266  	}
   267  }
   268  
   269  // resolveFwdRefs links all FwdRef uses up to their nearest dominating definition.
   270  func (s *phiState) resolveFwdRefs() {
   271  	// Do a depth-first walk of the dominator tree, keeping track
   272  	// of the most-recently-seen value for each variable.
   273  
   274  	// Map from variable ID to SSA value at the current point of the walk.
   275  	values := make([]*ssa.Value, len(s.varnum))
   276  	for i := range values {
   277  		values[i] = s.placeholder
   278  	}
   279  
   280  	// Stack of work to do.
   281  	type stackEntry struct {
   282  		b *ssa.Block // block to explore
   283  
   284  		// variable/value pair to reinstate on exit
   285  		n int32 // variable ID
   286  		v *ssa.Value
   287  
   288  		// Note: only one of b or n,v will be set.
   289  	}
   290  	var stk []stackEntry
   291  
   292  	stk = append(stk, stackEntry{b: s.f.Entry})
   293  	for len(stk) > 0 {
   294  		work := stk[len(stk)-1]
   295  		stk = stk[:len(stk)-1]
   296  
   297  		b := work.b
   298  		if b == nil {
   299  			// On exit from a block, this case will undo any assignments done below.
   300  			values[work.n] = work.v
   301  			continue
   302  		}
   303  
   304  		// Process phis as new defs. They come before FwdRefs in this block.
   305  		for _, v := range b.Values {
   306  			if v.Op != ssa.OpPhi {
   307  				continue
   308  			}
   309  			n := int32(v.AuxInt)
   310  			// Remember the old assignment so we can undo it when we exit b.
   311  			stk = append(stk, stackEntry{n: n, v: values[n]})
   312  			// Record the new assignment.
   313  			values[n] = v
   314  		}
   315  
   316  		// Replace a FwdRef op with the current incoming value for its variable.
   317  		for _, v := range b.Values {
   318  			if v.Op != ssa.OpFwdRef {
   319  				continue
   320  			}
   321  			n := s.varnum[v.Aux.(*Node)]
   322  			v.Op = ssa.OpCopy
   323  			v.Aux = nil
   324  			v.AddArg(values[n])
   325  		}
   326  
   327  		// Establish values for variables defined in b.
   328  		for var_, v := range s.defvars[b.ID] {
   329  			n, ok := s.varnum[var_]
   330  			if !ok {
   331  				// some variable not live across a basic block boundary.
   332  				continue
   333  			}
   334  			// Remember the old assignment so we can undo it when we exit b.
   335  			stk = append(stk, stackEntry{n: n, v: values[n]})
   336  			// Record the new assignment.
   337  			values[n] = v
   338  		}
   339  
   340  		// Replace phi args in successors with the current incoming value.
   341  		for _, e := range b.Succs {
   342  			c, i := e.Block(), e.Index()
   343  			for j := len(c.Values) - 1; j >= 0; j-- {
   344  				v := c.Values[j]
   345  				if v.Op != ssa.OpPhi {
   346  					break // All phis will be at the end of the block during phi building.
   347  				}
   348  				// Only set arguments that have been resolved.
   349  				// For very wide CFGs, this significantly speeds up phi resolution.
   350  				// See golang.org/issue/8225.
   351  				if w := values[v.AuxInt]; w.Op != ssa.OpUnknown {
   352  					v.SetArg(i, w)
   353  				}
   354  			}
   355  		}
   356  
   357  		// Walk children in dominator tree.
   358  		for c := s.tree[b.ID].firstChild; c != nil; c = s.tree[c.ID].sibling {
   359  			stk = append(stk, stackEntry{b: c})
   360  		}
   361  	}
   362  }
   363  
   364  // domBlock contains extra per-block information to record the dominator tree.
   365  type domBlock struct {
   366  	firstChild *ssa.Block // first child of block in dominator tree
   367  	sibling    *ssa.Block // next child of parent in dominator tree
   368  }
   369  
   370  // A block heap is used as a priority queue to implement the PiggyBank
   371  // from Sreedhar and Gao.  That paper uses an array which is better
   372  // asymptotically but worse in the common case when the PiggyBank
   373  // holds a sparse set of blocks.
   374  type blockHeap struct {
   375  	a     []*ssa.Block // block IDs in heap
   376  	level []int32      // depth in dominator tree (static, used for determining priority)
   377  }
   378  
   379  func (h *blockHeap) Len() int      { return len(h.a) }
   380  func (h *blockHeap) Swap(i, j int) { a := h.a; a[i], a[j] = a[j], a[i] }
   381  
   382  func (h *blockHeap) Push(x interface{}) {
   383  	v := x.(*ssa.Block)
   384  	h.a = append(h.a, v)
   385  }
   386  func (h *blockHeap) Pop() interface{} {
   387  	old := h.a
   388  	n := len(old)
   389  	x := old[n-1]
   390  	h.a = old[:n-1]
   391  	return x
   392  }
   393  func (h *blockHeap) Less(i, j int) bool {
   394  	return h.level[h.a[i].ID] > h.level[h.a[j].ID]
   395  }
   396  
   397  // TODO: stop walking the iterated domininance frontier when
   398  // the variable is dead. Maybe detect that by checking if the
   399  // node we're on is reverse dominated by all the reads?
   400  // Reverse dominated by the highest common successor of all the reads?
   401  
   402  // copy of ../ssa/sparseset.go
   403  // TODO: move this file to ../ssa, then use sparseSet there.
   404  type sparseSet struct {
   405  	dense  []ssa.ID
   406  	sparse []int32
   407  }
   408  
   409  // newSparseSet returns a sparseSet that can represent
   410  // integers between 0 and n-1
   411  func newSparseSet(n int) *sparseSet {
   412  	return &sparseSet{dense: nil, sparse: make([]int32, n)}
   413  }
   414  
   415  func (s *sparseSet) contains(x ssa.ID) bool {
   416  	i := s.sparse[x]
   417  	return i < int32(len(s.dense)) && s.dense[i] == x
   418  }
   419  
   420  func (s *sparseSet) add(x ssa.ID) {
   421  	i := s.sparse[x]
   422  	if i < int32(len(s.dense)) && s.dense[i] == x {
   423  		return
   424  	}
   425  	s.dense = append(s.dense, x)
   426  	s.sparse[x] = int32(len(s.dense)) - 1
   427  }
   428  
   429  func (s *sparseSet) clear() {
   430  	s.dense = s.dense[:0]
   431  }
   432  
   433  // Variant to use for small functions.
   434  type simplePhiState struct {
   435  	s         *state                 // SSA state
   436  	f         *ssa.Func              // function to work on
   437  	fwdrefs   []*ssa.Value           // list of FwdRefs to be processed
   438  	defvars   []map[*Node]*ssa.Value // defined variables at end of each block
   439  	reachable []bool                 // which blocks are reachable
   440  }
   441  
   442  func (s *simplePhiState) insertPhis() {
   443  	s.reachable = ssa.ReachableBlocks(s.f)
   444  
   445  	// Find FwdRef ops.
   446  	for _, b := range s.f.Blocks {
   447  		for _, v := range b.Values {
   448  			if v.Op != ssa.OpFwdRef {
   449  				continue
   450  			}
   451  			s.fwdrefs = append(s.fwdrefs, v)
   452  			var_ := v.Aux.(*Node)
   453  			if _, ok := s.defvars[b.ID][var_]; !ok {
   454  				s.defvars[b.ID][var_] = v // treat FwdDefs as definitions.
   455  			}
   456  		}
   457  	}
   458  
   459  	var args []*ssa.Value
   460  
   461  loop:
   462  	for len(s.fwdrefs) > 0 {
   463  		v := s.fwdrefs[len(s.fwdrefs)-1]
   464  		s.fwdrefs = s.fwdrefs[:len(s.fwdrefs)-1]
   465  		b := v.Block
   466  		var_ := v.Aux.(*Node)
   467  		if b == s.f.Entry {
   468  			// No variable should be live at entry.
   469  			s.s.Fatalf("Value live at entry. It shouldn't be. func %s, node %v, value %v", s.f.Name, var_, v)
   470  		}
   471  		if !s.reachable[b.ID] {
   472  			// This block is dead.
   473  			// It doesn't matter what we use here as long as it is well-formed.
   474  			v.Op = ssa.OpUnknown
   475  			v.Aux = nil
   476  			continue
   477  		}
   478  		// Find variable value on each predecessor.
   479  		args = args[:0]
   480  		for _, e := range b.Preds {
   481  			args = append(args, s.lookupVarOutgoing(e.Block(), v.Type, var_, v.Pos))
   482  		}
   483  
   484  		// Decide if we need a phi or not. We need a phi if there
   485  		// are two different args (which are both not v).
   486  		var w *ssa.Value
   487  		for _, a := range args {
   488  			if a == v {
   489  				continue // self-reference
   490  			}
   491  			if a == w {
   492  				continue // already have this witness
   493  			}
   494  			if w != nil {
   495  				// two witnesses, need a phi value
   496  				v.Op = ssa.OpPhi
   497  				v.AddArgs(args...)
   498  				v.Aux = nil
   499  				continue loop
   500  			}
   501  			w = a // save witness
   502  		}
   503  		if w == nil {
   504  			s.s.Fatalf("no witness for reachable phi %s", v)
   505  		}
   506  		// One witness. Make v a copy of w.
   507  		v.Op = ssa.OpCopy
   508  		v.Aux = nil
   509  		v.AddArg(w)
   510  	}
   511  }
   512  
   513  // lookupVarOutgoing finds the variable's value at the end of block b.
   514  func (s *simplePhiState) lookupVarOutgoing(b *ssa.Block, t *types.Type, var_ *Node, line src.XPos) *ssa.Value {
   515  	for {
   516  		if v := s.defvars[b.ID][var_]; v != nil {
   517  			return v
   518  		}
   519  		// The variable is not defined by b and we haven't looked it up yet.
   520  		// If b has exactly one predecessor, loop to look it up there.
   521  		// Otherwise, give up and insert a new FwdRef and resolve it later.
   522  		if len(b.Preds) != 1 {
   523  			break
   524  		}
   525  		b = b.Preds[0].Block()
   526  		if !s.reachable[b.ID] {
   527  			// This is rare; it happens with oddly interleaved infinite loops in dead code.
   528  			// See issue 19783.
   529  			break
   530  		}
   531  	}
   532  	// Generate a FwdRef for the variable and return that.
   533  	v := b.NewValue0A(line, ssa.OpFwdRef, t, var_)
   534  	s.defvars[b.ID][var_] = v
   535  	s.s.addNamedValue(var_, v)
   536  	s.fwdrefs = append(s.fwdrefs, v)
   537  	return v
   538  }