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 	"math"
     10 	"os"
     11 	"path/filepath"
     12 )
     13 
     14 func applyRewrite(f *Func, rb func(*Block, *Config) bool, rv func(*Value, *Config) bool) {
     15 	// repeat rewrites until we find no more rewrites
     16 	var curb *Block
     17 	var curv *Value
     18 	defer func() {
     19 		if curb != nil {
     20 			curb.Fatalf("panic during rewrite of block %s\n", curb.LongString())
     21 		}
     22 		if curv != nil {
     23 			curv.Fatalf("panic during rewrite of value %s\n", curv.LongString())
     24 			// TODO(khr): print source location also
     25 		}
     26 	}()
     27 	config := f.Config
     28 	for {
     29 		change := false
     30 		for _, b := range f.Blocks {
     31 			if b.Control != nil && b.Control.Op == OpCopy {
     32 				for b.Control.Op == OpCopy {
     33 					b.SetControl(b.Control.Args[0])
     34 				}
     35 			}
     36 			curb = b
     37 			if rb(b, config) {
     38 				change = true
     39 			}
     40 			curb = nil
     41 			for _, v := range b.Values {
     42 				change = phielimValue(v) || change
     43 
     44 				// Eliminate copy inputs.
     45 				// If any copy input becomes unused, mark it
     46 				// as invalid and discard its argument. Repeat
     47 				// recursively on the discarded argument.
     48 				// This phase helps remove phantom "dead copy" uses
     49 				// of a value so that a x.Uses==1 rule condition
     50 				// fires reliably.
     51 				for i, a := range v.Args {
     52 					if a.Op != OpCopy {
     53 						continue
     54 					}
     55 					v.SetArg(i, copySource(a))
     56 					change = true
     57 					for a.Uses == 0 {
     58 						b := a.Args[0]
     59 						a.reset(OpInvalid)
     60 						a = b
     61 					}
     62 				}
     63 
     64 				// apply rewrite function
     65 				curv = v
     66 				if rv(v, config) {
     67 					change = true
     68 				}
     69 				curv = nil
     70 			}
     71 		}
     72 		if !change {
     73 			break
     74 		}
     75 	}
     76 	// remove clobbered values
     77 	for _, b := range f.Blocks {
     78 		j := 0
     79 		for i, v := range b.Values {
     80 			if v.Op == OpInvalid {
     81 				f.freeValue(v)
     82 				continue
     83 			}
     84 			if i != j {
     85 				b.Values[j] = v
     86 			}
     87 			j++
     88 		}
     89 		if j != len(b.Values) {
     90 			tail := b.Values[j:]
     91 			for j := range tail {
     92 				tail[j] = nil
     93 			}
     94 			b.Values = b.Values[:j]
     95 		}
     96 	}
     97 }
     98 
     99 // Common functions called from rewriting rules
    100 
    101 func is64BitFloat(t Type) bool {
    102 	return t.Size() == 8 && t.IsFloat()
    103 }
    104 
    105 func is32BitFloat(t Type) bool {
    106 	return t.Size() == 4 && t.IsFloat()
    107 }
    108 
    109 func is64BitInt(t Type) bool {
    110 	return t.Size() == 8 && t.IsInteger()
    111 }
    112 
    113 func is32BitInt(t Type) bool {
    114 	return t.Size() == 4 && t.IsInteger()
    115 }
    116 
    117 func is16BitInt(t Type) bool {
    118 	return t.Size() == 2 && t.IsInteger()
    119 }
    120 
    121 func is8BitInt(t Type) bool {
    122 	return t.Size() == 1 && t.IsInteger()
    123 }
    124 
    125 func isPtr(t Type) bool {
    126 	return t.IsPtrShaped()
    127 }
    128 
    129 func isSigned(t Type) bool {
    130 	return t.IsSigned()
    131 }
    132 
    133 func typeSize(t Type) int64 {
    134 	return t.Size()
    135 }
    136 
    137 // mergeSym merges two symbolic offsets. There is no real merging of
    138 // offsets, we just pick the non-nil one.
    139 func mergeSym(x, y interface{}) interface{} {
    140 	if x == nil {
    141 		return y
    142 	}
    143 	if y == nil {
    144 		return x
    145 	}
    146 	panic(fmt.Sprintf("mergeSym with two non-nil syms %s %s", x, y))
    147 }
    148 func canMergeSym(x, y interface{}) bool {
    149 	return x == nil || y == nil
    150 }
    151 
    152 // canMergeLoad reports whether the load can be merged into target without
    153 // invalidating the schedule.
    154 func canMergeLoad(target, load *Value) bool {
    155 	if target.Block.ID != load.Block.ID {
    156 		// If the load is in a different block do not merge it.
    157 		return false
    158 	}
    159 	mem := load.Args[len(load.Args)-1]
    160 
    161 	// We need the load's memory arg to still be alive at target. That
    162 	// can't be the case if one of target's args depends on a memory
    163 	// state that is a successor of load's memory arg.
    164 	//
    165 	// For example, it would be invalid to merge load into target in
    166 	// the following situation because newmem has killed oldmem
    167 	// before target is reached:
    168 	//     load = read ... oldmem
    169 	//   newmem = write ... oldmem
    170 	//     arg0 = read ... newmem
    171 	//   target = add arg0 load
    172 	//
    173 	// If the argument comes from a different block then we can exclude
    174 	// it immediately because it must dominate load (which is in the
    175 	// same block as target).
    176 	var args []*Value
    177 	for _, a := range target.Args {
    178 		if a != load && a.Block.ID == target.Block.ID {
    179 			args = append(args, a)
    180 		}
    181 	}
    182 
    183 	// memPreds contains memory states known to be predecessors of load's
    184 	// memory state. It is lazily initialized.
    185 	var memPreds map[*Value]bool
    186 search:
    187 	for i := 0; len(args) > 0; i++ {
    188 		const limit = 100
    189 		if i >= limit {
    190 			// Give up if we have done a lot of iterations.
    191 			return false
    192 		}
    193 		v := args[len(args)-1]
    194 		args = args[:len(args)-1]
    195 		if target.Block.ID != v.Block.ID {
    196 			// Since target and load are in the same block
    197 			// we can stop searching when we leave the block.
    198 			continue search
    199 		}
    200 		if v.Op == OpPhi {
    201 			// A Phi implies we have reached the top of the block.
    202 			continue search
    203 		}
    204 		if v.Type.IsTuple() && v.Type.FieldType(1).IsMemory() {
    205 			// We could handle this situation however it is likely
    206 			// to be very rare.
    207 			return false
    208 		}
    209 		if v.Type.IsMemory() {
    210 			if memPreds == nil {
    211 				// Initialise a map containing memory states
    212 				// known to be predecessors of load's memory
    213 				// state.
    214 				memPreds = make(map[*Value]bool)
    215 				m := mem
    216 				const limit = 50
    217 				for i := 0; i < limit; i++ {
    218 					if m.Op == OpPhi {
    219 						break
    220 					}
    221 					if m.Block.ID != target.Block.ID {
    222 						break
    223 					}
    224 					if !m.Type.IsMemory() {
    225 						break
    226 					}
    227 					memPreds[m] = true
    228 					if len(m.Args) == 0 {
    229 						break
    230 					}
    231 					m = m.Args[len(m.Args)-1]
    232 				}
    233 			}
    234 
    235 			// We can merge if v is a predecessor of mem.
    236 			//
    237 			// For example, we can merge load into target in the
    238 			// following scenario:
    239 			//      x = read ... v
    240 			//    mem = write ... v
    241 			//   load = read ... mem
    242 			// target = add x load
    243 			if memPreds[v] {
    244 				continue search
    245 			}
    246 			return false
    247 		}
    248 		if len(v.Args) > 0 && v.Args[len(v.Args)-1] == mem {
    249 			// If v takes mem as an input then we know mem
    250 			// is valid at this point.
    251 			continue search
    252 		}
    253 		for _, a := range v.Args {
    254 			if target.Block.ID == a.Block.ID {
    255 				args = append(args, a)
    256 			}
    257 		}
    258 	}
    259 	return true
    260 }
    261 
    262 // isArg returns whether s is an arg symbol
    263 func isArg(s interface{}) bool {
    264 	_, ok := s.(*ArgSymbol)
    265 	return ok
    266 }
    267 
    268 // isAuto returns whether s is an auto symbol
    269 func isAuto(s interface{}) bool {
    270 	_, ok := s.(*AutoSymbol)
    271 	return ok
    272 }
    273 
    274 // isSameSym returns whether sym is the same as the given named symbol
    275 func isSameSym(sym interface{}, name string) bool {
    276 	s, ok := sym.(fmt.Stringer)
    277 	return ok && s.String() == name
    278 }
    279 
    280 // nlz returns the number of leading zeros.
    281 func nlz(x int64) int64 {
    282 	// log2(0) == 1, so nlz(0) == 64
    283 	return 63 - log2(x)
    284 }
    285 
    286 // ntz returns the number of trailing zeros.
    287 func ntz(x int64) int64 {
    288 	return 64 - nlz(^x&(x-1))
    289 }
    290 
    291 // nlo returns the number of leading ones.
    292 func nlo(x int64) int64 {
    293 	return nlz(^x)
    294 }
    295 
    296 // nto returns the number of trailing ones.
    297 func nto(x int64) int64 {
    298 	return ntz(^x)
    299 }
    300 
    301 // log2 returns logarithm in base of uint64(n), with log2(0) = -1.
    302 // Rounds down.
    303 func log2(n int64) (l int64) {
    304 	l = -1
    305 	x := uint64(n)
    306 	for ; x >= 0x8000; x >>= 16 {
    307 		l += 16
    308 	}
    309 	if x >= 0x80 {
    310 		x >>= 8
    311 		l += 8
    312 	}
    313 	if x >= 0x8 {
    314 		x >>= 4
    315 		l += 4
    316 	}
    317 	if x >= 0x2 {
    318 		x >>= 2
    319 		l += 2
    320 	}
    321 	if x >= 0x1 {
    322 		l++
    323 	}
    324 	return
    325 }
    326 
    327 // isPowerOfTwo reports whether n is a power of 2.
    328 func isPowerOfTwo(n int64) bool {
    329 	return n > 0 && n&(n-1) == 0
    330 }
    331 
    332 // is32Bit reports whether n can be represented as a signed 32 bit integer.
    333 func is32Bit(n int64) bool {
    334 	return n == int64(int32(n))
    335 }
    336 
    337 // is16Bit reports whether n can be represented as a signed 16 bit integer.
    338 func is16Bit(n int64) bool {
    339 	return n == int64(int16(n))
    340 }
    341 
    342 // isU16Bit reports whether n can be represented as an unsigned 16 bit integer.
    343 func isU16Bit(n int64) bool {
    344 	return n == int64(uint16(n))
    345 }
    346 
    347 // isU32Bit reports whether n can be represented as an unsigned 32 bit integer.
    348 func isU32Bit(n int64) bool {
    349 	return n == int64(uint32(n))
    350 }
    351 
    352 // is20Bit reports whether n can be represented as a signed 20 bit integer.
    353 func is20Bit(n int64) bool {
    354 	return -(1<<19) <= n && n < (1<<19)
    355 }
    356 
    357 // b2i translates a boolean value to 0 or 1 for assigning to auxInt.
    358 func b2i(b bool) int64 {
    359 	if b {
    360 		return 1
    361 	}
    362 	return 0
    363 }
    364 
    365 // i2f is used in rules for converting from an AuxInt to a float.
    366 func i2f(i int64) float64 {
    367 	return math.Float64frombits(uint64(i))
    368 }
    369 
    370 // i2f32 is used in rules for converting from an AuxInt to a float32.
    371 func i2f32(i int64) float32 {
    372 	return float32(math.Float64frombits(uint64(i)))
    373 }
    374 
    375 // f2i is used in the rules for storing a float in AuxInt.
    376 func f2i(f float64) int64 {
    377 	return int64(math.Float64bits(f))
    378 }
    379 
    380 // uaddOvf returns true if unsigned a+b would overflow.
    381 func uaddOvf(a, b int64) bool {
    382 	return uint64(a)+uint64(b) < uint64(a)
    383 }
    384 
    385 // isSamePtr reports whether p1 and p2 point to the same address.
    386 func isSamePtr(p1, p2 *Value) bool {
    387 	if p1 == p2 {
    388 		return true
    389 	}
    390 	if p1.Op != p2.Op {
    391 		return false
    392 	}
    393 	switch p1.Op {
    394 	case OpOffPtr:
    395 		return p1.AuxInt == p2.AuxInt && isSamePtr(p1.Args[0], p2.Args[0])
    396 	case OpAddr:
    397 		// OpAddr's 0th arg is either OpSP or OpSB, which means that it is uniquely identified by its Op.
    398 		// Checking for value equality only works after [z]cse has run.
    399 		return p1.Aux == p2.Aux && p1.Args[0].Op == p2.Args[0].Op
    400 	case OpAddPtr:
    401 		return p1.Args[1] == p2.Args[1] && isSamePtr(p1.Args[0], p2.Args[0])
    402 	}
    403 	return false
    404 }
    405 
    406 // moveSize returns the number of bytes an aligned MOV instruction moves
    407 func moveSize(align int64, c *Config) int64 {
    408 	switch {
    409 	case align%8 == 0 && c.IntSize == 8:
    410 		return 8
    411 	case align%4 == 0:
    412 		return 4
    413 	case align%2 == 0:
    414 		return 2
    415 	}
    416 	return 1
    417 }
    418 
    419 // mergePoint finds a block among a's blocks which dominates b and is itself
    420 // dominated by all of a's blocks. Returns nil if it can't find one.
    421 // Might return nil even if one does exist.
    422 func mergePoint(b *Block, a ...*Value) *Block {
    423 	// Walk backward from b looking for one of the a's blocks.
    424 
    425 	// Max distance
    426 	d := 100
    427 
    428 	for d > 0 {
    429 		for _, x := range a {
    430 			if b == x.Block {
    431 				goto found
    432 			}
    433 		}
    434 		if len(b.Preds) > 1 {
    435 			// Don't know which way to go back. Abort.
    436 			return nil
    437 		}
    438 		b = b.Preds[0].b
    439 		d--
    440 	}
    441 	return nil // too far away
    442 found:
    443 	// At this point, r is the first value in a that we find by walking backwards.
    444 	// if we return anything, r will be it.
    445 	r := b
    446 
    447 	// Keep going, counting the other a's that we find. They must all dominate r.
    448 	na := 0
    449 	for d > 0 {
    450 		for _, x := range a {
    451 			if b == x.Block {
    452 				na++
    453 			}
    454 		}
    455 		if na == len(a) {
    456 			// Found all of a in a backwards walk. We can return r.
    457 			return r
    458 		}
    459 		if len(b.Preds) > 1 {
    460 			return nil
    461 		}
    462 		b = b.Preds[0].b
    463 		d--
    464 
    465 	}
    466 	return nil // too far away
    467 }
    468 
    469 // clobber invalidates v.  Returns true.
    470 // clobber is used by rewrite rules to:
    471 //   A) make sure v is really dead and never used again.
    472 //   B) decrement use counts of v's args.
    473 func clobber(v *Value) bool {
    474 	v.reset(OpInvalid)
    475 	// Note: leave v.Block intact.  The Block field is used after clobber.
    476 	return true
    477 }
    478 
    479 // noteRule is an easy way to track if a rule is matched when writing
    480 // new ones.  Make the rule of interest also conditional on
    481 //     noteRule("note to self: rule of interest matched")
    482 // and that message will print when the rule matches.
    483 func noteRule(s string) bool {
    484 	fmt.Println(s)
    485 	return true
    486 }
    487 
    488 // warnRule generates a compiler debug output with string s when
    489 // cond is true and the rule is fired.
    490 func warnRule(cond bool, v *Value, s string) bool {
    491 	if cond {
    492 		v.Block.Func.Config.Warnl(v.Line, s)
    493 	}
    494 	return true
    495 }
    496 
    497 // logRule logs the use of the rule s. This will only be enabled if
    498 // rewrite rules were generated with the -log option, see gen/rulegen.go.
    499 func logRule(s string) {
    500 	if ruleFile == nil {
    501 		// Open a log file to write log to. We open in append
    502 		// mode because all.bash runs the compiler lots of times,
    503 		// and we want the concatenation of all of those logs.
    504 		// This means, of course, that users need to rm the old log
    505 		// to get fresh data.
    506 		// TODO: all.bash runs compilers in parallel. Need to synchronize logging somehow?
    507 		w, err := os.OpenFile(filepath.Join(os.Getenv("GOROOT"), "src", "rulelog"),
    508 			os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0666)
    509 		if err != nil {
    510 			panic(err)
    511 		}
    512 		ruleFile = w
    513 	}
    514 	_, err := fmt.Fprintf(ruleFile, "rewrite %s\n", s)
    515 	if err != nil {
    516 		panic(err)
    517 	}
    518 }
    519 
    520 var ruleFile *os.File
    521