github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/compile/internal/ssa/rewrite.go (about)

     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  	"cmd/compile/internal/types"
     9  	"cmd/internal/obj"
    10  	"fmt"
    11  	"io"
    12  	"math"
    13  	"os"
    14  	"path/filepath"
    15  )
    16  
    17  func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter) {
    18  	// repeat rewrites until we find no more rewrites
    19  	for {
    20  		change := false
    21  		for _, b := range f.Blocks {
    22  			if b.Control != nil && b.Control.Op == OpCopy {
    23  				for b.Control.Op == OpCopy {
    24  					b.SetControl(b.Control.Args[0])
    25  				}
    26  			}
    27  			if rb(b) {
    28  				change = true
    29  			}
    30  			for _, v := range b.Values {
    31  				change = phielimValue(v) || change
    32  
    33  				// Eliminate copy inputs.
    34  				// If any copy input becomes unused, mark it
    35  				// as invalid and discard its argument. Repeat
    36  				// recursively on the discarded argument.
    37  				// This phase helps remove phantom "dead copy" uses
    38  				// of a value so that a x.Uses==1 rule condition
    39  				// fires reliably.
    40  				for i, a := range v.Args {
    41  					if a.Op != OpCopy {
    42  						continue
    43  					}
    44  					v.SetArg(i, copySource(a))
    45  					change = true
    46  					for a.Uses == 0 {
    47  						b := a.Args[0]
    48  						a.reset(OpInvalid)
    49  						a = b
    50  					}
    51  				}
    52  
    53  				// apply rewrite function
    54  				if rv(v) {
    55  					change = true
    56  				}
    57  			}
    58  		}
    59  		if !change {
    60  			break
    61  		}
    62  	}
    63  	// remove clobbered values
    64  	for _, b := range f.Blocks {
    65  		j := 0
    66  		for i, v := range b.Values {
    67  			if v.Op == OpInvalid {
    68  				f.freeValue(v)
    69  				continue
    70  			}
    71  			if i != j {
    72  				b.Values[j] = v
    73  			}
    74  			j++
    75  		}
    76  		if j != len(b.Values) {
    77  			tail := b.Values[j:]
    78  			for j := range tail {
    79  				tail[j] = nil
    80  			}
    81  			b.Values = b.Values[:j]
    82  		}
    83  	}
    84  }
    85  
    86  // Common functions called from rewriting rules
    87  
    88  func is64BitFloat(t *types.Type) bool {
    89  	return t.Size() == 8 && t.IsFloat()
    90  }
    91  
    92  func is32BitFloat(t *types.Type) bool {
    93  	return t.Size() == 4 && t.IsFloat()
    94  }
    95  
    96  func is64BitInt(t *types.Type) bool {
    97  	return t.Size() == 8 && t.IsInteger()
    98  }
    99  
   100  func is32BitInt(t *types.Type) bool {
   101  	return t.Size() == 4 && t.IsInteger()
   102  }
   103  
   104  func is16BitInt(t *types.Type) bool {
   105  	return t.Size() == 2 && t.IsInteger()
   106  }
   107  
   108  func is8BitInt(t *types.Type) bool {
   109  	return t.Size() == 1 && t.IsInteger()
   110  }
   111  
   112  func isPtr(t *types.Type) bool {
   113  	return t.IsPtrShaped()
   114  }
   115  
   116  func isSigned(t *types.Type) bool {
   117  	return t.IsSigned()
   118  }
   119  
   120  func typeSize(t *types.Type) int64 {
   121  	return t.Size()
   122  }
   123  
   124  // mergeSym merges two symbolic offsets. There is no real merging of
   125  // offsets, we just pick the non-nil one.
   126  func mergeSym(x, y interface{}) interface{} {
   127  	if x == nil {
   128  		return y
   129  	}
   130  	if y == nil {
   131  		return x
   132  	}
   133  	panic(fmt.Sprintf("mergeSym with two non-nil syms %s %s", x, y))
   134  }
   135  func canMergeSym(x, y interface{}) bool {
   136  	return x == nil || y == nil
   137  }
   138  
   139  // canMergeLoad reports whether the load can be merged into target without
   140  // invalidating the schedule.
   141  // It also checks that the other non-load argument x is something we
   142  // are ok with clobbering (all our current load+op instructions clobber
   143  // their input register).
   144  func canMergeLoad(target, load, x *Value) bool {
   145  	if target.Block.ID != load.Block.ID {
   146  		// If the load is in a different block do not merge it.
   147  		return false
   148  	}
   149  
   150  	// We can't merge the load into the target if the load
   151  	// has more than one use.
   152  	if load.Uses != 1 {
   153  		return false
   154  	}
   155  
   156  	// The register containing x is going to get clobbered.
   157  	// Don't merge if we still need the value of x.
   158  	// We don't have liveness information here, but we can
   159  	// approximate x dying with:
   160  	//  1) target is x's only use.
   161  	//  2) target is not in a deeper loop than x.
   162  	if x.Uses != 1 {
   163  		return false
   164  	}
   165  	loopnest := x.Block.Func.loopnest()
   166  	loopnest.calculateDepths()
   167  	if loopnest.depth(target.Block.ID) > loopnest.depth(x.Block.ID) {
   168  		return false
   169  	}
   170  
   171  	mem := load.MemoryArg()
   172  
   173  	// We need the load's memory arg to still be alive at target. That
   174  	// can't be the case if one of target's args depends on a memory
   175  	// state that is a successor of load's memory arg.
   176  	//
   177  	// For example, it would be invalid to merge load into target in
   178  	// the following situation because newmem has killed oldmem
   179  	// before target is reached:
   180  	//     load = read ... oldmem
   181  	//   newmem = write ... oldmem
   182  	//     arg0 = read ... newmem
   183  	//   target = add arg0 load
   184  	//
   185  	// If the argument comes from a different block then we can exclude
   186  	// it immediately because it must dominate load (which is in the
   187  	// same block as target).
   188  	var args []*Value
   189  	for _, a := range target.Args {
   190  		if a != load && a.Block.ID == target.Block.ID {
   191  			args = append(args, a)
   192  		}
   193  	}
   194  
   195  	// memPreds contains memory states known to be predecessors of load's
   196  	// memory state. It is lazily initialized.
   197  	var memPreds map[*Value]bool
   198  search:
   199  	for i := 0; len(args) > 0; i++ {
   200  		const limit = 100
   201  		if i >= limit {
   202  			// Give up if we have done a lot of iterations.
   203  			return false
   204  		}
   205  		v := args[len(args)-1]
   206  		args = args[:len(args)-1]
   207  		if target.Block.ID != v.Block.ID {
   208  			// Since target and load are in the same block
   209  			// we can stop searching when we leave the block.
   210  			continue search
   211  		}
   212  		if v.Op == OpPhi {
   213  			// A Phi implies we have reached the top of the block.
   214  			// The memory phi, if it exists, is always
   215  			// the first logical store in the block.
   216  			continue search
   217  		}
   218  		if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
   219  			// We could handle this situation however it is likely
   220  			// to be very rare.
   221  			return false
   222  		}
   223  		if v.Type.IsMemory() {
   224  			if memPreds == nil {
   225  				// Initialise a map containing memory states
   226  				// known to be predecessors of load's memory
   227  				// state.
   228  				memPreds = make(map[*Value]bool)
   229  				m := mem
   230  				const limit = 50
   231  				for i := 0; i < limit; i++ {
   232  					if m.Op == OpPhi {
   233  						// The memory phi, if it exists, is always
   234  						// the first logical store in the block.
   235  						break
   236  					}
   237  					if m.Block.ID != target.Block.ID {
   238  						break
   239  					}
   240  					if !m.Type.IsMemory() {
   241  						break
   242  					}
   243  					memPreds[m] = true
   244  					if len(m.Args) == 0 {
   245  						break
   246  					}
   247  					m = m.MemoryArg()
   248  				}
   249  			}
   250  
   251  			// We can merge if v is a predecessor of mem.
   252  			//
   253  			// For example, we can merge load into target in the
   254  			// following scenario:
   255  			//      x = read ... v
   256  			//    mem = write ... v
   257  			//   load = read ... mem
   258  			// target = add x load
   259  			if memPreds[v] {
   260  				continue search
   261  			}
   262  			return false
   263  		}
   264  		if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem {
   265  			// If v takes mem as an input then we know mem
   266  			// is valid at this point.
   267  			continue search
   268  		}
   269  		for _, a := range v.Args {
   270  			if target.Block.ID == a.Block.ID {
   271  				args = append(args, a)
   272  			}
   273  		}
   274  	}
   275  
   276  	return true
   277  }
   278  
   279  // isSameSym returns whether sym is the same as the given named symbol
   280  func isSameSym(sym interface{}, name string) bool {
   281  	s, ok := sym.(fmt.Stringer)
   282  	return ok && s.String() == name
   283  }
   284  
   285  // nlz returns the number of leading zeros.
   286  func nlz(x int64) int64 {
   287  	// log2(0) == 1, so nlz(0) == 64
   288  	return 63 - log2(x)
   289  }
   290  
   291  // ntz returns the number of trailing zeros.
   292  func ntz(x int64) int64 {
   293  	return 64 - nlz(^x&(x-1))
   294  }
   295  
   296  func oneBit(x int64) bool {
   297  	return nlz(x)+ntz(x) == 63
   298  }
   299  
   300  // nlo returns the number of leading ones.
   301  func nlo(x int64) int64 {
   302  	return nlz(^x)
   303  }
   304  
   305  // nto returns the number of trailing ones.
   306  func nto(x int64) int64 {
   307  	return ntz(^x)
   308  }
   309  
   310  // log2 returns logarithm in base 2 of uint64(n), with log2(0) = -1.
   311  // Rounds down.
   312  func log2(n int64) (l int64) {
   313  	l = -1
   314  	x := uint64(n)
   315  	for ; x >= 0x8000; x >>= 16 {
   316  		l += 16
   317  	}
   318  	if x >= 0x80 {
   319  		x >>= 8
   320  		l += 8
   321  	}
   322  	if x >= 0x8 {
   323  		x >>= 4
   324  		l += 4
   325  	}
   326  	if x >= 0x2 {
   327  		x >>= 2
   328  		l += 2
   329  	}
   330  	if x >= 0x1 {
   331  		l++
   332  	}
   333  	return
   334  }
   335  
   336  // isPowerOfTwo reports whether n is a power of 2.
   337  func isPowerOfTwo(n int64) bool {
   338  	return n > 0 && n&(n-1) == 0
   339  }
   340  
   341  // is32Bit reports whether n can be represented as a signed 32 bit integer.
   342  func is32Bit(n int64) bool {
   343  	return n == int64(int32(n))
   344  }
   345  
   346  // is16Bit reports whether n can be represented as a signed 16 bit integer.
   347  func is16Bit(n int64) bool {
   348  	return n == int64(int16(n))
   349  }
   350  
   351  // isU12Bit reports whether n can be represented as an unsigned 12 bit integer.
   352  func isU12Bit(n int64) bool {
   353  	return 0 <= n && n < (1<<12)
   354  }
   355  
   356  // isU16Bit reports whether n can be represented as an unsigned 16 bit integer.
   357  func isU16Bit(n int64) bool {
   358  	return n == int64(uint16(n))
   359  }
   360  
   361  // isU32Bit reports whether n can be represented as an unsigned 32 bit integer.
   362  func isU32Bit(n int64) bool {
   363  	return n == int64(uint32(n))
   364  }
   365  
   366  // is20Bit reports whether n can be represented as a signed 20 bit integer.
   367  func is20Bit(n int64) bool {
   368  	return -(1<<19) <= n && n < (1<<19)
   369  }
   370  
   371  // b2i translates a boolean value to 0 or 1 for assigning to auxInt.
   372  func b2i(b bool) int64 {
   373  	if b {
   374  		return 1
   375  	}
   376  	return 0
   377  }
   378  
   379  // i2f is used in rules for converting from an AuxInt to a float.
   380  func i2f(i int64) float64 {
   381  	return math.Float64frombits(uint64(i))
   382  }
   383  
   384  // i2f32 is used in rules for converting from an AuxInt to a float32.
   385  func i2f32(i int64) float32 {
   386  	return float32(math.Float64frombits(uint64(i)))
   387  }
   388  
   389  // f2i is used in the rules for storing a float in AuxInt.
   390  func f2i(f float64) int64 {
   391  	return int64(math.Float64bits(f))
   392  }
   393  
   394  // uaddOvf returns true if unsigned a+b would overflow.
   395  func uaddOvf(a, b int64) bool {
   396  	return uint64(a)+uint64(b) < uint64(a)
   397  }
   398  
   399  // de-virtualize an InterCall
   400  // 'sym' is the symbol for the itab
   401  func devirt(v *Value, sym interface{}, offset int64) *obj.LSym {
   402  	f := v.Block.Func
   403  	n, ok := sym.(*obj.LSym)
   404  	if !ok {
   405  		return nil
   406  	}
   407  	lsym := f.fe.DerefItab(n, offset)
   408  	if f.pass.debug > 0 {
   409  		if lsym != nil {
   410  			f.Warnl(v.Pos, "de-virtualizing call")
   411  		} else {
   412  			f.Warnl(v.Pos, "couldn't de-virtualize call")
   413  		}
   414  	}
   415  	return lsym
   416  }
   417  
   418  // isSamePtr reports whether p1 and p2 point to the same address.
   419  func isSamePtr(p1, p2 *Value) bool {
   420  	if p1 == p2 {
   421  		return true
   422  	}
   423  	if p1.Op != p2.Op {
   424  		return false
   425  	}
   426  	switch p1.Op {
   427  	case OpOffPtr:
   428  		return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
   429  	case OpAddr:
   430  		// OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op.
   431  		// Checking for value equality only works after [z]cse has run.
   432  		return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op
   433  	case OpAddPtr:
   434  		return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0])
   435  	}
   436  	return false
   437  }
   438  
   439  // moveSize returns the number of bytes an aligned MOV instruction moves
   440  func moveSize(align int64, c *Config) int64 {
   441  	switch {
   442  	case align%8 == 0 && c.PtrSize == 8:
   443  		return 8
   444  	case align%4 == 0:
   445  		return 4
   446  	case align%2 == 0:
   447  		return 2
   448  	}
   449  	return 1
   450  }
   451  
   452  // mergePoint finds a block among a's blocks which dominates b and is itself
   453  // dominated by all of a's blocks. Returns nil if it can't find one.
   454  // Might return nil even if one does exist.
   455  func mergePoint(b *Block, a ...*Value) *Block {
   456  	// Walk backward from b looking for one of the a's blocks.
   457  
   458  	// Max distance
   459  	d := 100
   460  
   461  	for d > 0 {
   462  		for _, x := range a {
   463  			if b == x.Block {
   464  				goto found
   465  			}
   466  		}
   467  		if len(b.Preds) > 1 {
   468  			// Don't know which way to go back. Abort.
   469  			return nil
   470  		}
   471  		b = b.Preds[0].b
   472  		d--
   473  	}
   474  	return nil // too far away
   475  found:
   476  	// At this point, r is the first value in a that we find by walking backwards.
   477  	// if we return anything, r will be it.
   478  	r := b
   479  
   480  	// Keep going, counting the other a's that we find. They must all dominate r.
   481  	na := 0
   482  	for d > 0 {
   483  		for _, x := range a {
   484  			if b == x.Block {
   485  				na++
   486  			}
   487  		}
   488  		if na == len(a) {
   489  			// Found all of a in a backwards walk. We can return r.
   490  			return r
   491  		}
   492  		if len(b.Preds) > 1 {
   493  			return nil
   494  		}
   495  		b = b.Preds[0].b
   496  		d--
   497  
   498  	}
   499  	return nil // too far away
   500  }
   501  
   502  // clobber invalidates v.  Returns true.
   503  // clobber is used by rewrite rules to:
   504  //   A) make sure v is really dead and never used again.
   505  //   B) decrement use counts of v's args.
   506  func clobber(v *Value) bool {
   507  	v.reset(OpInvalid)
   508  	// Note: leave v.Block intact.  The Block field is used after clobber.
   509  	return true
   510  }
   511  
   512  // noteRule is an easy way to track if a rule is matched when writing
   513  // new ones.  Make the rule of interest also conditional on
   514  //     noteRule("note to self: rule of interest matched")
   515  // and that message will print when the rule matches.
   516  func noteRule(s string) bool {
   517  	fmt.Println(s)
   518  	return true
   519  }
   520  
   521  // warnRule generates a compiler debug output with string s when
   522  // cond is true and the rule is fired.
   523  func warnRule(cond bool, v *Value, s string) bool {
   524  	if cond {
   525  		v.Block.Func.Warnl(v.Pos, s)
   526  	}
   527  	return true
   528  }
   529  
   530  // logRule logs the use of the rule s. This will only be enabled if
   531  // rewrite rules were generated with the -log option, see gen/rulegen.go.
   532  func logRule(s string) {
   533  	if ruleFile == nil {
   534  		// Open a log file to write log to. We open in append
   535  		// mode because all.bash runs the compiler lots of times,
   536  		// and we want the concatenation of all of those logs.
   537  		// This means, of course, that users need to rm the old log
   538  		// to get fresh data.
   539  		// TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow?
   540  		w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
   541  			os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
   542  		if err != nil {
   543  			panic(err)
   544  		}
   545  		ruleFile = w
   546  	}
   547  	_, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s)
   548  	if err != nil {
   549  		panic(err)
   550  	}
   551  }
   552  
   553  var ruleFile io.Writer
   554  
   555  func min(x, y int64) int64 {
   556  	if x < y {
   557  		return x
   558  	}
   559  	return y
   560  }
   561  
   562  func isConstZero(v *Value) bool {
   563  	switch v.Op {
   564  	case OpConstNil:
   565  		return true
   566  	case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConst32F, OpConst64F:
   567  		return v.AuxInt == 0
   568  	}
   569  	return false
   570  }
   571  
   572  // reciprocalExact64 reports whether 1/c is exactly representable.
   573  func reciprocalExact64(c float64) bool {
   574  	b := math.Float64bits(c)
   575  	man := b & (1<<52 - 1)
   576  	if man != 0 {
   577  		return false // not a power of 2, denormal, or NaN
   578  	}
   579  	exp := b >> 52 & (1<<11 - 1)
   580  	// exponent bias is 0x3ff.  So taking the reciprocal of a number
   581  	// changes the exponent to 0x7fe-exp.
   582  	switch exp {
   583  	case 0:
   584  		return false // ±0
   585  	case 0x7ff:
   586  		return false // ±inf
   587  	case 0x7fe:
   588  		return false // exponent is not representable
   589  	default:
   590  		return true
   591  	}
   592  }
   593  
   594  // reciprocalExact32 reports whether 1/c is exactly representable.
   595  func reciprocalExact32(c float32) bool {
   596  	b := math.Float32bits(c)
   597  	man := b & (1<<23 - 1)
   598  	if man != 0 {
   599  		return false // not a power of 2, denormal, or NaN
   600  	}
   601  	exp := b >> 23 & (1<<8 - 1)
   602  	// exponent bias is 0x7f.  So taking the reciprocal of a number
   603  	// changes the exponent to 0xfe-exp.
   604  	switch exp {
   605  	case 0:
   606  		return false // ±0
   607  	case 0xff:
   608  		return false // ±inf
   609  	case 0xfe:
   610  		return false // exponent is not representable
   611  	default:
   612  		return true
   613  	}
   614  }
   615  
   616  // check if an immediate can be directly encoded into an ARM's instruction
   617  func isARMImmRot(v uint32) bool {
   618  	for i := 0; i < 16; i++ {
   619  		if v&^0xff == 0 {
   620  			return true
   621  		}
   622  		v = v<<2 | v>>30
   623  	}
   624  
   625  	return false
   626  }
   627  
   628  // overlap reports whether the ranges given by the given offset and
   629  // size pairs overlap.
   630  func overlap(offset1, size1, offset2, size2 int64) bool {
   631  	if offset1 >= offset2 && offset2+size2 > offset1 {
   632  		return true
   633  	}
   634  	if offset2 >= offset1 && offset1+size1 > offset2 {
   635  		return true
   636  	}
   637  	return false
   638  }
   639  
   640  // check if value zeroes out upper 32-bit of 64-bit register.
   641  // depth limits recursion depth. In AMD64.rules 3 is used as limit,
   642  // because it catches same amount of cases as 4.
   643  func zeroUpper32Bits(x *Value, depth int) bool {
   644  	switch x.Op {
   645  	case OpAMD64MOVLconst, OpAMD64MOVLload, OpAMD64MOVLQZX, OpAMD64MOVLloadidx1,
   646  		OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVBload, OpAMD64MOVBloadidx1,
   647  		OpAMD64MOVLloadidx4, OpAMD64ADDLmem, OpAMD64SUBLmem, OpAMD64ANDLmem,
   648  		OpAMD64ORLmem, OpAMD64XORLmem, OpAMD64CVTTSD2SL,
   649  		OpAMD64ADDL, OpAMD64ADDLconst, OpAMD64SUBL, OpAMD64SUBLconst,
   650  		OpAMD64ANDL, OpAMD64ANDLconst, OpAMD64ORL, OpAMD64ORLconst,
   651  		OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL:
   652  		return true
   653  	case OpArg, OpSelect0, OpSelect1:
   654  		return x.Type.Width == 4
   655  	case OpPhi:
   656  		// Phis can use each-other as an arguments, instead of tracking visited values,
   657  		// just limit recursion depth.
   658  		if depth <= 0 {
   659  			return false
   660  		}
   661  		for i := range x.Args {
   662  			if !zeroUpper32Bits(x.Args[i], depth-1) {
   663  				return false
   664  			}
   665  		}
   666  		return true
   667  
   668  	}
   669  	return false
   670  }
   671  
   672  // inlineablememmovesize reports whether the given arch performs OpMove of the given size
   673  // faster than memmove and in a safe way when src and dst overlap.
   674  // This is used as a check for replacing memmove with OpMove.
   675  func isInlinableMemmoveSize(sz int64, c *Config) bool {
   676  	switch c.arch {
   677  	case "amd64", "amd64p32":
   678  		return sz <= 16
   679  	case "386", "ppc64", "s390x", "ppc64le":
   680  		return sz <= 8
   681  	case "arm", "mips", "mips64", "mipsle", "mips64le":
   682  		return sz <= 4
   683  	}
   684  	return false
   685  }