github.com/slayercat/go@v0.0.0-20170428012452-c51559813f61/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 := testConfig(b) 164 fun := c.Fun("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 := c.Fun("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 := c.Fun("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 := c.Fun("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 := c.Fun("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 := c.Fun("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 := c.Fun("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 TestInfiniteLoop(t *testing.T) { 376 c := testConfig(t) 377 // note lack of an exit block 378 fun := c.Fun("entry", 379 Bloc("entry", 380 Valu("mem", OpInitMem, TypeMem, 0, nil), 381 Valu("p", OpConstBool, TypeBool, 1, nil), 382 Goto("a")), 383 Bloc("a", 384 Goto("b")), 385 Bloc("b", 386 Goto("a"))) 387 388 CheckFunc(fun.f) 389 doms := map[string]string{"a": "entry", 390 "b": "a"} 391 verifyDominators(t, fun, dominators, doms) 392 } 393 394 func TestDomTricky(t *testing.T) { 395 doms := map[string]string{ 396 "4": "1", 397 "2": "4", 398 "5": "4", 399 "11": "4", 400 "15": "4", // the incorrect answer is "5" 401 "10": "15", 402 "19": "15", 403 } 404 405 if4 := [2]string{"2", "5"} 406 if5 := [2]string{"15", "11"} 407 if15 := [2]string{"19", "10"} 408 409 for i := 0; i < 8; i++ { 410 a := 1 & i 411 b := 1 & i >> 1 412 c := 1 & i >> 2 413 414 cfg := testConfig(t) 415 fun := cfg.Fun("1", 416 Bloc("1", 417 Valu("mem", OpInitMem, TypeMem, 0, nil), 418 Valu("p", OpConstBool, TypeBool, 1, nil), 419 Goto("4")), 420 Bloc("2", 421 Goto("11")), 422 Bloc("4", 423 If("p", if4[a], if4[1-a])), // 2, 5 424 Bloc("5", 425 If("p", if5[b], if5[1-b])), //15, 11 426 Bloc("10", 427 Exit("mem")), 428 Bloc("11", 429 Goto("15")), 430 Bloc("15", 431 If("p", if15[c], if15[1-c])), //19, 10 432 Bloc("19", 433 Goto("10"))) 434 CheckFunc(fun.f) 435 verifyDominators(t, fun, dominators, doms) 436 verifyDominators(t, fun, dominatorsSimple, doms) 437 } 438 } 439 440 // generateDominatorMap uses dominatorsSimple to obtain a 441 // reference dominator tree for testing faster algorithms. 442 func generateDominatorMap(fut fun) map[string]string { 443 blockNames := map[*Block]string{} 444 for n, b := range fut.blocks { 445 blockNames[b] = n 446 } 447 referenceDom := dominatorsSimple(fut.f) 448 doms := make(map[string]string) 449 for _, b := range fut.f.Blocks { 450 if d := referenceDom[b.ID]; d != nil { 451 doms[blockNames[b]] = blockNames[d] 452 } 453 } 454 return doms 455 } 456 457 func TestDominatorsPostTrickyA(t *testing.T) { 458 testDominatorsPostTricky(t, "b8", "b11", "b10", "b8", "b14", "b15") 459 } 460 461 func TestDominatorsPostTrickyB(t *testing.T) { 462 testDominatorsPostTricky(t, "b11", "b8", "b10", "b8", "b14", "b15") 463 } 464 465 func TestDominatorsPostTrickyC(t *testing.T) { 466 testDominatorsPostTricky(t, "b8", "b11", "b8", "b10", "b14", "b15") 467 } 468 469 func TestDominatorsPostTrickyD(t *testing.T) { 470 testDominatorsPostTricky(t, "b11", "b8", "b8", "b10", "b14", "b15") 471 } 472 473 func TestDominatorsPostTrickyE(t *testing.T) { 474 testDominatorsPostTricky(t, "b8", "b11", "b10", "b8", "b15", "b14") 475 } 476 477 func TestDominatorsPostTrickyF(t *testing.T) { 478 testDominatorsPostTricky(t, "b11", "b8", "b10", "b8", "b15", "b14") 479 } 480 481 func TestDominatorsPostTrickyG(t *testing.T) { 482 testDominatorsPostTricky(t, "b8", "b11", "b8", "b10", "b15", "b14") 483 } 484 485 func TestDominatorsPostTrickyH(t *testing.T) { 486 testDominatorsPostTricky(t, "b11", "b8", "b8", "b10", "b15", "b14") 487 } 488 489 func testDominatorsPostTricky(t *testing.T, b7then, b7else, b12then, b12else, b13then, b13else string) { 490 c := testConfig(t) 491 fun := c.Fun("b1", 492 Bloc("b1", 493 Valu("mem", OpInitMem, TypeMem, 0, nil), 494 Valu("p", OpConstBool, TypeBool, 1, nil), 495 If("p", "b3", "b2")), 496 Bloc("b3", 497 If("p", "b5", "b6")), 498 Bloc("b5", 499 Goto("b7")), 500 Bloc("b7", 501 If("p", b7then, b7else)), 502 Bloc("b8", 503 Goto("b13")), 504 Bloc("b13", 505 If("p", b13then, b13else)), 506 Bloc("b14", 507 Goto("b10")), 508 Bloc("b15", 509 Goto("b16")), 510 Bloc("b16", 511 Goto("b9")), 512 Bloc("b9", 513 Goto("b7")), 514 Bloc("b11", 515 Goto("b12")), 516 Bloc("b12", 517 If("p", b12then, b12else)), 518 Bloc("b10", 519 Goto("b6")), 520 Bloc("b6", 521 Goto("b17")), 522 Bloc("b17", 523 Goto("b18")), 524 Bloc("b18", 525 If("p", "b22", "b19")), 526 Bloc("b22", 527 Goto("b23")), 528 Bloc("b23", 529 If("p", "b21", "b19")), 530 Bloc("b19", 531 If("p", "b24", "b25")), 532 Bloc("b24", 533 Goto("b26")), 534 Bloc("b26", 535 Goto("b25")), 536 Bloc("b25", 537 If("p", "b27", "b29")), 538 Bloc("b27", 539 Goto("b30")), 540 Bloc("b30", 541 Goto("b28")), 542 Bloc("b29", 543 Goto("b31")), 544 Bloc("b31", 545 Goto("b28")), 546 Bloc("b28", 547 If("p", "b32", "b33")), 548 Bloc("b32", 549 Goto("b21")), 550 Bloc("b21", 551 Goto("b47")), 552 Bloc("b47", 553 If("p", "b45", "b46")), 554 Bloc("b45", 555 Goto("b48")), 556 Bloc("b48", 557 Goto("b49")), 558 Bloc("b49", 559 If("p", "b50", "b51")), 560 Bloc("b50", 561 Goto("b52")), 562 Bloc("b52", 563 Goto("b53")), 564 Bloc("b53", 565 Goto("b51")), 566 Bloc("b51", 567 Goto("b54")), 568 Bloc("b54", 569 Goto("b46")), 570 Bloc("b46", 571 Exit("mem")), 572 Bloc("b33", 573 Goto("b34")), 574 Bloc("b34", 575 Goto("b37")), 576 Bloc("b37", 577 If("p", "b35", "b36")), 578 Bloc("b35", 579 Goto("b38")), 580 Bloc("b38", 581 Goto("b39")), 582 Bloc("b39", 583 If("p", "b40", "b41")), 584 Bloc("b40", 585 Goto("b42")), 586 Bloc("b42", 587 Goto("b43")), 588 Bloc("b43", 589 Goto("b41")), 590 Bloc("b41", 591 Goto("b44")), 592 Bloc("b44", 593 Goto("b36")), 594 Bloc("b36", 595 Goto("b20")), 596 Bloc("b20", 597 Goto("b18")), 598 Bloc("b2", 599 Goto("b4")), 600 Bloc("b4", 601 Exit("mem"))) 602 CheckFunc(fun.f) 603 doms := generateDominatorMap(fun) 604 verifyDominators(t, fun, dominators, doms) 605 }