github.com/hlts2/go@v0.0.0-20170904000733-812b34efaed8/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  // isArg returns whether s is an arg symbol
   280  func isArg(s interface{}) bool {
   281  	_, ok := s.(*ArgSymbol)
   282  	return ok
   283  }
   284  
   285  // isAuto returns whether s is an auto symbol
   286  func isAuto(s interface{}) bool {
   287  	_, ok := s.(*AutoSymbol)
   288  	return ok
   289  }
   290  
   291  // isSameSym returns whether sym is the same as the given named symbol
   292  func isSameSym(sym interface{}, name string) bool {
   293  	s, ok := sym.(fmt.Stringer)
   294  	return ok && s.String() == name
   295  }
   296  
   297  // nlz returns the number of leading zeros.
   298  func nlz(x int64) int64 {
   299  	// log2(0) == 1, so nlz(0) == 64
   300  	return 63 - log2(x)
   301  }
   302  
   303  // ntz returns the number of trailing zeros.
   304  func ntz(x int64) int64 {
   305  	return 64 - nlz(^x&(x-1))
   306  }
   307  
   308  func oneBit(x int64) bool {
   309  	return nlz(x)+ntz(x) == 63
   310  }
   311  
   312  // nlo returns the number of leading ones.
   313  func nlo(x int64) int64 {
   314  	return nlz(^x)
   315  }
   316  
   317  // nto returns the number of trailing ones.
   318  func nto(x int64) int64 {
   319  	return ntz(^x)
   320  }
   321  
   322  // log2 returns logarithm in base 2 of uint64(n), with log2(0) = -1.
   323  // Rounds down.
   324  func log2(n int64) (l int64) {
   325  	l = -1
   326  	x := uint64(n)
   327  	for ; x >= 0x8000; x >>= 16 {
   328  		l += 16
   329  	}
   330  	if x >= 0x80 {
   331  		x >>= 8
   332  		l += 8
   333  	}
   334  	if x >= 0x8 {
   335  		x >>= 4
   336  		l += 4
   337  	}
   338  	if x >= 0x2 {
   339  		x >>= 2
   340  		l += 2
   341  	}
   342  	if x >= 0x1 {
   343  		l++
   344  	}
   345  	return
   346  }
   347  
   348  // isPowerOfTwo reports whether n is a power of 2.
   349  func isPowerOfTwo(n int64) bool {
   350  	return n > 0 && n&(n-1) == 0
   351  }
   352  
   353  // is32Bit reports whether n can be represented as a signed 32 bit integer.
   354  func is32Bit(n int64) bool {
   355  	return n == int64(int32(n))
   356  }
   357  
   358  // is16Bit reports whether n can be represented as a signed 16 bit integer.
   359  func is16Bit(n int64) bool {
   360  	return n == int64(int16(n))
   361  }
   362  
   363  // isU12Bit reports whether n can be represented as an unsigned 12 bit integer.
   364  func isU12Bit(n int64) bool {
   365  	return 0 <= n && n < (1<<12)
   366  }
   367  
   368  // isU16Bit reports whether n can be represented as an unsigned 16 bit integer.
   369  func isU16Bit(n int64) bool {
   370  	return n == int64(uint16(n))
   371  }
   372  
   373  // isU32Bit reports whether n can be represented as an unsigned 32 bit integer.
   374  func isU32Bit(n int64) bool {
   375  	return n == int64(uint32(n))
   376  }
   377  
   378  // is20Bit reports whether n can be represented as a signed 20 bit integer.
   379  func is20Bit(n int64) bool {
   380  	return -(1<<19) <= n && n < (1<<19)
   381  }
   382  
   383  // b2i translates a boolean value to 0 or 1 for assigning to auxInt.
   384  func b2i(b bool) int64 {
   385  	if b {
   386  		return 1
   387  	}
   388  	return 0
   389  }
   390  
   391  // i2f is used in rules for converting from an AuxInt to a float.
   392  func i2f(i int64) float64 {
   393  	return math.Float64frombits(uint64(i))
   394  }
   395  
   396  // i2f32 is used in rules for converting from an AuxInt to a float32.
   397  func i2f32(i int64) float32 {
   398  	return float32(math.Float64frombits(uint64(i)))
   399  }
   400  
   401  // f2i is used in the rules for storing a float in AuxInt.
   402  func f2i(f float64) int64 {
   403  	return int64(math.Float64bits(f))
   404  }
   405  
   406  // uaddOvf returns true if unsigned a+b would overflow.
   407  func uaddOvf(a, b int64) bool {
   408  	return uint64(a)+uint64(b) < uint64(a)
   409  }
   410  
   411  // de-virtualize an InterCall
   412  // 'sym' is the symbol for the itab
   413  func devirt(v *Value, sym interface{}, offset int64) *obj.LSym {
   414  	f := v.Block.Func
   415  	ext, ok := sym.(*ExternSymbol)
   416  	if !ok {
   417  		return nil
   418  	}
   419  	lsym := f.fe.DerefItab(ext.Sym, offset)
   420  	if f.pass.debug > 0 {
   421  		if lsym != nil {
   422  			f.Warnl(v.Pos, "de-virtualizing call")
   423  		} else {
   424  			f.Warnl(v.Pos, "couldn't de-virtualize call")
   425  		}
   426  	}
   427  	return lsym
   428  }
   429  
   430  // isSamePtr reports whether p1 and p2 point to the same address.
   431  func isSamePtr(p1, p2 *Value) bool {
   432  	if p1 == p2 {
   433  		return true
   434  	}
   435  	if p1.Op != p2.Op {
   436  		return false
   437  	}
   438  	switch p1.Op {
   439  	case OpOffPtr:
   440  		return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
   441  	case OpAddr:
   442  		// OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op.
   443  		// Checking for value equality only works after [z]cse has run.
   444  		return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op
   445  	case OpAddPtr:
   446  		return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0])
   447  	}
   448  	return false
   449  }
   450  
   451  // moveSize returns the number of bytes an aligned MOV instruction moves
   452  func moveSize(align int64, c *Config) int64 {
   453  	switch {
   454  	case align%8 == 0 && c.PtrSize == 8:
   455  		return 8
   456  	case align%4 == 0:
   457  		return 4
   458  	case align%2 == 0:
   459  		return 2
   460  	}
   461  	return 1
   462  }
   463  
   464  // mergePoint finds a block among a's blocks which dominates b and is itself
   465  // dominated by all of a's blocks. Returns nil if it can't find one.
   466  // Might return nil even if one does exist.
   467  func mergePoint(b *Block, a ...*Value) *Block {
   468  	// Walk backward from b looking for one of the a's blocks.
   469  
   470  	// Max distance
   471  	d := 100
   472  
   473  	for d > 0 {
   474  		for _, x := range a {
   475  			if b == x.Block {
   476  				goto found
   477  			}
   478  		}
   479  		if len(b.Preds) > 1 {
   480  			// Don't know which way to go back. Abort.
   481  			return nil
   482  		}
   483  		b = b.Preds[0].b
   484  		d--
   485  	}
   486  	return nil // too far away
   487  found:
   488  	// At this point, r is the first value in a that we find by walking backwards.
   489  	// if we return anything, r will be it.
   490  	r := b
   491  
   492  	// Keep going, counting the other a's that we find. They must all dominate r.
   493  	na := 0
   494  	for d > 0 {
   495  		for _, x := range a {
   496  			if b == x.Block {
   497  				na++
   498  			}
   499  		}
   500  		if na == len(a) {
   501  			// Found all of a in a backwards walk. We can return r.
   502  			return r
   503  		}
   504  		if len(b.Preds) > 1 {
   505  			return nil
   506  		}
   507  		b = b.Preds[0].b
   508  		d--
   509  
   510  	}
   511  	return nil // too far away
   512  }
   513  
   514  // clobber invalidates v.  Returns true.
   515  // clobber is used by rewrite rules to:
   516  //   A) make sure v is really dead and never used again.
   517  //   B) decrement use counts of v's args.
   518  func clobber(v *Value) bool {
   519  	v.reset(OpInvalid)
   520  	// Note: leave v.Block intact.  The Block field is used after clobber.
   521  	return true
   522  }
   523  
   524  // noteRule is an easy way to track if a rule is matched when writing
   525  // new ones.  Make the rule of interest also conditional on
   526  //     noteRule("note to self: rule of interest matched")
   527  // and that message will print when the rule matches.
   528  func noteRule(s string) bool {
   529  	fmt.Println(s)
   530  	return true
   531  }
   532  
   533  // warnRule generates a compiler debug output with string s when
   534  // cond is true and the rule is fired.
   535  func warnRule(cond bool, v *Value, s string) bool {
   536  	if cond {
   537  		v.Block.Func.Warnl(v.Pos, s)
   538  	}
   539  	return true
   540  }
   541  
   542  // logRule logs the use of the rule s. This will only be enabled if
   543  // rewrite rules were generated with the -log option, see gen/rulegen.go.
   544  func logRule(s string) {
   545  	if ruleFile == nil {
   546  		// Open a log file to write log to. We open in append
   547  		// mode because all.bash runs the compiler lots of times,
   548  		// and we want the concatenation of all of those logs.
   549  		// This means, of course, that users need to rm the old log
   550  		// to get fresh data.
   551  		// TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow?
   552  		w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
   553  			os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
   554  		if err != nil {
   555  			panic(err)
   556  		}
   557  		ruleFile = w
   558  	}
   559  	_, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s)
   560  	if err != nil {
   561  		panic(err)
   562  	}
   563  }
   564  
   565  var ruleFile io.Writer
   566  
   567  func min(x, y int64) int64 {
   568  	if x < y {
   569  		return x
   570  	}
   571  	return y
   572  }
   573  
   574  func isConstZero(v *Value) bool {
   575  	switch v.Op {
   576  	case OpConstNil:
   577  		return true
   578  	case OpConst64, OpConst32, OpConst16, OpConst8, OpConstBool, OpConst32F, OpConst64F:
   579  		return v.AuxInt == 0
   580  	}
   581  	return false
   582  }
   583  
   584  // reciprocalExact64 reports whether 1/c is exactly representable.
   585  func reciprocalExact64(c float64) bool {
   586  	b := math.Float64bits(c)
   587  	man := b & (1<<52 - 1)
   588  	if man != 0 {
   589  		return false // not a power of 2, denormal, or NaN
   590  	}
   591  	exp := b >> 52 & (1<<11 - 1)
   592  	// exponent bias is 0x3ff.  So taking the reciprocal of a number
   593  	// changes the exponent to 0x7fe-exp.
   594  	switch exp {
   595  	case 0:
   596  		return false // ±0
   597  	case 0x7ff:
   598  		return false // ±inf
   599  	case 0x7fe:
   600  		return false // exponent is not representable
   601  	default:
   602  		return true
   603  	}
   604  }
   605  
   606  // reciprocalExact32 reports whether 1/c is exactly representable.
   607  func reciprocalExact32(c float32) bool {
   608  	b := math.Float32bits(c)
   609  	man := b & (1<<23 - 1)
   610  	if man != 0 {
   611  		return false // not a power of 2, denormal, or NaN
   612  	}
   613  	exp := b >> 23 & (1<<8 - 1)
   614  	// exponent bias is 0x7f.  So taking the reciprocal of a number
   615  	// changes the exponent to 0xfe-exp.
   616  	switch exp {
   617  	case 0:
   618  		return false // ±0
   619  	case 0xff:
   620  		return false // ±inf
   621  	case 0xfe:
   622  		return false // exponent is not representable
   623  	default:
   624  		return true
   625  	}
   626  }
   627  
   628  // check if an immediate can be directly encoded into an ARM's instruction
   629  func isARMImmRot(v uint32) bool {
   630  	for i := 0; i < 16; i++ {
   631  		if v&^0xff == 0 {
   632  			return true
   633  		}
   634  		v = v<<2 | v>>30
   635  	}
   636  
   637  	return false
   638  }
   639  
   640  // overlap reports whether the ranges given by the given offset and
   641  // size pairs overlap.
   642  func overlap(offset1, size1, offset2, size2 int64) bool {
   643  	if offset1 >= offset2 && offset2+size2 > offset1 {
   644  		return true
   645  	}
   646  	if offset2 >= offset1 && offset1+size1 > offset2 {
   647  		return true
   648  	}
   649  	return false
   650  }
   651  
   652  // check if value zeroes out upper 32-bit of 64-bit register.
   653  // depth limits recursion depth. In AMD64.rules 3 is used as limit,
   654  // because it catches same amount of cases as 4.
   655  func zeroUpper32Bits(x *Value, depth int) bool {
   656  	switch x.Op {
   657  	case OpAMD64MOVLconst, OpAMD64MOVLload, OpAMD64MOVLQZX, OpAMD64MOVLloadidx1,
   658  		OpAMD64MOVWload, OpAMD64MOVWloadidx1, OpAMD64MOVBload, OpAMD64MOVBloadidx1,
   659  		OpAMD64MOVLloadidx4, OpAMD64ADDLmem, OpAMD64SUBLmem, OpAMD64ANDLmem,
   660  		OpAMD64ORLmem, OpAMD64XORLmem, OpAMD64CVTTSD2SL,
   661  		OpAMD64ADDL, OpAMD64ADDLconst, OpAMD64SUBL, OpAMD64SUBLconst,
   662  		OpAMD64ANDL, OpAMD64ANDLconst, OpAMD64ORL, OpAMD64ORLconst,
   663  		OpAMD64XORL, OpAMD64XORLconst, OpAMD64NEGL, OpAMD64NOTL:
   664  		return true
   665  	case OpArg, OpSelect0, OpSelect1:
   666  		return x.Type.Width == 4
   667  	case OpPhi:
   668  		// Phis can use each-other as an arguments, instead of tracking visited values,
   669  		// just limit recursion depth.
   670  		if depth <= 0 {
   671  			return false
   672  		}
   673  		for i := range x.Args {
   674  			if !zeroUpper32Bits(x.Args[i], depth-1) {
   675  				return false
   676  			}
   677  		}
   678  		return true
   679  
   680  	}
   681  	return false
   682  }