github.com/llvm-mirror/llgo@v0.0.0-20190322182713-bf6f0a60fce1/third_party/gotools/go/ssa/sanity.go (about) 1 // Copyright 2013 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 // An optional pass for sanity-checking invariants of the SSA representation. 8 // Currently it checks CFG invariants but little at the instruction level. 9 10 import ( 11 "fmt" 12 "io" 13 "os" 14 "strings" 15 16 "llvm.org/llgo/third_party/gotools/go/types" 17 ) 18 19 type sanity struct { 20 reporter io.Writer 21 fn *Function 22 block *BasicBlock 23 instrs map[Instruction]struct{} 24 insane bool 25 } 26 27 // sanityCheck performs integrity checking of the SSA representation 28 // of the function fn and returns true if it was valid. Diagnostics 29 // are written to reporter if non-nil, os.Stderr otherwise. Some 30 // diagnostics are only warnings and do not imply a negative result. 31 // 32 // Sanity-checking is intended to facilitate the debugging of code 33 // transformation passes. 34 // 35 func sanityCheck(fn *Function, reporter io.Writer) bool { 36 if reporter == nil { 37 reporter = os.Stderr 38 } 39 return (&sanity{reporter: reporter}).checkFunction(fn) 40 } 41 42 // mustSanityCheck is like sanityCheck but panics instead of returning 43 // a negative result. 44 // 45 func mustSanityCheck(fn *Function, reporter io.Writer) { 46 if !sanityCheck(fn, reporter) { 47 fn.WriteTo(os.Stderr) 48 panic("SanityCheck failed") 49 } 50 } 51 52 func (s *sanity) diagnostic(prefix, format string, args ...interface{}) { 53 fmt.Fprintf(s.reporter, "%s: function %s", prefix, s.fn) 54 if s.block != nil { 55 fmt.Fprintf(s.reporter, ", block %s", s.block) 56 } 57 io.WriteString(s.reporter, ": ") 58 fmt.Fprintf(s.reporter, format, args...) 59 io.WriteString(s.reporter, "\n") 60 } 61 62 func (s *sanity) errorf(format string, args ...interface{}) { 63 s.insane = true 64 s.diagnostic("Error", format, args...) 65 } 66 67 func (s *sanity) warnf(format string, args ...interface{}) { 68 s.diagnostic("Warning", format, args...) 69 } 70 71 // findDuplicate returns an arbitrary basic block that appeared more 72 // than once in blocks, or nil if all were unique. 73 func findDuplicate(blocks []*BasicBlock) *BasicBlock { 74 if len(blocks) < 2 { 75 return nil 76 } 77 if blocks[0] == blocks[1] { 78 return blocks[0] 79 } 80 // Slow path: 81 m := make(map[*BasicBlock]bool) 82 for _, b := range blocks { 83 if m[b] { 84 return b 85 } 86 m[b] = true 87 } 88 return nil 89 } 90 91 func (s *sanity) checkInstr(idx int, instr Instruction) { 92 switch instr := instr.(type) { 93 case *If, *Jump, *Return, *Panic: 94 s.errorf("control flow instruction not at end of block") 95 case *Phi: 96 if idx == 0 { 97 // It suffices to apply this check to just the first phi node. 98 if dup := findDuplicate(s.block.Preds); dup != nil { 99 s.errorf("phi node in block with duplicate predecessor %s", dup) 100 } 101 } else { 102 prev := s.block.Instrs[idx-1] 103 if _, ok := prev.(*Phi); !ok { 104 s.errorf("Phi instruction follows a non-Phi: %T", prev) 105 } 106 } 107 if ne, np := len(instr.Edges), len(s.block.Preds); ne != np { 108 s.errorf("phi node has %d edges but %d predecessors", ne, np) 109 110 } else { 111 for i, e := range instr.Edges { 112 if e == nil { 113 s.errorf("phi node '%s' has no value for edge #%d from %s", instr.Comment, i, s.block.Preds[i]) 114 } 115 } 116 } 117 118 case *Alloc: 119 if !instr.Heap { 120 found := false 121 for _, l := range s.fn.Locals { 122 if l == instr { 123 found = true 124 break 125 } 126 } 127 if !found { 128 s.errorf("local alloc %s = %s does not appear in Function.Locals", instr.Name(), instr) 129 } 130 } 131 132 case *BinOp: 133 case *Call: 134 case *ChangeInterface: 135 case *ChangeType: 136 case *Convert: 137 if _, ok := instr.X.Type().Underlying().(*types.Basic); !ok { 138 if _, ok := instr.Type().Underlying().(*types.Basic); !ok { 139 s.errorf("convert %s -> %s: at least one type must be basic", instr.X.Type(), instr.Type()) 140 } 141 } 142 143 case *Defer: 144 case *Extract: 145 case *Field: 146 case *FieldAddr: 147 case *Go: 148 case *Index: 149 case *IndexAddr: 150 case *Lookup: 151 case *MakeChan: 152 case *MakeClosure: 153 numFree := len(instr.Fn.(*Function).FreeVars) 154 numBind := len(instr.Bindings) 155 if numFree != numBind { 156 s.errorf("MakeClosure has %d Bindings for function %s with %d free vars", 157 numBind, instr.Fn, numFree) 158 159 } 160 if recv := instr.Type().(*types.Signature).Recv(); recv != nil { 161 s.errorf("MakeClosure's type includes receiver %s", recv.Type()) 162 } 163 164 case *MakeInterface: 165 case *MakeMap: 166 case *MakeSlice: 167 case *MapUpdate: 168 case *Next: 169 case *Range: 170 case *RunDefers: 171 case *Select: 172 case *Send: 173 case *Slice: 174 case *Store: 175 case *TypeAssert: 176 case *UnOp: 177 case *DebugRef: 178 // TODO(adonovan): implement checks. 179 default: 180 panic(fmt.Sprintf("Unknown instruction type: %T", instr)) 181 } 182 183 if call, ok := instr.(CallInstruction); ok { 184 if call.Common().Signature() == nil { 185 s.errorf("nil signature: %s", call) 186 } 187 } 188 189 // Check that value-defining instructions have valid types 190 // and a valid referrer list. 191 if v, ok := instr.(Value); ok { 192 t := v.Type() 193 if t == nil { 194 s.errorf("no type: %s = %s", v.Name(), v) 195 } else if t == tRangeIter { 196 // not a proper type; ignore. 197 } else if b, ok := t.Underlying().(*types.Basic); ok && b.Info()&types.IsUntyped != 0 { 198 s.errorf("instruction has 'untyped' result: %s = %s : %s", v.Name(), v, t) 199 } 200 s.checkReferrerList(v) 201 } 202 203 // Untyped constants are legal as instruction Operands(), 204 // for example: 205 // _ = "foo"[0] 206 // or: 207 // if wordsize==64 {...} 208 209 // All other non-Instruction Values can be found via their 210 // enclosing Function or Package. 211 } 212 213 func (s *sanity) checkFinalInstr(idx int, instr Instruction) { 214 switch instr := instr.(type) { 215 case *If: 216 if nsuccs := len(s.block.Succs); nsuccs != 2 { 217 s.errorf("If-terminated block has %d successors; expected 2", nsuccs) 218 return 219 } 220 if s.block.Succs[0] == s.block.Succs[1] { 221 s.errorf("If-instruction has same True, False target blocks: %s", s.block.Succs[0]) 222 return 223 } 224 225 case *Jump: 226 if nsuccs := len(s.block.Succs); nsuccs != 1 { 227 s.errorf("Jump-terminated block has %d successors; expected 1", nsuccs) 228 return 229 } 230 231 case *Return: 232 if nsuccs := len(s.block.Succs); nsuccs != 0 { 233 s.errorf("Return-terminated block has %d successors; expected none", nsuccs) 234 return 235 } 236 if na, nf := len(instr.Results), s.fn.Signature.Results().Len(); nf != na { 237 s.errorf("%d-ary return in %d-ary function", na, nf) 238 } 239 240 case *Panic: 241 if nsuccs := len(s.block.Succs); nsuccs != 0 { 242 s.errorf("Panic-terminated block has %d successors; expected none", nsuccs) 243 return 244 } 245 246 default: 247 s.errorf("non-control flow instruction at end of block") 248 } 249 } 250 251 func (s *sanity) checkBlock(b *BasicBlock, index int) { 252 s.block = b 253 254 if b.Index != index { 255 s.errorf("block has incorrect Index %d", b.Index) 256 } 257 if b.parent != s.fn { 258 s.errorf("block has incorrect parent %s", b.parent) 259 } 260 261 // Check all blocks are reachable. 262 // (The entry block is always implicitly reachable, 263 // as is the Recover block, if any.) 264 if (index > 0 && b != b.parent.Recover) && len(b.Preds) == 0 { 265 s.warnf("unreachable block") 266 if b.Instrs == nil { 267 // Since this block is about to be pruned, 268 // tolerating transient problems in it 269 // simplifies other optimizations. 270 return 271 } 272 } 273 274 // Check predecessor and successor relations are dual, 275 // and that all blocks in CFG belong to same function. 276 for _, a := range b.Preds { 277 found := false 278 for _, bb := range a.Succs { 279 if bb == b { 280 found = true 281 break 282 } 283 } 284 if !found { 285 s.errorf("expected successor edge in predecessor %s; found only: %s", a, a.Succs) 286 } 287 if a.parent != s.fn { 288 s.errorf("predecessor %s belongs to different function %s", a, a.parent) 289 } 290 } 291 for _, c := range b.Succs { 292 found := false 293 for _, bb := range c.Preds { 294 if bb == b { 295 found = true 296 break 297 } 298 } 299 if !found { 300 s.errorf("expected predecessor edge in successor %s; found only: %s", c, c.Preds) 301 } 302 if c.parent != s.fn { 303 s.errorf("successor %s belongs to different function %s", c, c.parent) 304 } 305 } 306 307 // Check each instruction is sane. 308 n := len(b.Instrs) 309 if n == 0 { 310 s.errorf("basic block contains no instructions") 311 } 312 var rands [10]*Value // reuse storage 313 for j, instr := range b.Instrs { 314 if instr == nil { 315 s.errorf("nil instruction at index %d", j) 316 continue 317 } 318 if b2 := instr.Block(); b2 == nil { 319 s.errorf("nil Block() for instruction at index %d", j) 320 continue 321 } else if b2 != b { 322 s.errorf("wrong Block() (%s) for instruction at index %d ", b2, j) 323 continue 324 } 325 if j < n-1 { 326 s.checkInstr(j, instr) 327 } else { 328 s.checkFinalInstr(j, instr) 329 } 330 331 // Check Instruction.Operands. 332 operands: 333 for i, op := range instr.Operands(rands[:0]) { 334 if op == nil { 335 s.errorf("nil operand pointer %d of %s", i, instr) 336 continue 337 } 338 val := *op 339 if val == nil { 340 continue // a nil operand is ok 341 } 342 343 // Check that "untyped" types only appear on constant operands. 344 if _, ok := (*op).(*Const); !ok { 345 if basic, ok := (*op).Type().(*types.Basic); ok { 346 if basic.Info()&types.IsUntyped != 0 { 347 s.errorf("operand #%d of %s is untyped: %s", i, instr, basic) 348 } 349 } 350 } 351 352 // Check that Operands that are also Instructions belong to same function. 353 // TODO(adonovan): also check their block dominates block b. 354 if val, ok := val.(Instruction); ok { 355 if val.Parent() != s.fn { 356 s.errorf("operand %d of %s is an instruction (%s) from function %s", i, instr, val, val.Parent()) 357 } 358 } 359 360 // Check that each function-local operand of 361 // instr refers back to instr. (NB: quadratic) 362 switch val := val.(type) { 363 case *Const, *Global, *Builtin: 364 continue // not local 365 case *Function: 366 if val.parent == nil { 367 continue // only anon functions are local 368 } 369 } 370 371 // TODO(adonovan): check val.Parent() != nil <=> val.Referrers() is defined. 372 373 if refs := val.Referrers(); refs != nil { 374 for _, ref := range *refs { 375 if ref == instr { 376 continue operands 377 } 378 } 379 s.errorf("operand %d of %s (%s) does not refer to us", i, instr, val) 380 } else { 381 s.errorf("operand %d of %s (%s) has no referrers", i, instr, val) 382 } 383 } 384 } 385 } 386 387 func (s *sanity) checkReferrerList(v Value) { 388 refs := v.Referrers() 389 if refs == nil { 390 s.errorf("%s has missing referrer list", v.Name()) 391 return 392 } 393 for i, ref := range *refs { 394 if _, ok := s.instrs[ref]; !ok { 395 s.errorf("%s.Referrers()[%d] = %s is not an instruction belonging to this function", v.Name(), i, ref) 396 } 397 } 398 } 399 400 func (s *sanity) checkFunction(fn *Function) bool { 401 // TODO(adonovan): check Function invariants: 402 // - check params match signature 403 // - check transient fields are nil 404 // - warn if any fn.Locals do not appear among block instructions. 405 s.fn = fn 406 if fn.Prog == nil { 407 s.errorf("nil Prog") 408 } 409 410 fn.String() // must not crash 411 fn.RelString(fn.pkgobj()) // must not crash 412 413 // All functions have a package, except delegates (which are 414 // shared across packages, or duplicated as weak symbols in a 415 // separate-compilation model), and error.Error. 416 if fn.Pkg == nil { 417 if strings.HasPrefix(fn.Synthetic, "wrapper ") || 418 strings.HasPrefix(fn.Synthetic, "bound ") || 419 strings.HasPrefix(fn.Synthetic, "thunk ") || 420 strings.HasSuffix(fn.name, "Error") { 421 // ok 422 } else { 423 s.errorf("nil Pkg") 424 } 425 } 426 if src, syn := fn.Synthetic == "", fn.Syntax() != nil; src != syn { 427 s.errorf("got fromSource=%t, hasSyntax=%t; want same values", src, syn) 428 } 429 for i, l := range fn.Locals { 430 if l.Parent() != fn { 431 s.errorf("Local %s at index %d has wrong parent", l.Name(), i) 432 } 433 if l.Heap { 434 s.errorf("Local %s at index %d has Heap flag set", l.Name(), i) 435 } 436 } 437 // Build the set of valid referrers. 438 s.instrs = make(map[Instruction]struct{}) 439 for _, b := range fn.Blocks { 440 for _, instr := range b.Instrs { 441 s.instrs[instr] = struct{}{} 442 } 443 } 444 for i, p := range fn.Params { 445 if p.Parent() != fn { 446 s.errorf("Param %s at index %d has wrong parent", p.Name(), i) 447 } 448 s.checkReferrerList(p) 449 } 450 for i, fv := range fn.FreeVars { 451 if fv.Parent() != fn { 452 s.errorf("FreeVar %s at index %d has wrong parent", fv.Name(), i) 453 } 454 s.checkReferrerList(fv) 455 } 456 457 if fn.Blocks != nil && len(fn.Blocks) == 0 { 458 // Function _had_ blocks (so it's not external) but 459 // they were "optimized" away, even the entry block. 460 s.errorf("Blocks slice is non-nil but empty") 461 } 462 for i, b := range fn.Blocks { 463 if b == nil { 464 s.warnf("nil *BasicBlock at f.Blocks[%d]", i) 465 continue 466 } 467 s.checkBlock(b, i) 468 } 469 if fn.Recover != nil && fn.Blocks[fn.Recover.Index] != fn.Recover { 470 s.errorf("Recover block is not in Blocks slice") 471 } 472 473 s.block = nil 474 for i, anon := range fn.AnonFuncs { 475 if anon.Parent() != fn { 476 s.errorf("AnonFuncs[%d]=%s but %s.Parent()=%s", i, anon, anon, anon.Parent()) 477 } 478 } 479 s.fn = nil 480 return !s.insane 481 } 482 483 // sanityCheckPackage checks invariants of packages upon creation. 484 // It does not require that the package is built. 485 // Unlike sanityCheck (for functions), it just panics at the first error. 486 func sanityCheckPackage(pkg *Package) { 487 if pkg.Object == nil { 488 panic(fmt.Sprintf("Package %s has no Object", pkg)) 489 } 490 pkg.String() // must not crash 491 492 for name, mem := range pkg.Members { 493 if name != mem.Name() { 494 panic(fmt.Sprintf("%s: %T.Name() = %s, want %s", 495 pkg.Object.Path(), mem, mem.Name(), name)) 496 } 497 obj := mem.Object() 498 if obj == nil { 499 // This check is sound because fields 500 // {Global,Function}.object have type 501 // types.Object. (If they were declared as 502 // *types.{Var,Func}, we'd have a non-empty 503 // interface containing a nil pointer.) 504 505 continue // not all members have typechecker objects 506 } 507 if obj.Name() != name { 508 if obj.Name() == "init" && strings.HasPrefix(mem.Name(), "init#") { 509 // Ok. The name of a declared init function varies between 510 // its types.Func ("init") and its ssa.Function ("init#%d"). 511 } else { 512 panic(fmt.Sprintf("%s: %T.Object().Name() = %s, want %s", 513 pkg.Object.Path(), mem, obj.Name(), name)) 514 } 515 } 516 if obj.Pos() != mem.Pos() { 517 panic(fmt.Sprintf("%s Pos=%d obj.Pos=%d", mem, mem.Pos(), obj.Pos())) 518 } 519 } 520 }