github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/cmd/compile/internal/ssa/dom_test.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 "testing" 8 9 func BenchmarkDominatorsLinear(b *testing.B) { benchmarkDominators(b, 10000, genLinear) } 10 func BenchmarkDominatorsFwdBack(b *testing.B) { benchmarkDominators(b, 10000, genFwdBack) } 11 func BenchmarkDominatorsManyPred(b *testing.B) { benchmarkDominators(b, 10000, genManyPred) } 12 func BenchmarkDominatorsMaxPred(b *testing.B) { benchmarkDominators(b, 10000, genMaxPred) } 13 func BenchmarkDominatorsMaxPredVal(b *testing.B) { benchmarkDominators(b, 10000, genMaxPredValue) } 14 15 type blockGen func(size int) []bloc 16 17 // genLinear creates an array of blocks that succeed one another 18 // b_n -> [b_n+1]. 19 func genLinear(size int) []bloc { 20 var blocs []bloc 21 blocs = append(blocs, 22 Bloc("entry", 23 Valu("mem", OpInitMem, TypeMem, 0, nil), 24 Goto(blockn(0)), 25 ), 26 ) 27 for i := 0; i < size; i++ { 28 blocs = append(blocs, Bloc(blockn(i), 29 Goto(blockn(i+1)))) 30 } 31 32 blocs = append(blocs, 33 Bloc(blockn(size), Goto("exit")), 34 Bloc("exit", Exit("mem")), 35 ) 36 37 return blocs 38 } 39 40 // genLinear creates an array of blocks that alternate between 41 // b_n -> [b_n+1], b_n -> [b_n+1, b_n-1] , b_n -> [b_n+1, b_n+2] 42 func genFwdBack(size int) []bloc { 43 var blocs []bloc 44 blocs = append(blocs, 45 Bloc("entry", 46 Valu("mem", OpInitMem, TypeMem, 0, nil), 47 Valu("p", OpConstBool, TypeBool, 1, nil), 48 Goto(blockn(0)), 49 ), 50 ) 51 for i := 0; i < size; i++ { 52 switch i % 2 { 53 case 0: 54 blocs = append(blocs, Bloc(blockn(i), 55 If("p", blockn(i+1), blockn(i+2)))) 56 case 1: 57 blocs = append(blocs, Bloc(blockn(i), 58 If("p", blockn(i+1), blockn(i-1)))) 59 } 60 } 61 62 blocs = append(blocs, 63 Bloc(blockn(size), Goto("exit")), 64 Bloc("exit", Exit("mem")), 65 ) 66 67 return blocs 68 } 69 70 // genManyPred creates an array of blocks where 1/3rd have a successor of the 71 // first block, 1/3rd the last block, and the remaining third are plain. 72 func genManyPred(size int) []bloc { 73 var blocs []bloc 74 blocs = append(blocs, 75 Bloc("entry", 76 Valu("mem", OpInitMem, TypeMem, 0, nil), 77 Valu("p", OpConstBool, TypeBool, 1, nil), 78 Goto(blockn(0)), 79 ), 80 ) 81 82 // We want predecessor lists to be long, so 2/3rds of the blocks have a 83 // successor of the first or last block. 84 for i := 0; i < size; i++ { 85 switch i % 3 { 86 case 0: 87 blocs = append(blocs, Bloc(blockn(i), 88 Valu("a", OpConstBool, TypeBool, 1, nil), 89 Goto(blockn(i+1)))) 90 case 1: 91 blocs = append(blocs, Bloc(blockn(i), 92 Valu("a", OpConstBool, TypeBool, 1, nil), 93 If("p", blockn(i+1), blockn(0)))) 94 case 2: 95 blocs = append(blocs, Bloc(blockn(i), 96 Valu("a", OpConstBool, TypeBool, 1, nil), 97 If("p", blockn(i+1), blockn(size)))) 98 } 99 } 100 101 blocs = append(blocs, 102 Bloc(blockn(size), Goto("exit")), 103 Bloc("exit", Exit("mem")), 104 ) 105 106 return blocs 107 } 108 109 // genMaxPred maximizes the size of the 'exit' predecessor list. 110 func genMaxPred(size int) []bloc { 111 var blocs []bloc 112 blocs = append(blocs, 113 Bloc("entry", 114 Valu("mem", OpInitMem, TypeMem, 0, nil), 115 Valu("p", OpConstBool, TypeBool, 1, nil), 116 Goto(blockn(0)), 117 ), 118 ) 119 120 for i := 0; i < size; i++ { 121 blocs = append(blocs, Bloc(blockn(i), 122 If("p", blockn(i+1), "exit"))) 123 } 124 125 blocs = append(blocs, 126 Bloc(blockn(size), Goto("exit")), 127 Bloc("exit", Exit("mem")), 128 ) 129 130 return blocs 131 } 132 133 // genMaxPredValue is identical to genMaxPred but contains an 134 // additional value. 135 func genMaxPredValue(size int) []bloc { 136 var blocs []bloc 137 blocs = append(blocs, 138 Bloc("entry", 139 Valu("mem", OpInitMem, TypeMem, 0, nil), 140 Valu("p", OpConstBool, TypeBool, 1, nil), 141 Goto(blockn(0)), 142 ), 143 ) 144 145 for i := 0; i < size; i++ { 146 blocs = append(blocs, Bloc(blockn(i), 147 Valu("a", OpConstBool, TypeBool, 1, nil), 148 If("p", blockn(i+1), "exit"))) 149 } 150 151 blocs = append(blocs, 152 Bloc(blockn(size), Goto("exit")), 153 Bloc("exit", Exit("mem")), 154 ) 155 156 return blocs 157 } 158 159 // sink for benchmark 160 var domBenchRes []*Block 161 162 func benchmarkDominators(b *testing.B, size int, bg blockGen) { 163 c := NewConfig("amd64", DummyFrontend{b}, nil, true) 164 fun := Fun(c, "entry", bg(size)...) 165 166 CheckFunc(fun.f) 167 b.SetBytes(int64(size)) 168 b.ResetTimer() 169 for i := 0; i < b.N; i++ { 170 domBenchRes = dominators(fun.f) 171 } 172 } 173 174 type domFunc func(f *Func) []*Block 175 176 // verifyDominators verifies that the dominators of fut (function under test) 177 // as determined by domFn, match the map node->dominator 178 func verifyDominators(t *testing.T, fut fun, domFn domFunc, doms map[string]string) { 179 blockNames := map[*Block]string{} 180 for n, b := range fut.blocks { 181 blockNames[b] = n 182 } 183 184 calcDom := domFn(fut.f) 185 186 for n, d := range doms { 187 nblk, ok := fut.blocks[n] 188 if !ok { 189 t.Errorf("invalid block name %s", n) 190 } 191 dblk, ok := fut.blocks[d] 192 if !ok { 193 t.Errorf("invalid block name %s", d) 194 } 195 196 domNode := calcDom[nblk.ID] 197 switch { 198 case calcDom[nblk.ID] == dblk: 199 calcDom[nblk.ID] = nil 200 continue 201 case calcDom[nblk.ID] != dblk: 202 t.Errorf("expected %s as dominator of %s, found %s", d, n, blockNames[domNode]) 203 default: 204 t.Fatal("unexpected dominator condition") 205 } 206 } 207 208 for id, d := range calcDom { 209 // If nil, we've already verified it 210 if d == nil { 211 continue 212 } 213 for _, b := range fut.blocks { 214 if int(b.ID) == id { 215 t.Errorf("unexpected dominator of %s for %s", blockNames[d], blockNames[b]) 216 } 217 } 218 } 219 220 } 221 222 func TestDominatorsSingleBlock(t *testing.T) { 223 c := testConfig(t) 224 fun := Fun(c, "entry", 225 Bloc("entry", 226 Valu("mem", OpInitMem, TypeMem, 0, nil), 227 Exit("mem"))) 228 229 doms := map[string]string{} 230 231 CheckFunc(fun.f) 232 verifyDominators(t, fun, dominators, doms) 233 verifyDominators(t, fun, dominatorsSimple, doms) 234 235 } 236 237 func TestDominatorsSimple(t *testing.T) { 238 c := testConfig(t) 239 fun := Fun(c, "entry", 240 Bloc("entry", 241 Valu("mem", OpInitMem, TypeMem, 0, nil), 242 Goto("a")), 243 Bloc("a", 244 Goto("b")), 245 Bloc("b", 246 Goto("c")), 247 Bloc("c", 248 Goto("exit")), 249 Bloc("exit", 250 Exit("mem"))) 251 252 doms := map[string]string{ 253 "a": "entry", 254 "b": "a", 255 "c": "b", 256 "exit": "c", 257 } 258 259 CheckFunc(fun.f) 260 verifyDominators(t, fun, dominators, doms) 261 verifyDominators(t, fun, dominatorsSimple, doms) 262 263 } 264 265 func TestDominatorsMultPredFwd(t *testing.T) { 266 c := testConfig(t) 267 fun := Fun(c, "entry", 268 Bloc("entry", 269 Valu("mem", OpInitMem, TypeMem, 0, nil), 270 Valu("p", OpConstBool, TypeBool, 1, nil), 271 If("p", "a", "c")), 272 Bloc("a", 273 If("p", "b", "c")), 274 Bloc("b", 275 Goto("c")), 276 Bloc("c", 277 Goto("exit")), 278 Bloc("exit", 279 Exit("mem"))) 280 281 doms := map[string]string{ 282 "a": "entry", 283 "b": "a", 284 "c": "entry", 285 "exit": "c", 286 } 287 288 CheckFunc(fun.f) 289 verifyDominators(t, fun, dominators, doms) 290 verifyDominators(t, fun, dominatorsSimple, doms) 291 } 292 293 func TestDominatorsDeadCode(t *testing.T) { 294 c := testConfig(t) 295 fun := Fun(c, "entry", 296 Bloc("entry", 297 Valu("mem", OpInitMem, TypeMem, 0, nil), 298 Valu("p", OpConstBool, TypeBool, 0, nil), 299 If("p", "b3", "b5")), 300 Bloc("b2", Exit("mem")), 301 Bloc("b3", Goto("b2")), 302 Bloc("b4", Goto("b2")), 303 Bloc("b5", Goto("b2"))) 304 305 doms := map[string]string{ 306 "b2": "entry", 307 "b3": "entry", 308 "b5": "entry", 309 } 310 311 CheckFunc(fun.f) 312 verifyDominators(t, fun, dominators, doms) 313 verifyDominators(t, fun, dominatorsSimple, doms) 314 } 315 316 func TestDominatorsMultPredRev(t *testing.T) { 317 c := testConfig(t) 318 fun := Fun(c, "entry", 319 Bloc("entry", 320 Goto("first")), 321 Bloc("first", 322 Valu("mem", OpInitMem, TypeMem, 0, nil), 323 Valu("p", OpConstBool, TypeBool, 1, nil), 324 Goto("a")), 325 Bloc("a", 326 If("p", "b", "first")), 327 Bloc("b", 328 Goto("c")), 329 Bloc("c", 330 If("p", "exit", "b")), 331 Bloc("exit", 332 Exit("mem"))) 333 334 doms := map[string]string{ 335 "first": "entry", 336 "a": "first", 337 "b": "a", 338 "c": "b", 339 "exit": "c", 340 } 341 342 CheckFunc(fun.f) 343 verifyDominators(t, fun, dominators, doms) 344 verifyDominators(t, fun, dominatorsSimple, doms) 345 } 346 347 func TestDominatorsMultPred(t *testing.T) { 348 c := testConfig(t) 349 fun := Fun(c, "entry", 350 Bloc("entry", 351 Valu("mem", OpInitMem, TypeMem, 0, nil), 352 Valu("p", OpConstBool, TypeBool, 1, nil), 353 If("p", "a", "c")), 354 Bloc("a", 355 If("p", "b", "c")), 356 Bloc("b", 357 Goto("c")), 358 Bloc("c", 359 If("p", "b", "exit")), 360 Bloc("exit", 361 Exit("mem"))) 362 363 doms := map[string]string{ 364 "a": "entry", 365 "b": "entry", 366 "c": "entry", 367 "exit": "c", 368 } 369 370 CheckFunc(fun.f) 371 verifyDominators(t, fun, dominators, doms) 372 verifyDominators(t, fun, dominatorsSimple, doms) 373 } 374 375 func TestPostDominators(t *testing.T) { 376 c := testConfig(t) 377 fun := Fun(c, "entry", 378 Bloc("entry", 379 Valu("mem", OpInitMem, TypeMem, 0, nil), 380 Valu("p", OpConstBool, TypeBool, 1, nil), 381 If("p", "a", "c")), 382 Bloc("a", 383 If("p", "b", "c")), 384 Bloc("b", 385 Goto("c")), 386 Bloc("c", 387 If("p", "b", "exit")), 388 Bloc("exit", 389 Exit("mem"))) 390 391 doms := map[string]string{"entry": "c", 392 "a": "c", 393 "b": "c", 394 "c": "exit", 395 } 396 397 CheckFunc(fun.f) 398 verifyDominators(t, fun, postDominators, doms) 399 } 400 401 func TestInfiniteLoop(t *testing.T) { 402 c := testConfig(t) 403 // note lack of an exit block 404 fun := Fun(c, "entry", 405 Bloc("entry", 406 Valu("mem", OpInitMem, TypeMem, 0, nil), 407 Valu("p", OpConstBool, TypeBool, 1, nil), 408 Goto("a")), 409 Bloc("a", 410 Goto("b")), 411 Bloc("b", 412 Goto("a"))) 413 414 CheckFunc(fun.f) 415 doms := map[string]string{"a": "entry", 416 "b": "a"} 417 verifyDominators(t, fun, dominators, doms) 418 419 // no exit block, so there are no post-dominators 420 postDoms := map[string]string{} 421 verifyDominators(t, fun, postDominators, postDoms) 422 }