1
2
3
4
5 package ssacompile
6
7 import (
8 "testing"
9
10 "cmd/compile/internal/ssa/block"
11 "cmd/compile/internal/ssa/ssaop"
12 "cmd/compile/internal/types"
13 )
14
15
16 func TestBranchElimIf(t *testing.T) {
17 var testData = []struct {
18 arch string
19 intType string
20 ok bool
21 }{
22 {"arm64", "int32", true},
23 {"amd64", "int32", true},
24 {"amd64", "int8", false},
25 }
26
27 for _, data := range testData {
28 t.Run(data.arch+"/"+data.intType, func(t *testing.T) {
29 c := testConfigArch(t, data.arch)
30 boolType := c.config.Types.Bool
31 var intType *types.Type
32 switch data.intType {
33 case "int32":
34 intType = c.config.Types.Int32
35 case "int8":
36 intType = c.config.Types.Int8
37 default:
38 t.Fatal("invalid integer type:", data.intType)
39 }
40 fun := c.Fun("entry",
41 Bloc("entry",
42 Valu("start", ssaop.OpInitMem, types.TypeMem, 0, nil),
43 Valu("sb", ssaop.OpSB, c.config.Types.Uintptr, 0, nil),
44 Valu("const1", ssaop.OpConst32, intType, 1, nil),
45 Valu("const2", ssaop.OpConst32, intType, 2, nil),
46 Valu("addr", ssaop.OpAddr, boolType.PtrTo(), 0, nil, "sb"),
47 Valu("cond", ssaop.OpLoad, boolType, 0, nil, "addr", "start"),
48 If("cond", "b2", "b3")),
49 Bloc("b2",
50 Goto("b3")),
51 Bloc("b3",
52 Valu("phi", ssaop.OpPhi, intType, 0, nil, "const1", "const2"),
53 Valu("retstore", ssaop.OpStore, types.TypeMem, 0, nil, "phi", "sb", "start"),
54 Exit("retstore")))
55
56 CheckFunc(fun.f)
57 branchelim(fun.f)
58 CheckFunc(fun.f)
59 Deadcode(fun.f)
60 CheckFunc(fun.f)
61
62 if data.ok {
63
64 if len(fun.f.Blocks) != 1 {
65 t.Fatalf("expected 1 block after branchelim and deadcode; found %d", len(fun.f.Blocks))
66 }
67 if fun.values["phi"].Op != ssaop.OpCondSelect {
68 t.Fatalf("expected phi op to be CondSelect; found op %s", fun.values["phi"].Op)
69 }
70 if fun.values["phi"].Args[2] != fun.values["cond"] {
71 t.Errorf("expected CondSelect condition to be %s; found %s", fun.values["cond"], fun.values["phi"].Args[2])
72 }
73 if fun.blocks["entry"].Kind != block.BlockExit {
74 t.Errorf("expected entry to be BlockExit; found kind %s", fun.blocks["entry"].Kind.String())
75 }
76 } else {
77 if len(fun.f.Blocks) != 3 {
78 t.Fatalf("expected 3 block after branchelim and deadcode; found %d", len(fun.f.Blocks))
79 }
80 }
81 })
82 }
83 }
84
85
86 func TestBranchElimIfElse(t *testing.T) {
87 for _, arch := range []string{"arm64", "amd64"} {
88 t.Run(arch, func(t *testing.T) {
89 c := testConfigArch(t, arch)
90 boolType := c.config.Types.Bool
91 intType := c.config.Types.Int32
92 fun := c.Fun("entry",
93 Bloc("entry",
94 Valu("start", ssaop.OpInitMem, types.TypeMem, 0, nil),
95 Valu("sb", ssaop.OpSB, c.config.Types.Uintptr, 0, nil),
96 Valu("const1", ssaop.OpConst32, intType, 1, nil),
97 Valu("const2", ssaop.OpConst32, intType, 2, nil),
98 Valu("addr", ssaop.OpAddr, boolType.PtrTo(), 0, nil, "sb"),
99 Valu("cond", ssaop.OpLoad, boolType, 0, nil, "addr", "start"),
100 If("cond", "b2", "b3")),
101 Bloc("b2",
102 Goto("b4")),
103 Bloc("b3",
104 Goto("b4")),
105 Bloc("b4",
106 Valu("phi", ssaop.OpPhi, intType, 0, nil, "const1", "const2"),
107 Valu("retstore", ssaop.OpStore, types.TypeMem, 0, nil, "phi", "sb", "start"),
108 Exit("retstore")))
109
110 CheckFunc(fun.f)
111 branchelim(fun.f)
112 CheckFunc(fun.f)
113 Deadcode(fun.f)
114 CheckFunc(fun.f)
115
116 if len(fun.f.Blocks) != 1 {
117 t.Fatalf("expected 1 block after branchelim; found %d", len(fun.f.Blocks))
118 }
119 if fun.values["phi"].Op != ssaop.OpCondSelect {
120 t.Fatalf("expected phi op to be CondSelect; found op %s", fun.values["phi"].Op)
121 }
122 if fun.values["phi"].Args[2] != fun.values["cond"] {
123 t.Errorf("expected CondSelect condition to be %s; found %s", fun.values["cond"], fun.values["phi"].Args[2])
124 }
125 if fun.blocks["entry"].Kind != block.BlockExit {
126 t.Errorf("expected entry to be BlockExit; found kind %s", fun.blocks["entry"].Kind.String())
127 }
128 })
129 }
130 }
131
132
133
134 func TestNoBranchElimLoop(t *testing.T) {
135 for _, arch := range []string{"arm64", "amd64"} {
136 t.Run(arch, func(t *testing.T) {
137 c := testConfigArch(t, arch)
138 boolType := c.config.Types.Bool
139 intType := c.config.Types.Int32
140
141
142
143
144 fun := c.Fun("entry",
145 Bloc("entry",
146 Valu("start", ssaop.OpInitMem, types.TypeMem, 0, nil),
147 Valu("sb", ssaop.OpSB, c.config.Types.Uintptr, 0, nil),
148 Valu("const2", ssaop.OpConst32, intType, 2, nil),
149 Valu("const3", ssaop.OpConst32, intType, 3, nil),
150 Goto("b5")),
151 Bloc("b2",
152 Valu("addr", ssaop.OpAddr, boolType.PtrTo(), 0, nil, "sb"),
153 Valu("cond", ssaop.OpLoad, boolType, 0, nil, "addr", "start"),
154 Valu("phi", ssaop.OpPhi, intType, 0, nil, "const2", "const3"),
155 If("cond", "b3", "b4")),
156 Bloc("b3",
157 Goto("b2")),
158 Bloc("b4",
159 Goto("b2")),
160 Bloc("b5",
161 Exit("start")))
162
163 CheckFunc(fun.f)
164 branchelim(fun.f)
165 CheckFunc(fun.f)
166
167 if len(fun.f.Blocks) != 5 {
168 t.Errorf("expected 5 block after branchelim; found %d", len(fun.f.Blocks))
169 }
170 if fun.values["phi"].Op != ssaop.OpPhi {
171 t.Errorf("expected phi op to be CondSelect; found op %s", fun.values["phi"].Op)
172 }
173 })
174 }
175 }
176
View as plain text