github.com/corona10/go@v0.0.0-20180224231303-7a218942be57/src/cmd/compile/internal/ssa/check.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 "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 case auxCCop: 164 if _, ok := v.Aux.(Op); !ok { 165 f.Fatalf("bad type %T for CCop in %v", v.Aux, v) 166 } 167 canHaveAux = true 168 default: 169 f.Fatalf("unknown aux type for %s", v.Op) 170 } 171 if !canHaveAux && v.Aux != nil { 172 f.Fatalf("value %s has an Aux value %v but shouldn't", v.LongString(), v.Aux) 173 } 174 if !canHaveAuxInt && v.AuxInt != 0 { 175 f.Fatalf("value %s has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt) 176 } 177 178 for i, arg := range v.Args { 179 if arg == nil { 180 f.Fatalf("value %s has nil arg", v.LongString()) 181 } 182 if v.Op != OpPhi { 183 // For non-Phi ops, memory args must be last, if present 184 if arg.Type.IsMemory() && i != len(v.Args)-1 { 185 f.Fatalf("value %s has non-final memory arg (%d < %d)", v.LongString(), i, len(v.Args)-1) 186 } 187 } 188 } 189 190 if valueMark[v.ID] { 191 f.Fatalf("value %s appears twice!", v.LongString()) 192 } 193 valueMark[v.ID] = true 194 195 if v.Block != b { 196 f.Fatalf("%s.block != %s", v, b) 197 } 198 if v.Op == OpPhi && len(v.Args) != len(b.Preds) { 199 f.Fatalf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b) 200 } 201 202 if v.Op == OpAddr { 203 if len(v.Args) == 0 { 204 f.Fatalf("no args for OpAddr %s", v.LongString()) 205 } 206 if v.Args[0].Op != OpSP && v.Args[0].Op != OpSB { 207 f.Fatalf("bad arg to OpAddr %v", v) 208 } 209 } 210 211 if f.RegAlloc != nil && f.Config.SoftFloat && v.Type.IsFloat() { 212 f.Fatalf("unexpected floating-point type %v", v.LongString()) 213 } 214 215 // TODO: check for cycles in values 216 // TODO: check type 217 } 218 } 219 220 // Check to make sure all Blocks referenced are in the function. 221 if !blockMark[f.Entry.ID] { 222 f.Fatalf("entry block %v is missing", f.Entry) 223 } 224 for _, b := range f.Blocks { 225 for _, c := range b.Preds { 226 if !blockMark[c.b.ID] { 227 f.Fatalf("predecessor block %v for %v is missing", c, b) 228 } 229 } 230 for _, c := range b.Succs { 231 if !blockMark[c.b.ID] { 232 f.Fatalf("successor block %v for %v is missing", c, b) 233 } 234 } 235 } 236 237 if len(f.Entry.Preds) > 0 { 238 f.Fatalf("entry block %s of %s has predecessor(s) %v", f.Entry, f.Name, f.Entry.Preds) 239 } 240 241 // Check to make sure all Values referenced are in the function. 242 for _, b := range f.Blocks { 243 for _, v := range b.Values { 244 for i, a := range v.Args { 245 if !valueMark[a.ID] { 246 f.Fatalf("%v, arg %d of %s, is missing", a, i, v.LongString()) 247 } 248 } 249 } 250 if b.Control != nil && !valueMark[b.Control.ID] { 251 f.Fatalf("control value for %s is missing: %v", b, b.Control) 252 } 253 } 254 for b := f.freeBlocks; b != nil; b = b.succstorage[0].b { 255 if blockMark[b.ID] { 256 f.Fatalf("used block b%d in free list", b.ID) 257 } 258 } 259 for v := f.freeValues; v != nil; v = v.argstorage[0] { 260 if valueMark[v.ID] { 261 f.Fatalf("used value v%d in free list", v.ID) 262 } 263 } 264 265 // Check to make sure all args dominate uses. 266 if f.RegAlloc == nil { 267 // Note: regalloc introduces non-dominating args. 268 // See TODO in regalloc.go. 269 sdom := f.sdom() 270 for _, b := range f.Blocks { 271 for _, v := range b.Values { 272 for i, arg := range v.Args { 273 x := arg.Block 274 y := b 275 if v.Op == OpPhi { 276 y = b.Preds[i].b 277 } 278 if !domCheck(f, sdom, x, y) { 279 f.Fatalf("arg %d of value %s does not dominate, arg=%s", i, v.LongString(), arg.LongString()) 280 } 281 } 282 } 283 if b.Control != nil && !domCheck(f, sdom, b.Control.Block, b) { 284 f.Fatalf("control value %s for %s doesn't dominate", b.Control, b) 285 } 286 } 287 } 288 289 // Check loop construction 290 if f.RegAlloc == nil && f.pass != nil { // non-nil pass allows better-targeted debug printing 291 ln := f.loopnest() 292 if !ln.hasIrreducible { 293 po := f.postorder() // use po to avoid unreachable blocks. 294 for _, b := range po { 295 for _, s := range b.Succs { 296 bb := s.Block() 297 if ln.b2l[b.ID] == nil && ln.b2l[bb.ID] != nil && bb != ln.b2l[bb.ID].header { 298 f.Fatalf("block %s not in loop branches to non-header block %s in loop", b.String(), bb.String()) 299 } 300 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]) { 301 f.Fatalf("block %s in loop branches to non-header block %s in non-containing loop", b.String(), bb.String()) 302 } 303 } 304 } 305 } 306 } 307 308 // Check use counts 309 uses := make([]int32, f.NumValues()) 310 for _, b := range f.Blocks { 311 for _, v := range b.Values { 312 for _, a := range v.Args { 313 uses[a.ID]++ 314 } 315 } 316 if b.Control != nil { 317 uses[b.Control.ID]++ 318 } 319 } 320 for _, b := range f.Blocks { 321 for _, v := range b.Values { 322 if v.Uses != uses[v.ID] { 323 f.Fatalf("%s has %d uses, but has Uses=%d", v, uses[v.ID], v.Uses) 324 } 325 } 326 } 327 328 memCheck(f) 329 } 330 331 func memCheck(f *Func) { 332 // Check that if a tuple has a memory type, it is second. 333 for _, b := range f.Blocks { 334 for _, v := range b.Values { 335 if v.Type.IsTuple() && v.Type.FieldType(0).IsMemory() { 336 f.Fatalf("memory is first in a tuple: %s\n", v.LongString()) 337 } 338 } 339 } 340 341 // Single live memory checks. 342 // These checks only work if there are no memory copies. 343 // (Memory copies introduce ambiguity about which mem value is really live. 344 // probably fixable, but it's easier to avoid the problem.) 345 // For the same reason, disable this check if some memory ops are unused. 346 for _, b := range f.Blocks { 347 for _, v := range b.Values { 348 if (v.Op == OpCopy || v.Uses == 0) && v.Type.IsMemory() { 349 return 350 } 351 } 352 if b != f.Entry && len(b.Preds) == 0 { 353 return 354 } 355 } 356 357 // Compute live memory at the end of each block. 358 lastmem := make([]*Value, f.NumBlocks()) 359 ss := newSparseSet(f.NumValues()) 360 for _, b := range f.Blocks { 361 // Mark overwritten memory values. Those are args of other 362 // ops that generate memory values. 363 ss.clear() 364 for _, v := range b.Values { 365 if v.Op == OpPhi || !v.Type.IsMemory() { 366 continue 367 } 368 if m := v.MemoryArg(); m != nil { 369 ss.add(m.ID) 370 } 371 } 372 // There should be at most one remaining unoverwritten memory value. 373 for _, v := range b.Values { 374 if !v.Type.IsMemory() { 375 continue 376 } 377 if ss.contains(v.ID) { 378 continue 379 } 380 if lastmem[b.ID] != nil { 381 f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], v) 382 } 383 lastmem[b.ID] = v 384 } 385 // If there is no remaining memory value, that means there was no memory update. 386 // Take any memory arg. 387 if lastmem[b.ID] == nil { 388 for _, v := range b.Values { 389 if v.Op == OpPhi { 390 continue 391 } 392 m := v.MemoryArg() 393 if m == nil { 394 continue 395 } 396 if lastmem[b.ID] != nil && lastmem[b.ID] != m { 397 f.Fatalf("two live memory values in %s: %s and %s", b, lastmem[b.ID], m) 398 } 399 lastmem[b.ID] = m 400 } 401 } 402 } 403 // Propagate last live memory through storeless blocks. 404 for { 405 changed := false 406 for _, b := range f.Blocks { 407 if lastmem[b.ID] != nil { 408 continue 409 } 410 for _, e := range b.Preds { 411 p := e.b 412 if lastmem[p.ID] != nil { 413 lastmem[b.ID] = lastmem[p.ID] 414 changed = true 415 break 416 } 417 } 418 } 419 if !changed { 420 break 421 } 422 } 423 // Check merge points. 424 for _, b := range f.Blocks { 425 for _, v := range b.Values { 426 if v.Op == OpPhi && v.Type.IsMemory() { 427 for i, a := range v.Args { 428 if a != lastmem[b.Preds[i].b.ID] { 429 f.Fatalf("inconsistent memory phi %s %d %s %s", v.LongString(), i, a, lastmem[b.Preds[i].b.ID]) 430 } 431 } 432 } 433 } 434 } 435 436 // Check that only one memory is live at any point. 437 if f.scheduled { 438 for _, b := range f.Blocks { 439 var mem *Value // the current live memory in the block 440 for _, v := range b.Values { 441 if v.Op == OpPhi { 442 if v.Type.IsMemory() { 443 mem = v 444 } 445 continue 446 } 447 if mem == nil && len(b.Preds) > 0 { 448 // If no mem phi, take mem of any predecessor. 449 mem = lastmem[b.Preds[0].b.ID] 450 } 451 for _, a := range v.Args { 452 if a.Type.IsMemory() && a != mem { 453 f.Fatalf("two live mems @ %s: %s and %s", v, mem, a) 454 } 455 } 456 if v.Type.IsMemory() { 457 mem = v 458 } 459 } 460 } 461 } 462 463 // Check that after scheduling, phis are always first in the block. 464 if f.scheduled { 465 for _, b := range f.Blocks { 466 seenNonPhi := false 467 for _, v := range b.Values { 468 switch v.Op { 469 case OpPhi: 470 if seenNonPhi { 471 f.Fatalf("phi after non-phi @ %s: %s", b, v) 472 } 473 default: 474 seenNonPhi = true 475 } 476 } 477 } 478 } 479 } 480 481 // domCheck reports whether x dominates y (including x==y). 482 func domCheck(f *Func, sdom SparseTree, x, y *Block) bool { 483 if !sdom.isAncestorEq(f.Entry, y) { 484 // unreachable - ignore 485 return true 486 } 487 return sdom.isAncestorEq(x, y) 488 } 489 490 // isExactFloat32 reports whether v has an AuxInt that can be exactly represented as a float32. 491 func isExactFloat32(v *Value) bool { 492 x := v.AuxFloat() 493 return math.Float64bits(x) == math.Float64bits(float64(float32(x))) 494 }