Home | History | Annotate | Download | only in ssa
      1 // Copyright 2015 The Go Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style
      3 // license that can be found in the LICENSE file.
      4 
      5 package ssa
      6 
      7 import (
      8 	"fmt"
      9 	"sort"
     10 )
     11 
     12 // cse does common-subexpression elimination on the Function.
     13 // Values are just relinked, nothing is deleted. A subsequent deadcode
     14 // pass is required to actually remove duplicate expressions.
     15 func cse(f *Func) {
     16 	// Two values are equivalent if they satisfy the following definition:
     17 	// equivalent(v, w):
     18 	//   v.op == w.op
     19 	//   v.type == w.type
     20 	//   v.aux == w.aux
     21 	//   v.auxint == w.auxint
     22 	//   len(v.args) == len(w.args)
     23 	//   v.block == w.block if v.op == OpPhi
     24 	//   equivalent(v.args[i], w.args[i]) for i in 0..len(v.args)-1
     25 
     26 	// The algorithm searches for a partition of f's values into
     27 	// equivalence classes using the above definition.
     28 	// It starts with a coarse partition and iteratively refines it
     29 	// until it reaches a fixed point.
     30 
     31 	// Make initial coarse partitions by using a subset of the conditions above.
     32 	a := make([]*Value, 0, f.NumValues())
     33 	auxIDs := auxmap{}
     34 	for _, b := range f.Blocks {
     35 		for _, v := range b.Values {
     36 			if auxIDs[v.Aux] == 0 {
     37 				auxIDs[v.Aux] = int32(len(auxIDs)) + 1
     38 			}
     39 			if v.Type.IsMemory() {
     40 				continue // memory values can never cse
     41 			}
     42 			if opcodeTable[v.Op].commutative && len(v.Args) == 2 && v.Args[1].ID < v.Args[0].ID {
     43 				// Order the arguments of binary commutative operations.
     44 				v.Args[0], v.Args[1] = v.Args[1], v.Args[0]
     45 			}
     46 			a = append(a, v)
     47 		}
     48 	}
     49 	partition := partitionValues(a, auxIDs)
     50 
     51 	// map from value id back to eqclass id
     52 	valueEqClass := make([]ID, f.NumValues())
     53 	for _, b := range f.Blocks {
     54 		for _, v := range b.Values {
     55 			// Use negative equivalence class #s for unique values.
     56 			valueEqClass[v.ID] = -v.ID
     57 		}
     58 	}
     59 	var pNum ID = 1
     60 	for _, e := range partition {
     61 		if f.pass.debug > 1 && len(e) > 500 {
     62 			fmt.Printf("CSE.large partition (%d): ", len(e))
     63 			for j := 0; j < 3; j++ {
     64 				fmt.Printf("%s ", e[j].LongString())
     65 			}
     66 			fmt.Println()
     67 		}
     68 
     69 		for _, v := range e {
     70 			valueEqClass[v.ID] = pNum
     71 		}
     72 		if f.pass.debug > 2 && len(e) > 1 {
     73 			fmt.Printf("CSE.partition #%d:", pNum)
     74 			for _, v := range e {
     75 				fmt.Printf(" %s", v.String())
     76 			}
     77 			fmt.Printf("\n")
     78 		}
     79 		pNum++
     80 	}
     81 
     82 	// Split equivalence classes at points where they have
     83 	// non-equivalent arguments.  Repeat until we can't find any
     84 	// more splits.
     85 	var splitPoints []int
     86 	byArgClass := new(partitionByArgClass) // reuseable partitionByArgClass to reduce allocations
     87 	for {
     88 		changed := false
     89 
     90 		// partition can grow in the loop. By not using a range loop here,
     91 		// we process new additions as they arrive, avoiding O(n^2) behavior.
     92 		for i := 0; i < len(partition); i++ {
     93 			e := partition[i]
     94 
     95 			// Sort by eq class of arguments.
     96 			byArgClass.a = e
     97 			byArgClass.eqClass = valueEqClass
     98 			sort.Sort(byArgClass)
     99 
    100 			// Find split points.
    101 			splitPoints = append(splitPoints[:0], 0)
    102 			for j := 1; j < len(e); j++ {
    103 				v, w := e[j-1], e[j]
    104 				eqArgs := true
    105 				for k, a := range v.Args {
    106 					b := w.Args[k]
    107 					if valueEqClass[a.ID] != valueEqClass[b.ID] {
    108 						eqArgs = false
    109 						break
    110 					}
    111 				}
    112 				if !eqArgs {
    113 					splitPoints = append(splitPoints, j)
    114 				}
    115 			}
    116 			if len(splitPoints) == 1 {
    117 				continue // no splits, leave equivalence class alone.
    118 			}
    119 
    120 			// Move another equivalence class down in place of e.
    121 			partition[i] = partition[len(partition)-1]
    122 			partition = partition[:len(partition)-1]
    123 			i--
    124 
    125 			// Add new equivalence classes for the parts of e we found.
    126 			splitPoints = append(splitPoints, len(e))
    127 			for j := 0; j < len(splitPoints)-1; j++ {
    128 				f := e[splitPoints[j]:splitPoints[j+1]]
    129 				if len(f) == 1 {
    130 					// Don't add singletons.
    131 					valueEqClass[f[0].ID] = -f[0].ID
    132 					continue
    133 				}
    134 				for _, v := range f {
    135 					valueEqClass[v.ID] = pNum
    136 				}
    137 				pNum++
    138 				partition = append(partition, f)
    139 			}
    140 			changed = true
    141 		}
    142 
    143 		if !changed {
    144 			break
    145 		}
    146 	}
    147 
    148 	sdom := f.sdom()
    149 
    150 	// Compute substitutions we would like to do. We substitute v for w
    151 	// if v and w are in the same equivalence class and v dominates w.
    152 	rewrite := make([]*Value, f.NumValues())
    153 	byDom := new(partitionByDom) // reusable partitionByDom to reduce allocs
    154 	for _, e := range partition {
    155 		byDom.a = e
    156 		byDom.sdom = sdom
    157 		sort.Sort(byDom)
    158 		for i := 0; i < len(e)-1; i++ {
    159 			// e is sorted by domorder, so a maximal dominant element is first in the slice
    160 			v := e[i]
    161 			if v == nil {
    162 				continue
    163 			}
    164 
    165 			e[i] = nil
    166 			// Replace all elements of e which v dominates
    167 			for j := i + 1; j < len(e); j++ {
    168 				w := e[j]
    169 				if w == nil {
    170 					continue
    171 				}
    172 				if sdom.isAncestorEq(v.Block, w.Block) {
    173 					rewrite[w.ID] = v
    174 					e[j] = nil
    175 				} else {
    176 					// e is sorted by domorder, so v.Block doesn't dominate any subsequent blocks in e
    177 					break
    178 				}
    179 			}
    180 		}
    181 	}
    182 
    183 	// if we rewrite a tuple generator to a new one in a different block,
    184 	// copy its selectors to the new generator's block, so tuple generator
    185 	// and selectors stay together.
    186 	// be careful not to copy same selectors more than once (issue 16741).
    187 	copiedSelects := make(map[ID][]*Value)
    188 	for _, b := range f.Blocks {
    189 	out:
    190 		for _, v := range b.Values {
    191 			// New values are created when selectors are copied to
    192 			// a new block. We can safely ignore those new values,
    193 			// since they have already been copied (issue 17918).
    194 			if int(v.ID) >= len(rewrite) || rewrite[v.ID] != nil {
    195 				continue
    196 			}
    197 			if v.Op != OpSelect0 && v.Op != OpSelect1 {
    198 				continue
    199 			}
    200 			if !v.Args[0].Type.IsTuple() {
    201 				f.Fatalf("arg of tuple selector %s is not a tuple: %s", v.String(), v.Args[0].LongString())
    202 			}
    203 			t := rewrite[v.Args[0].ID]
    204 			if t != nil && t.Block != b {
    205 				// v.Args[0] is tuple generator, CSE'd into a different block as t, v is left behind
    206 				for _, c := range copiedSelects[t.ID] {
    207 					if v.Op == c.Op {
    208 						// an equivalent selector is already copied
    209 						rewrite[v.ID] = c
    210 						continue out
    211 					}
    212 				}
    213 				c := v.copyInto(t.Block)
    214 				rewrite[v.ID] = c
    215 				copiedSelects[t.ID] = append(copiedSelects[t.ID], c)
    216 			}
    217 		}
    218 	}
    219 
    220 	rewrites := int64(0)
    221 
    222 	// Apply substitutions
    223 	for _, b := range f.Blocks {
    224 		for _, v := range b.Values {
    225 			for i, w := range v.Args {
    226 				if x := rewrite[w.ID]; x != nil {
    227 					v.SetArg(i, x)
    228 					rewrites++
    229 				}
    230 			}
    231 		}
    232 		if v := b.Control; v != nil {
    233 			if x := rewrite[v.ID]; x != nil {
    234 				if v.Op == OpNilCheck {
    235 					// nilcheck pass will remove the nil checks and log
    236 					// them appropriately, so don't mess with them here.
    237 					continue
    238 				}
    239 				b.SetControl(x)
    240 			}
    241 		}
    242 	}
    243 	if f.pass.stats > 0 {
    244 		f.LogStat("CSE REWRITES", rewrites)
    245 	}
    246 }
    247 
    248 // An eqclass approximates an equivalence class. During the
    249 // algorithm it may represent the union of several of the
    250 // final equivalence classes.
    251 type eqclass []*Value
    252 
    253 // partitionValues partitions the values into equivalence classes
    254 // based on having all the following features match:
    255 //  - opcode
    256 //  - type
    257 //  - auxint
    258 //  - aux
    259 //  - nargs
    260 //  - block # if a phi op
    261 //  - first two arg's opcodes and auxint
    262 //  - NOT first two arg's aux; that can break CSE.
    263 // partitionValues returns a list of equivalence classes, each
    264 // being a sorted by ID list of *Values. The eqclass slices are
    265 // backed by the same storage as the input slice.
    266 // Equivalence classes of size 1 are ignored.
    267 func partitionValues(a []*Value, auxIDs auxmap) []eqclass {
    268 	sort.Sort(sortvalues{a, auxIDs})
    269 
    270 	var partition []eqclass
    271 	for len(a) > 0 {
    272 		v := a[0]
    273 		j := 1
    274 		for ; j < len(a); j++ {
    275 			w := a[j]
    276 			if cmpVal(v, w, auxIDs) != CMPeq {
    277 				break
    278 			}
    279 		}
    280 		if j > 1 {
    281 			partition = append(partition, a[:j])
    282 		}
    283 		a = a[j:]
    284 	}
    285 
    286 	return partition
    287 }
    288 func lt2Cmp(isLt bool) Cmp {
    289 	if isLt {
    290 		return CMPlt
    291 	}
    292 	return CMPgt
    293 }
    294 
    295 type auxmap map[interface{}]int32
    296 
    297 func cmpVal(v, w *Value, auxIDs auxmap) Cmp {
    298 	// Try to order these comparison by cost (cheaper first)
    299 	if v.Op != w.Op {
    300 		return lt2Cmp(v.Op < w.Op)
    301 	}
    302 	if v.AuxInt != w.AuxInt {
    303 		return lt2Cmp(v.AuxInt < w.AuxInt)
    304 	}
    305 	if len(v.Args) != len(w.Args) {
    306 		return lt2Cmp(len(v.Args) < len(w.Args))
    307 	}
    308 	if v.Op == OpPhi && v.Block != w.Block {
    309 		return lt2Cmp(v.Block.ID < w.Block.ID)
    310 	}
    311 	if v.Type.IsMemory() {
    312 		// We will never be able to CSE two values
    313 		// that generate memory.
    314 		return lt2Cmp(v.ID < w.ID)
    315 	}
    316 
    317 	if tc := v.Type.Compare(w.Type); tc != CMPeq {
    318 		return tc
    319 	}
    320 
    321 	if v.Aux != w.Aux {
    322 		if v.Aux == nil {
    323 			return CMPlt
    324 		}
    325 		if w.Aux == nil {
    326 			return CMPgt
    327 		}
    328 		return lt2Cmp(auxIDs[v.Aux] < auxIDs[w.Aux])
    329 	}
    330 
    331 	return CMPeq
    332 }
    333 
    334 // Sort values to make the initial partition.
    335 type sortvalues struct {
    336 	a      []*Value // array of values
    337 	auxIDs auxmap   // aux -> aux ID map
    338 }
    339 
    340 func (sv sortvalues) Len() int      { return len(sv.a) }
    341 func (sv sortvalues) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
    342 func (sv sortvalues) Less(i, j int) bool {
    343 	v := sv.a[i]
    344 	w := sv.a[j]
    345 	if cmp := cmpVal(v, w, sv.auxIDs); cmp != CMPeq {
    346 		return cmp == CMPlt
    347 	}
    348 
    349 	// Sort by value ID last to keep the sort result deterministic.
    350 	return v.ID < w.ID
    351 }
    352 
    353 type partitionByDom struct {
    354 	a    []*Value // array of values
    355 	sdom SparseTree
    356 }
    357 
    358 func (sv partitionByDom) Len() int      { return len(sv.a) }
    359 func (sv partitionByDom) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
    360 func (sv partitionByDom) Less(i, j int) bool {
    361 	v := sv.a[i]
    362 	w := sv.a[j]
    363 	return sv.sdom.domorder(v.Block) < sv.sdom.domorder(w.Block)
    364 }
    365 
    366 type partitionByArgClass struct {
    367 	a       []*Value // array of values
    368 	eqClass []ID     // equivalence class IDs of values
    369 }
    370 
    371 func (sv partitionByArgClass) Len() int      { return len(sv.a) }
    372 func (sv partitionByArgClass) Swap(i, j int) { sv.a[i], sv.a[j] = sv.a[j], sv.a[i] }
    373 func (sv partitionByArgClass) Less(i, j int) bool {
    374 	v := sv.a[i]
    375 	w := sv.a[j]
    376 	for i, a := range v.Args {
    377 		b := w.Args[i]
    378 		if sv.eqClass[a.ID] < sv.eqClass[b.ID] {
    379 			return true
    380 		}
    381 		if sv.eqClass[a.ID] > sv.eqClass[b.ID] {
    382 			return false
    383 		}
    384 	}
    385 	return false
    386 }
    387