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