github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/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 // checkFunc checks invariants of f. 8 func checkFunc(f *Func) { 9 blockMark := make([]bool, f.NumBlocks()) 10 valueMark := make([]bool, f.NumValues()) 11 12 for _, b := range f.Blocks { 13 if blockMark[b.ID] { 14 f.Fatalf("block %s appears twice in %s!", b, f.Name) 15 } 16 blockMark[b.ID] = true 17 if b.Func != f { 18 f.Fatalf("%s.Func=%s, want %s", b, b.Func.Name, f.Name) 19 } 20 21 if f.RegAlloc == nil { 22 for i, c := range b.Succs { 23 for j, d := range b.Succs { 24 if i != j && c == d { 25 f.Fatalf("%s.Succs has duplicate block %s", b, c) 26 } 27 } 28 } 29 } 30 // Note: duplicate successors are hard in the following case: 31 // if(...) goto x else goto x 32 // x: v = phi(a, b) 33 // If the conditional is true, does v get the value of a or b? 34 // We could solve this other ways, but the easiest is just to 35 // require (by possibly adding empty control-flow blocks) that 36 // all successors are distinct. They will need to be distinct 37 // anyway for register allocation (duplicate successors implies 38 // the existence of critical edges). 39 // After regalloc we can allow non-distinct predecessors. 40 41 for _, p := range b.Preds { 42 var found bool 43 for _, c := range p.Succs { 44 if c == b { 45 found = true 46 break 47 } 48 } 49 if !found { 50 f.Fatalf("block %s is not a succ of its pred block %s", b, p) 51 } 52 } 53 54 switch b.Kind { 55 case BlockExit: 56 if len(b.Succs) != 0 { 57 f.Fatalf("exit block %s has successors", b) 58 } 59 if b.Control == nil { 60 f.Fatalf("exit block %s has no control value", b) 61 } 62 if !b.Control.Type.IsMemory() { 63 f.Fatalf("exit block %s has non-memory control value %s", b, b.Control.LongString()) 64 } 65 case BlockRet: 66 if len(b.Succs) != 0 { 67 f.Fatalf("ret block %s has successors", b) 68 } 69 if b.Control == nil { 70 f.Fatalf("ret block %s has nil control %s", b) 71 } 72 if !b.Control.Type.IsMemory() { 73 f.Fatalf("ret block %s has non-memory control value %s", b, b.Control.LongString()) 74 } 75 case BlockRetJmp: 76 if len(b.Succs) != 0 { 77 f.Fatalf("retjmp block %s len(Succs)==%d, want 0", b, len(b.Succs)) 78 } 79 if b.Control == nil { 80 f.Fatalf("retjmp block %s has nil control %s", b) 81 } 82 if !b.Control.Type.IsMemory() { 83 f.Fatalf("retjmp block %s has non-memory control value %s", b, b.Control.LongString()) 84 } 85 if b.Aux == nil { 86 f.Fatalf("retjmp block %s has nil Aux field", b) 87 } 88 case BlockDead: 89 if len(b.Succs) != 0 { 90 f.Fatalf("dead block %s has successors", b) 91 } 92 if len(b.Preds) != 0 { 93 f.Fatalf("dead block %s has predecessors", b) 94 } 95 if len(b.Values) != 0 { 96 f.Fatalf("dead block %s has values", b) 97 } 98 if b.Control != nil { 99 f.Fatalf("dead block %s has a control value", b) 100 } 101 case BlockPlain: 102 if len(b.Succs) != 1 { 103 f.Fatalf("plain block %s len(Succs)==%d, want 1", b, len(b.Succs)) 104 } 105 if b.Control != nil { 106 f.Fatalf("plain block %s has non-nil control %s", b, b.Control.LongString()) 107 } 108 case BlockIf: 109 if len(b.Succs) != 2 { 110 f.Fatalf("if block %s len(Succs)==%d, want 2", b, len(b.Succs)) 111 } 112 if b.Control == nil { 113 f.Fatalf("if block %s has no control value", b) 114 } 115 if !b.Control.Type.IsBoolean() { 116 f.Fatalf("if block %s has non-bool control value %s", b, b.Control.LongString()) 117 } 118 case BlockCall: 119 if len(b.Succs) != 1 { 120 f.Fatalf("call block %s len(Succs)==%d, want 1", b, len(b.Succs)) 121 } 122 if b.Control == nil { 123 f.Fatalf("call block %s has no control value", b) 124 } 125 if !b.Control.Type.IsMemory() { 126 f.Fatalf("call block %s has non-memory control value %s", b, b.Control.LongString()) 127 } 128 case BlockDefer: 129 if len(b.Succs) != 2 { 130 f.Fatalf("defer block %s len(Succs)==%d, want 2", b, len(b.Succs)) 131 } 132 if b.Control == nil { 133 f.Fatalf("defer block %s has no control value", b) 134 } 135 if !b.Control.Type.IsMemory() { 136 f.Fatalf("defer block %s has non-memory control value %s", b, b.Control.LongString()) 137 } 138 case BlockCheck: 139 if len(b.Succs) != 1 { 140 f.Fatalf("check block %s len(Succs)==%d, want 1", b, len(b.Succs)) 141 } 142 if b.Control == nil { 143 f.Fatalf("check block %s has no control value", b) 144 } 145 if !b.Control.Type.IsVoid() { 146 f.Fatalf("check block %s has non-void control value %s", b, b.Control.LongString()) 147 } 148 case BlockFirst: 149 if len(b.Succs) != 2 { 150 f.Fatalf("plain/dead block %s len(Succs)==%d, want 2", b, len(b.Succs)) 151 } 152 if b.Control != nil { 153 f.Fatalf("plain/dead block %s has a control value", b) 154 } 155 } 156 if len(b.Succs) > 2 && b.Likely != BranchUnknown { 157 f.Fatalf("likeliness prediction %d for block %s with %d successors: %s", b.Likely, b, len(b.Succs)) 158 } 159 160 for _, v := range b.Values { 161 // Check to make sure argument count makes sense (argLen of -1 indicates 162 // variable length args) 163 nArgs := opcodeTable[v.Op].argLen 164 if nArgs != -1 && int32(len(v.Args)) != nArgs { 165 f.Fatalf("value %v has %d args, expected %d", v.LongString(), 166 len(v.Args), nArgs) 167 } 168 169 // Check to make sure aux values make sense. 170 canHaveAux := false 171 canHaveAuxInt := false 172 switch opcodeTable[v.Op].auxType { 173 case auxNone: 174 case auxBool: 175 if v.AuxInt < 0 || v.AuxInt > 1 { 176 f.Fatalf("bad bool AuxInt value for %v", v) 177 } 178 canHaveAuxInt = true 179 case auxInt8: 180 if v.AuxInt != int64(int8(v.AuxInt)) { 181 f.Fatalf("bad int8 AuxInt value for %v", v) 182 } 183 canHaveAuxInt = true 184 case auxInt16: 185 if v.AuxInt != int64(int16(v.AuxInt)) { 186 f.Fatalf("bad int16 AuxInt value for %v", v) 187 } 188 canHaveAuxInt = true 189 case auxInt32: 190 if v.AuxInt != int64(int32(v.AuxInt)) { 191 f.Fatalf("bad int32 AuxInt value for %v", v) 192 } 193 canHaveAuxInt = true 194 case auxInt64, auxFloat64: 195 canHaveAuxInt = true 196 case auxFloat32: 197 canHaveAuxInt = true 198 if !isExactFloat32(v) { 199 f.Fatalf("value %v has an AuxInt value that is not an exact float32", v) 200 } 201 case auxString, auxSym: 202 canHaveAux = true 203 case auxSymOff, auxSymValAndOff: 204 canHaveAuxInt = true 205 canHaveAux = true 206 default: 207 f.Fatalf("unknown aux type for %s", v.Op) 208 } 209 if !canHaveAux && v.Aux != nil { 210 f.Fatalf("value %v has an Aux value %v but shouldn't", v.LongString(), v.Aux) 211 } 212 if !canHaveAuxInt && v.AuxInt != 0 { 213 f.Fatalf("value %v has an AuxInt value %d but shouldn't", v.LongString(), v.AuxInt) 214 } 215 216 for _, arg := range v.Args { 217 if arg == nil { 218 f.Fatalf("value %v has nil arg", v.LongString()) 219 } 220 } 221 222 if valueMark[v.ID] { 223 f.Fatalf("value %s appears twice!", v.LongString()) 224 } 225 valueMark[v.ID] = true 226 227 if v.Block != b { 228 f.Fatalf("%s.block != %s", v, b) 229 } 230 if v.Op == OpPhi && len(v.Args) != len(b.Preds) { 231 f.Fatalf("phi length %s does not match pred length %d for block %s", v.LongString(), len(b.Preds), b) 232 } 233 234 if v.Op == OpAddr { 235 if len(v.Args) == 0 { 236 f.Fatalf("no args for OpAddr %s", v.LongString()) 237 } 238 if v.Args[0].Op != OpSP && v.Args[0].Op != OpSB { 239 f.Fatalf("bad arg to OpAddr %v", v) 240 } 241 } 242 243 // TODO: check for cycles in values 244 // TODO: check type 245 } 246 } 247 248 // Check to make sure all Blocks referenced are in the function. 249 if !blockMark[f.Entry.ID] { 250 f.Fatalf("entry block %v is missing", f.Entry) 251 } 252 for _, b := range f.Blocks { 253 for _, c := range b.Preds { 254 if !blockMark[c.ID] { 255 f.Fatalf("predecessor block %v for %v is missing", c, b) 256 } 257 } 258 for _, c := range b.Succs { 259 if !blockMark[c.ID] { 260 f.Fatalf("successor block %v for %v is missing", c, b) 261 } 262 } 263 } 264 265 if len(f.Entry.Preds) > 0 { 266 f.Fatalf("entry block %s of %s has predecessor(s) %v", f.Entry, f.Name, f.Entry.Preds) 267 } 268 269 // Check to make sure all Values referenced are in the function. 270 for _, b := range f.Blocks { 271 for _, v := range b.Values { 272 for i, a := range v.Args { 273 if !valueMark[a.ID] { 274 f.Fatalf("%v, arg %d of %v, is missing", a, i, v) 275 } 276 } 277 } 278 if b.Control != nil && !valueMark[b.Control.ID] { 279 f.Fatalf("control value for %s is missing: %v", b, b.Control) 280 } 281 } 282 for b := f.freeBlocks; b != nil; b = b.succstorage[0] { 283 if blockMark[b.ID] { 284 f.Fatalf("used block b%d in free list", b.ID) 285 } 286 } 287 for v := f.freeValues; v != nil; v = v.argstorage[0] { 288 if valueMark[v.ID] { 289 f.Fatalf("used value v%d in free list", v.ID) 290 } 291 } 292 293 // Check to make sure all args dominate uses. 294 if f.RegAlloc == nil { 295 // Note: regalloc introduces non-dominating args. 296 // See TODO in regalloc.go. 297 idom := dominators(f) 298 sdom := newSparseTree(f, idom) 299 for _, b := range f.Blocks { 300 for _, v := range b.Values { 301 for i, arg := range v.Args { 302 x := arg.Block 303 y := b 304 if v.Op == OpPhi { 305 y = b.Preds[i] 306 } 307 if !domCheck(f, sdom, x, y) { 308 f.Fatalf("arg %d of value %s does not dominate, arg=%s", i, v.LongString(), arg.LongString()) 309 } 310 } 311 } 312 if b.Control != nil && !domCheck(f, sdom, b.Control.Block, b) { 313 f.Fatalf("control value %s for %s doesn't dominate", b.Control, b) 314 } 315 } 316 } 317 318 // Check use counts 319 uses := make([]int32, f.NumValues()) 320 for _, b := range f.Blocks { 321 for _, v := range b.Values { 322 for _, a := range v.Args { 323 uses[a.ID]++ 324 } 325 } 326 if b.Control != nil { 327 uses[b.Control.ID]++ 328 } 329 } 330 for _, b := range f.Blocks { 331 for _, v := range b.Values { 332 if v.Uses != uses[v.ID] { 333 f.Fatalf("%s has %d uses, but has Uses=%d", v, uses[v.ID], v.Uses) 334 } 335 } 336 } 337 } 338 339 // domCheck reports whether x dominates y (including x==y). 340 func domCheck(f *Func, sdom sparseTree, x, y *Block) bool { 341 if !sdom.isAncestorEq(y, f.Entry) { 342 // unreachable - ignore 343 return true 344 } 345 return sdom.isAncestorEq(x, y) 346 } 347 348 // isExactFloat32 reoprts whether v has an AuxInt that can be exactly represented as a float32. 349 func isExactFloat32(v *Value) bool { 350 return v.AuxFloat() == float64(float32(v.AuxFloat())) 351 }