github.com/goproxy0/go@v0.0.0-20171111080102-49cc0c489d2c/src/cmd/compile/internal/ssa/fuse_test.go (about) 1 package ssa 2 3 import ( 4 "cmd/compile/internal/types" 5 "fmt" 6 "strconv" 7 "testing" 8 ) 9 10 func TestFuseEliminatesOneBranch(t *testing.T) { 11 c := testConfig(t) 12 ptrType := c.config.Types.BytePtr 13 fun := c.Fun("entry", 14 Bloc("entry", 15 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 16 Valu("sb", OpSB, types.TypeInvalid, 0, nil), 17 Goto("checkPtr")), 18 Bloc("checkPtr", 19 Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"), 20 Valu("nilptr", OpConstNil, ptrType, 0, nil), 21 Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"), 22 If("bool1", "then", "exit")), 23 Bloc("then", 24 Goto("exit")), 25 Bloc("exit", 26 Exit("mem"))) 27 28 CheckFunc(fun.f) 29 fuse(fun.f) 30 31 for _, b := range fun.f.Blocks { 32 if b == fun.blocks["then"] && b.Kind != BlockInvalid { 33 t.Errorf("then was not eliminated, but should have") 34 } 35 } 36 } 37 38 func TestFuseEliminatesBothBranches(t *testing.T) { 39 c := testConfig(t) 40 ptrType := c.config.Types.BytePtr 41 fun := c.Fun("entry", 42 Bloc("entry", 43 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 44 Valu("sb", OpSB, types.TypeInvalid, 0, nil), 45 Goto("checkPtr")), 46 Bloc("checkPtr", 47 Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"), 48 Valu("nilptr", OpConstNil, ptrType, 0, nil), 49 Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"), 50 If("bool1", "then", "else")), 51 Bloc("then", 52 Goto("exit")), 53 Bloc("else", 54 Goto("exit")), 55 Bloc("exit", 56 Exit("mem"))) 57 58 CheckFunc(fun.f) 59 fuse(fun.f) 60 61 for _, b := range fun.f.Blocks { 62 if b == fun.blocks["then"] && b.Kind != BlockInvalid { 63 t.Errorf("then was not eliminated, but should have") 64 } 65 if b == fun.blocks["else"] && b.Kind != BlockInvalid { 66 t.Errorf("then was not eliminated, but should have") 67 } 68 } 69 } 70 71 func TestFuseHandlesPhis(t *testing.T) { 72 c := testConfig(t) 73 ptrType := c.config.Types.BytePtr 74 fun := c.Fun("entry", 75 Bloc("entry", 76 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 77 Valu("sb", OpSB, types.TypeInvalid, 0, nil), 78 Goto("checkPtr")), 79 Bloc("checkPtr", 80 Valu("ptr1", OpLoad, ptrType, 0, nil, "sb", "mem"), 81 Valu("nilptr", OpConstNil, ptrType, 0, nil), 82 Valu("bool1", OpNeqPtr, c.config.Types.Bool, 0, nil, "ptr1", "nilptr"), 83 If("bool1", "then", "else")), 84 Bloc("then", 85 Goto("exit")), 86 Bloc("else", 87 Goto("exit")), 88 Bloc("exit", 89 Valu("phi", OpPhi, ptrType, 0, nil, "ptr1", "ptr1"), 90 Exit("mem"))) 91 92 CheckFunc(fun.f) 93 fuse(fun.f) 94 95 for _, b := range fun.f.Blocks { 96 if b == fun.blocks["then"] && b.Kind != BlockInvalid { 97 t.Errorf("then was not eliminated, but should have") 98 } 99 if b == fun.blocks["else"] && b.Kind != BlockInvalid { 100 t.Errorf("then was not eliminated, but should have") 101 } 102 } 103 } 104 105 func TestFuseEliminatesEmptyBlocks(t *testing.T) { 106 c := testConfig(t) 107 fun := c.Fun("entry", 108 Bloc("entry", 109 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 110 Valu("sb", OpSB, types.TypeInvalid, 0, nil), 111 Goto("z0")), 112 Bloc("z1", 113 Goto("z2")), 114 Bloc("z3", 115 Goto("exit")), 116 Bloc("z2", 117 Goto("z3")), 118 Bloc("z0", 119 Goto("z1")), 120 Bloc("exit", 121 Exit("mem"), 122 )) 123 124 CheckFunc(fun.f) 125 fuse(fun.f) 126 127 for k, b := range fun.blocks { 128 if k[:1] == "z" && b.Kind != BlockInvalid { 129 t.Errorf("%s was not eliminated, but should have", k) 130 } 131 } 132 } 133 134 func BenchmarkFuse(b *testing.B) { 135 for _, n := range [...]int{1, 10, 100, 1000, 10000} { 136 b.Run(strconv.Itoa(n), func(b *testing.B) { 137 c := testConfig(b) 138 139 blocks := make([]bloc, 0, 2*n+3) 140 blocks = append(blocks, 141 Bloc("entry", 142 Valu("mem", OpInitMem, types.TypeMem, 0, nil), 143 Valu("cond", OpArg, c.config.Types.Bool, 0, nil), 144 Valu("x", OpArg, c.config.Types.Int64, 0, nil), 145 Goto("exit"))) 146 147 phiArgs := make([]string, 0, 2*n) 148 for i := 0; i < n; i++ { 149 cname := fmt.Sprintf("c%d", i) 150 blocks = append(blocks, 151 Bloc(fmt.Sprintf("b%d", i), If("cond", cname, "merge")), 152 Bloc(cname, Goto("merge"))) 153 phiArgs = append(phiArgs, "x", "x") 154 } 155 blocks = append(blocks, 156 Bloc("merge", 157 Valu("phi", OpPhi, types.TypeMem, 0, nil, phiArgs...), 158 Goto("exit")), 159 Bloc("exit", 160 Exit("mem"))) 161 162 b.ResetTimer() 163 for i := 0; i < b.N; i++ { 164 fun := c.Fun("entry", blocks...) 165 fuse(fun.f) 166 } 167 }) 168 } 169 }