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 	"math"
      9 )
     10 
     11 // checkFunc checks invariants of f.
     12 func checkFunc(f *Func) {
     13 	blockMark := make([]bool, f.NumBlocks())
     14 	valueMark := make([]bool, f.NumValues())
     15 
     16 	for _, b := range f.Blocks {
     17 		if blockMark[b.ID] {
     18 			f.Fatalf("block %s appears twice in %s!", b, f.Name)
     19 		}
     20 		blockMark[b.ID] = true
     21 		if b.Func != f {
     22 			f.Fatalf("%s.Func=%s, want %s", b, b.Func.Name, f.Name)
     23 		}
     24 
     25 		for i, e := range b.Preds {
     26 			if se := e.b.Succs[e.i]; se.b != b || se.i != i {
     27 				f.Fatalf("block pred/succ not crosslinked correctly %d:%s %d:%s", i, b, se.i, se.b)
     28 			}
     29 		}
     30 		for i, e := range b.Succs {
     31 			if pe := e.b.Preds[e.i]; pe.b != b || pe.i != i {
     32 				f.Fatalf("block succ/pred not crosslinked correctly %d:%s %d:%s", i, b, pe.i, pe.b)
     33 			}
     34 		}
     35 
     36 		switch b.Kind {
     37 		case BlockExit:
     38 			if len(b.Succs) != 0 {
     39 				f.Fatalf("exit block %s has successors", b)
     40 			}
     41 			if b.Control == nil {
     42 				f.Fatalf("exit block %s has no control value", b)
     43 			}
     44 			if !b.Control.Type.IsMemory() {
     45 				f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString())
     46 			}
     47 		case BlockRet:
     48 			if len(b.Succs) != 0 {
     49 				f.Fatalf("ret block %s has successors", b)
     50 			}
     51 			if b.Control == nil {
     52 				f.Fatalf("ret block %s has nil control", b)
     53 			}
     54 			if !b.Control.Type.IsMemory() {
     55 				f.Fatalf("ret block %s has non-memory control value %s", b, b.Control.LongString())
     56 			}
     57 		case BlockRetJmp:
     58 			if len(b.Succs) != 0 {
     59 				f.Fatalf("retjmp block %s len(Succs)==%d, want 0", b, len(b.Succs))
     60 			}
     61 			if b.Control == nil {
     62 				f.Fatalf("retjmp block %s has nil control", b)
     63 			}
     64 			if !b.Control.Type.IsMemory() {
     65 				f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Control.LongString())
     66 			}
     67 			if b.Aux == nil {
     68 				f.Fatalf("retjmp block %s has nil Aux field", b)
     69 			}
     70 		case BlockPlain:
     71 			if len(b.Succs) != 1 {
     72 				f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs))
     73 			}
     74 			if b.Control != nil {
     75 				f.Fatalf("plain block %s has non-nil control %s", b, b.Control.LongString())
     76 			}
     77 		case BlockIf:
     78 			if len(b.Succs) != 2 {
     79 				f.Fatalf("if block %s len(Succs)==%d, want 2", b, len(b.Succs))
     80 			}
     81 			if b.Control == nil {
     82 				f.Fatalf("if block %s has no control value", b)
     83 			}
     84 			if !b.Control.Type.IsBoolean() {
     85 				f.Fatalf("if block %s has non-bool control value %s", b, b.Control.LongString())
     86 			}
     87 		case BlockDefer:
     88 			if len(b.Succs) != 2 {
     89 				f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs))
     90 			}
     91 			if b.Control == nil {
     92 				f.Fatalf("defer block %s has no control value", b)
     93 			}
     94 			if !b.Control.Type.IsMemory() {
     95 				f.Fatalf("defer block %s has non-memory control value %s", b, b.Control.LongString())
     96 			}
     97 		case BlockFirst:
     98 			if len(b.Succs) != 2 {
     99 				f.Fatalf("plain/dead block %s len(Succs)==%d, want 2", b, len(b.Succs))
    100 			}
    101 			if b.Control != nil {
    102 				f.Fatalf("plain/dead block %s has a control value", b)
    103 			}
    104 		}
    105 		if len(b.Succs) > 2 && b.Likely != BranchUnknown {
    106 			f.Fatalf("likeliness prediction %d for block %s with %d successors", b.Likely, b, len(b.Succs))
    107 		}
    108 
    109 		for _, v := range b.Values {
    110 			// Check to make sure argument count makes sense (argLen of -1 indicates
    111 			// variable length args)
    112 			nArgs := opcodeTable[v.Op].argLen
    113 			if nArgs != -1 && int32(len(v.Args)) != nArgs {
    114 				f.Fatalf("value %s has %d args, expected %d", v.LongString(),
    115 					len(v.Args), nArgs)
    116 			}
    117 
    118 			// Check to make sure aux values make sense.
    119 			canHaveAux := false
    120 			canHaveAuxInt := false
    121 			switch opcodeTable[v.Op].auxType {
    122 			case auxNone:
    123 			case auxBool:
    124 				if v.AuxInt < 0 || v.AuxInt > 1 {
    125 					f.Fatalf("bad bool AuxInt value for %v", v)
    126 				}
    127 				canHaveAuxInt = true
    128 			case auxInt8:
    129 				if v.AuxInt != int64(int8(v.AuxInt)) {
    130 					f.Fatalf("bad int8 AuxInt value for %v", v)
    131 				}
    132 				canHaveAuxInt = true
    133 			case auxInt16:
    134 				if v.AuxInt != int64(int16(v.AuxInt)) {
    135 					f.Fatalf("bad int16 AuxInt value for %v", v)
    136 				}
    137 				canHaveAuxInt = true
    138 			case auxInt32:
    139 				if v.AuxInt != int64(int32(v.AuxInt)) {
    140 					f.Fatalf("bad int32 AuxInt value for %v", v)
    141 				}
    142 				canHaveAuxInt = true
    143 			case auxInt64, auxFloat64:
    144 				canHaveAuxInt = true
    145 			case auxInt128:
    146 				// AuxInt must be zero, so leave canHaveAuxInt set to false.
    147 			case auxFloat32:
    148 				canHaveAuxInt = true
    149 				if !isExactFloat32(v) {
    150 					f.Fatalf("value %v has an AuxInt value that is not an exact float32", v)
    151 				}
    152 			case auxString, auxSym, auxTyp:
    153 				canHaveAux = true
    154 			case auxSymOff, auxSymValAndOff, auxTypSize:
    155 				canHaveAuxInt = true
    156 				canHaveAux = true
    157 			case auxSymInt32:
    158 				if v.AuxInt != int64(int32(v.AuxInt)) {
    159 					f.Fatalf("bad int32 AuxInt value for %v", v)
    160 				}
    161 				canHaveAuxInt = true
    162 				canHaveAux = true
    163 			default:
    164 				f.Fatalf("unknown aux type for %s", v.Op)
    165 			}
    166 			if !canHaveAux && v.Aux != nil {
    167 				f.Fatalf("value %s has an Aux value %v but shouldn't", v.LongString(), v.Aux)
    168 			}
    169 			if !canHaveAuxInt && v.AuxInt != 0 {
    170 				f.Fatalf("value %s has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt)
    171 			}
    172 
    173 			for i, arg := range v.Args {
    174 				if arg == nil {
    175 					f.Fatalf("value %s has nil arg", v.LongString())
    176 				}
    177 				if v.Op != OpPhi {
    178 					// For non-Phi ops, memory args must be last, if present
    179 					if arg.Type.IsMemory() && i != len(v.Args)-1 {
    180 						f.Fatalf("value %s has non-final memory arg (%d < %d)", v.LongString(), i, len(v.Args)-1)
    181 					}
    182 				}
    183 			}
    184 
    185 			if valueMark[v.ID] {
    186 				f.Fatalf("value %s appears twice!", v.LongString())
    187 			}
    188 			valueMark[v.ID] = true
    189 
    190 			if v.Block != b {
    191 				f.Fatalf("%s.block != %s", v, b)
    192 			}
    193 			if v.Op == OpPhi && len(v.Args) != len(b.Preds) {
    194 				f.Fatalf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b)
    195 			}
    196 
    197 			if v.Op == OpAddr {
    198 				if len(v.Args) == 0 {
    199 					f.Fatalf("no args for OpAddr %s", v.LongString())
    200 				}
    201 				if v.Args[0].Op != OpSP && v.Args[0].Op != OpSB {
    202 					f.Fatalf("bad arg to OpAddr %v", v)
    203 				}
    204 			}
    205 
    206 			if f.RegAlloc != nil && f.Config.SoftFloat && v.Type.IsFloat() {
    207 				f.Fatalf("unexpected floating-point type %v", v.LongString())
    208 			}
    209 
    210 			// TODO: check for cycles in values
    211 			// TODO: check type
    212 		}
    213 	}
    214 
    215 	// Check to make sure all Blocks referenced are in the function.
    216 	if !blockMark[f.Entry.ID] {
    217 		f.Fatalf("entry block %v is missing", f.Entry)
    218 	}
    219 	for _, b := range f.Blocks {
    220 		for _, c := range b.Preds {
    221 			if !blockMark[c.b.ID] {
    222 				f.Fatalf("predecessor block %v for %v is missing", c, b)
    223 			}
    224 		}
    225 		for _, c := range b.Succs {
    226 			if !blockMark[c.b.ID] {
    227 				f.Fatalf("successor block %v for %v is missing", c, b)
    228 			}
    229 		}
    230 	}
    231 
    232 	if len(f.Entry.Preds) > 0 {
    233 		f.Fatalf("entry block %s of %s has predecessor(s) %v", f.Entry, f.Name, f.Entry.Preds)
    234 	}
    235 
    236 	// Check to make sure all Values referenced are in the function.
    237 	for _, b := range f.Blocks {
    238 		for _, v := range b.Values {
    239 			for i, a := range v.Args {
    240 				if !valueMark[a.ID] {
    241 					f.Fatalf("%v, arg %d of %s, is missing", a, i, v.LongString())
    242 				}
    243 			}
    244 		}
    245 		if b.Control != nil && !valueMark[b.Control.ID] {
    246 			f.Fatalf("control value for %s is missing: %v", b, b.Control)
    247 		}
    248 	}
    249 	for b := f.freeBlocks; b != nil; b = b.succstorage[0].b {
    250 		if blockMark[b.ID] {
    251 			f.Fatalf("used block b%d in free list", b.ID)
    252 		}
    253 	}
    254 	for v := f.freeValues; v != nil; v = v.argstorage[0] {
    255 		if valueMark[v.ID] {
    256 			f.Fatalf("used value v%d in free list", v.ID)
    257 		}
    258 	}
    259 
    260 	// Check to make sure all args dominate uses.
    261 	if f.RegAlloc == nil {
    262 		// Note: regalloc introduces non-dominating args.
    263 		// See TODO in regalloc.go.
    264 		sdom := f.sdom()
    265 		for _, b := range f.Blocks {
    266 			for _, v := range b.Values {
    267 				for i, arg := range v.Args {
    268 					x := arg.Block
    269 					y := b
    270 					if v.Op == OpPhi {
    271 						y = b.Preds[i].b
    272 					}
    273 					if !domCheck(f, sdom, x, y) {
    274 						f.Fatalf("arg %d of value %s does not dominate, arg=%s", i, v.LongString(), arg.LongString())
    275 					}
    276 				}
    277 			}
    278 			if b.Control != nil && !domCheck(f, sdom, b.Control.Block, b) {
    279 				f.Fatalf("control value %s for %s doesn't dominate", b.Control, b)
    280 			}
    281 		}
    282 	}
    283 
    284 	// Check loop construction
    285 	if f.RegAlloc == nil && f.pass != nil { // non-nil pass allows better-targeted debug printing
    286 		ln := f.loopnest()
    287 		if !ln.hasIrreducible {
    288 			po := f.postorder() // use po to avoid unreachable blocks.
    289 			for _, b := range po {
    290 				for _, s := range b.Succs {
    291 					bb := s.Block()
    292 					if ln.b2l[b.ID] == nil && ln.b2l[bb.ID] != nil && bb != ln.b2l[bb.ID].header {
    293 						f.Fatalf("block %s not in loop branches to non-header block %s in loop", b.String(), bb.String())
    294 					}
    295 					if ln.b2l[b.ID] != nil && ln.b2l[bb.ID] != nil && bb != ln.b2l[bb.ID].header && !ln.b2l[b.ID].isWithinOrEq(ln.b2l[bb.ID]) {
    296 						f.Fatalf("block %s in loop branches to non-header block %s in non-containing loop", b.String(), bb.String())
    297 					}
    298 				}
    299 			}
    300 		}
    301 	}
    302 
    303 	// Check use counts
    304 	uses := make([]int32, f.NumValues())
    305 	for _, b := range f.Blocks {
    306 		for _, v := range b.Values {
    307 			for _, a := range v.Args {
    308 				uses[a.ID]++
    309 			}
    310 		}
    311 		if b.Control != nil {
    312 			uses[b.Control.ID]++
    313 		}
    314 	}
    315 	for _, b := range f.Blocks {
    316 		for _, v := range b.Values {
    317 			if v.Uses != uses[v.ID] {
    318 				f.Fatalf("%s has %d uses, but has Uses=%d", v, uses[v.ID], v.Uses)
    319 			}
    320 		}
    321 	}
    322 
    323 	memCheck(f)
    324 }
    325 
    326 func memCheck(f *Func) {
    327 	// Check that if a tuple has a memory type, it is second.
    328 	for _, b := range f.Blocks {
    329 		for _, v := range b.Values {
    330 			if v.Type.IsTuple() && v.Type.FieldType(0).IsMemory() {
    331 				f.Fatalf("memory is first in a tuple: %s\n", v.LongString())
    332 			}
    333 		}
    334 	}
    335 
    336 	// Single live memory checks.
    337 	// These checks only work if there are no memory copies.
    338 	// (Memory copies introduce ambiguity about which mem value is really live.
    339 	// probably fixable, but it's easier to avoid the problem.)
    340 	// For the same reason, disable this check if some memory ops are unused.
    341 	for _, b := range f.Blocks {
    342 		for _, v := range b.Values {
    343 			if (v.Op == OpCopy || v.Uses == 0) && v.Type.IsMemory() {
    344 				return
    345 			}
    346 		}
    347 		if b != f.Entry && len(b.Preds) == 0 {
    348 			return
    349 		}
    350 	}
    351 
    352 	// Compute live memory at the end of each block.
    353 	lastmem := make([]*Value, f.NumBlocks())
    354 	ss := newSparseSet(f.NumValues())
    355 	for _, b := range f.Blocks {
    356 		// Mark overwritten memory values. Those are args of other
    357 		// ops that generate memory values.
    358 		ss.clear()
    359 		for _, v := range b.Values {
    360 			if v.Op == OpPhi || !v.Type.IsMemory() {
    361 				continue
    362 			}
    363 			if m := v.MemoryArg(); m != nil {
    364 				ss.add(m.ID)
    365 			}
    366 		}
    367 		// There should be at most one remaining unoverwritten memory value.
    368 		for _, v := range b.Values {
    369 			if !v.Type.IsMemory() {
    370 				continue
    371 			}
    372 			if ss.contains(v.ID) {
    373 				continue
    374 			}
    375 			if lastmem[b.ID] != nil {
    376 				f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], v)
    377 			}
    378 			lastmem[b.ID] = v
    379 		}
    380 		// If there is no remaining memory value, that means there was no memory update.
    381 		// Take any memory arg.
    382 		if lastmem[b.ID] == nil {
    383 			for _, v := range b.Values {
    384 				if v.Op == OpPhi {
    385 					continue
    386 				}
    387 				m := v.MemoryArg()
    388 				if m == nil {
    389 					continue
    390 				}
    391 				if lastmem[b.ID] != nil && lastmem[b.ID] != m {
    392 					f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], m)
    393 				}
    394 				lastmem[b.ID] = m
    395 			}
    396 		}
    397 	}
    398 	// Propagate last live memory through storeless blocks.
    399 	for {
    400 		changed := false
    401 		for _, b := range f.Blocks {
    402 			if lastmem[b.ID] != nil {
    403 				continue
    404 			}
    405 			for _, e := range b.Preds {
    406 				p := e.b
    407 				if lastmem[p.ID] != nil {
    408 					lastmem[b.ID] = lastmem[p.ID]
    409 					changed = true
    410 					break
    411 				}
    412 			}
    413 		}
    414 		if !changed {
    415 			break
    416 		}
    417 	}
    418 	// Check merge points.
    419 	for _, b := range f.Blocks {
    420 		for _, v := range b.Values {
    421 			if v.Op == OpPhi && v.Type.IsMemory() {
    422 				for i, a := range v.Args {
    423 					if a != lastmem[b.Preds[i].b.ID] {
    424 						f.Fatalf("inconsistent memory phi %s %d %s %s", v.LongString(), i, a, lastmem[b.Preds[i].b.ID])
    425 					}
    426 				}
    427 			}
    428 		}
    429 	}
    430 
    431 	// Check that only one memory is live at any point.
    432 	if f.scheduled {
    433 		for _, b := range f.Blocks {
    434 			var mem *Value // the current live memory in the block
    435 			for _, v := range b.Values {
    436 				if v.Op == OpPhi {
    437 					if v.Type.IsMemory() {
    438 						mem = v
    439 					}
    440 					continue
    441 				}
    442 				if mem == nil && len(b.Preds) > 0 {
    443 					// If no mem phi, take mem of any predecessor.
    444 					mem = lastmem[b.Preds[0].b.ID]
    445 				}
    446 				for _, a := range v.Args {
    447 					if a.Type.IsMemory() && a != mem {
    448 						f.Fatalf("two live mems @ %s: %s and %s", v, mem, a)
    449 					}
    450 				}
    451 				if v.Type.IsMemory() {
    452 					mem = v
    453 				}
    454 			}
    455 		}
    456 	}
    457 
    458 	// Check that after scheduling, phis are always first in the block.
    459 	if f.scheduled {
    460 		for _, b := range f.Blocks {
    461 			seenNonPhi := false
    462 			for _, v := range b.Values {
    463 				switch v.Op {
    464 				case OpPhi:
    465 					if seenNonPhi {
    466 						f.Fatalf("phi after non-phi @ %s: %s", b, v)
    467 					}
    468 				case OpRegKill:
    469 					if f.RegAlloc == nil {
    470 						f.Fatalf("RegKill seen before register allocation @ %s: %s", b, v)
    471 					}
    472 				default:
    473 					seenNonPhi = true
    474 				}
    475 			}
    476 		}
    477 	}
    478 }
    479 
    480 // domCheck reports whether x dominates y (including x==y).
    481 func domCheck(f *Func, sdom SparseTree, x, y *Block) bool {
    482 	if !sdom.isAncestorEq(f.Entry, y) {
    483 		// unreachable - ignore
    484 		return true
    485 	}
    486 	return sdom.isAncestorEq(x, y)
    487 }
    488 
    489 // isExactFloat32 reports whether v has an AuxInt that can be exactly represented as a float32.
    490 func isExactFloat32(v *Value) bool {
    491 	x := v.AuxFloat()
    492 	return math.Float64bits(x) == math.Float64bits(float64(float32(x)))
    493 }
    494