github.com/go-asm/go@v1.21.1-0.20240213172139-40c5ead50c48/cmd/compile/ssa/deadcode_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 ( 8 "fmt" 9 "strconv" 10 "testing" 11 12 "github.com/go-asm/go/cmd/compile/types" 13 ) 14 15 func TestDeadLoop(t *testing.T) { 16 c := testConfig(t) 17 fun := c.Fun("entry", 18 Bloc("entry", 19 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 20 Goto("exit")), 21 Bloc("exit", 22 Exit("mem")), 23 // dead loop 24 Bloc("deadblock", 25 // dead value in dead block 26 Valu("deadval", OpConstBool, c.config.Types.Bool, 1, nil), 27 If("deadval", "deadblock", "exit"))) 28 29 CheckFunc(fun.f) 30 Deadcode(fun.f) 31 CheckFunc(fun.f) 32 33 for _, b := range fun.f.Blocks { 34 if b == fun.blocks["deadblock"] { 35 t.Errorf("dead block not removed") 36 } 37 for _, v := range b.Values { 38 if v == fun.values["deadval"] { 39 t.Errorf("control value of dead block not removed") 40 } 41 } 42 } 43 } 44 45 func TestDeadValue(t *testing.T) { 46 c := testConfig(t) 47 fun := c.Fun("entry", 48 Bloc("entry", 49 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 50 Valu("deadval", OpConst64, c.config.Types.Int64, 37, nil), 51 Goto("exit")), 52 Bloc("exit", 53 Exit("mem"))) 54 55 CheckFunc(fun.f) 56 Deadcode(fun.f) 57 CheckFunc(fun.f) 58 59 for _, b := range fun.f.Blocks { 60 for _, v := range b.Values { 61 if v == fun.values["deadval"] { 62 t.Errorf("dead value not removed") 63 } 64 } 65 } 66 } 67 68 func TestNeverTaken(t *testing.T) { 69 c := testConfig(t) 70 fun := c.Fun("entry", 71 Bloc("entry", 72 Valu("cond", OpConstBool, c.config.Types.Bool, 0, nil), 73 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 74 If("cond", "then", "else")), 75 Bloc("then", 76 Goto("exit")), 77 Bloc("else", 78 Goto("exit")), 79 Bloc("exit", 80 Exit("mem"))) 81 82 CheckFunc(fun.f) 83 Opt(fun.f) 84 Deadcode(fun.f) 85 CheckFunc(fun.f) 86 87 if fun.blocks["entry"].Kind != BlockPlain { 88 t.Errorf("if(false) not simplified") 89 } 90 for _, b := range fun.f.Blocks { 91 if b == fun.blocks["then"] { 92 t.Errorf("then block still present") 93 } 94 for _, v := range b.Values { 95 if v == fun.values["cond"] { 96 t.Errorf("constant condition still present") 97 } 98 } 99 } 100 101 } 102 103 func TestNestedDeadBlocks(t *testing.T) { 104 c := testConfig(t) 105 fun := c.Fun("entry", 106 Bloc("entry", 107 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 108 Valu("cond", OpConstBool, c.config.Types.Bool, 0, nil), 109 If("cond", "b2", "b4")), 110 Bloc("b2", 111 If("cond", "b3", "b4")), 112 Bloc("b3", 113 If("cond", "b3", "b4")), 114 Bloc("b4", 115 If("cond", "b3", "exit")), 116 Bloc("exit", 117 Exit("mem"))) 118 119 CheckFunc(fun.f) 120 Opt(fun.f) 121 CheckFunc(fun.f) 122 Deadcode(fun.f) 123 CheckFunc(fun.f) 124 if fun.blocks["entry"].Kind != BlockPlain { 125 t.Errorf("if(false) not simplified") 126 } 127 for _, b := range fun.f.Blocks { 128 if b == fun.blocks["b2"] { 129 t.Errorf("b2 block still present") 130 } 131 if b == fun.blocks["b3"] { 132 t.Errorf("b3 block still present") 133 } 134 for _, v := range b.Values { 135 if v == fun.values["cond"] { 136 t.Errorf("constant condition still present") 137 } 138 } 139 } 140 } 141 142 func BenchmarkDeadCode(b *testing.B) { 143 for _, n := range [...]int{1, 10, 100, 1000, 10000, 100000, 200000} { 144 b.Run(strconv.Itoa(n), func(b *testing.B) { 145 c := testConfig(b) 146 blocks := make([]bloc, 0, n+2) 147 blocks = append(blocks, 148 Bloc("entry", 149 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 150 Goto("exit"))) 151 blocks = append(blocks, Bloc("exit", Exit("mem"))) 152 for i := 0; i < n; i++ { 153 blocks = append(blocks, Bloc(fmt.Sprintf("dead%d", i), Goto("exit"))) 154 } 155 b.ResetTimer() 156 for i := 0; i < b.N; i++ { 157 fun := c.Fun("entry", blocks...) 158 Deadcode(fun.f) 159 } 160 }) 161 } 162 }