github.com/gagliardetto/golang-go@v0.0.0-20201020153340-53909ea70814/cmd/compile/internal/ssa/zcse.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 ssa
     6  
     7  import "github.com/gagliardetto/golang-go/cmd/compile/internal/types"
     8  
     9  // zcse does an initial pass of common-subexpression elimination on the
    10  // function for values with zero arguments to allow the more expensive cse
    11  // to begin with a reduced number of values. Values are just relinked,
    12  // nothing is deleted. A subsequent deadcode pass is required to actually
    13  // remove duplicate expressions.
    14  func zcse(f *Func) {
    15  	vals := make(map[vkey]*Value)
    16  
    17  	for _, b := range f.Blocks {
    18  		for i := 0; i < len(b.Values); {
    19  			v := b.Values[i]
    20  			next := true
    21  			if opcodeTable[v.Op].argLen == 0 {
    22  				key := vkey{v.Op, keyFor(v), v.Aux, v.Type}
    23  				if vals[key] == nil {
    24  					vals[key] = v
    25  					if b != f.Entry {
    26  						// Move v to the entry block so it will dominate every block
    27  						// where we might use it. This prevents the need for any dominator
    28  						// calculations in this pass.
    29  						v.Block = f.Entry
    30  						f.Entry.Values = append(f.Entry.Values, v)
    31  						last := len(b.Values) - 1
    32  						b.Values[i] = b.Values[last]
    33  						b.Values[last] = nil
    34  						b.Values = b.Values[:last]
    35  
    36  						// process b.Values[i] again
    37  						next = false
    38  					}
    39  				}
    40  			}
    41  			if next {
    42  				i++
    43  			}
    44  		}
    45  	}
    46  
    47  	for _, b := range f.Blocks {
    48  		for _, v := range b.Values {
    49  			for i, a := range v.Args {
    50  				if opcodeTable[a.Op].argLen == 0 {
    51  					key := vkey{a.Op, keyFor(a), a.Aux, a.Type}
    52  					if rv, ok := vals[key]; ok {
    53  						v.SetArg(i, rv)
    54  					}
    55  				}
    56  			}
    57  		}
    58  	}
    59  }
    60  
    61  // vkey is a type used to uniquely identify a zero arg value.
    62  type vkey struct {
    63  	op Op
    64  	ai int64       // aux int
    65  	ax interface{} // aux
    66  	t  *types.Type // type
    67  }
    68  
    69  // keyFor returns the AuxInt portion of a  key structure uniquely identifying a
    70  // zero arg value for the supported ops.
    71  func keyFor(v *Value) int64 {
    72  	switch v.Op {
    73  	case OpConst64, OpConst64F, OpConst32F:
    74  		return v.AuxInt
    75  	case OpConst32:
    76  		return int64(int32(v.AuxInt))
    77  	case OpConst16:
    78  		return int64(int16(v.AuxInt))
    79  	case OpConst8, OpConstBool:
    80  		return int64(int8(v.AuxInt))
    81  	default:
    82  		return v.AuxInt
    83  	}
    84  }