1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33 package ssa
34
35
36
37
38
39 import (
40 "cmd/compile/internal/types"
41 "cmd/internal/obj"
42 "cmd/internal/src"
43 "fmt"
44 "reflect"
45 "testing"
46 )
47
48
49
50
51
52
53
54 func Equiv(f, g *Func) bool {
55 valcor := make(map[*Value]*Value)
56 var checkVal func(fv, gv *Value) bool
57 checkVal = func(fv, gv *Value) bool {
58 if fv == nil && gv == nil {
59 return true
60 }
61 if valcor[fv] == nil && valcor[gv] == nil {
62 valcor[fv] = gv
63 valcor[gv] = fv
64
65
66
67 if fv.Op != gv.Op || fv.Type != gv.Type || fv.AuxInt != gv.AuxInt {
68 return false
69 }
70 if !reflect.DeepEqual(fv.Aux, gv.Aux) {
71
72
73
74
75 return false
76 }
77 if len(fv.Args) != len(gv.Args) {
78 return false
79 }
80 for i := range fv.Args {
81 if !checkVal(fv.Args[i], gv.Args[i]) {
82 return false
83 }
84 }
85 }
86 return valcor[fv] == gv && valcor[gv] == fv
87 }
88 blkcor := make(map[*Block]*Block)
89 var checkBlk func(fb, gb *Block) bool
90 checkBlk = func(fb, gb *Block) bool {
91 if blkcor[fb] == nil && blkcor[gb] == nil {
92 blkcor[fb] = gb
93 blkcor[gb] = fb
94
95 if fb.Kind != gb.Kind {
96 return false
97 }
98 if len(fb.Values) != len(gb.Values) {
99 return false
100 }
101 for i := range fb.Values {
102 if !checkVal(fb.Values[i], gb.Values[i]) {
103 return false
104 }
105 }
106 if len(fb.Succs) != len(gb.Succs) {
107 return false
108 }
109 for i := range fb.Succs {
110 if !checkBlk(fb.Succs[i].b, gb.Succs[i].b) {
111 return false
112 }
113 }
114 if len(fb.Preds) != len(gb.Preds) {
115 return false
116 }
117 for i := range fb.Preds {
118 if !checkBlk(fb.Preds[i].b, gb.Preds[i].b) {
119 return false
120 }
121 }
122 return true
123
124 }
125 return blkcor[fb] == gb && blkcor[gb] == fb
126 }
127
128 return checkBlk(f.Entry, g.Entry)
129 }
130
131
132
133
134 type fun struct {
135 f *Func
136 blocks map[string]*Block
137 values map[string]*Value
138 }
139
140 var emptyPass pass = pass{
141 name: "empty pass",
142 }
143
144
145
146 func AuxCallLSym(name string) *AuxCall {
147 return &AuxCall{Fn: &obj.LSym{}}
148 }
149
150
151
152
153
154 func (c *Conf) Fun(entry string, blocs ...bloc) fun {
155
156
157
158 f := c.config.NewFunc(c.Frontend(), new(Cache))
159 f.pass = &emptyPass
160 f.cachedLineStarts = newXposmap(map[int]lineRange{0: {0, 100}, 1: {0, 100}, 2: {0, 100}, 3: {0, 100}, 4: {0, 100}})
161
162 blocks := make(map[string]*Block)
163 values := make(map[string]*Value)
164
165 for _, bloc := range blocs {
166 b := f.NewBlock(bloc.control.kind)
167 blocks[bloc.name] = b
168 for _, valu := range bloc.valus {
169
170 values[valu.name] = b.NewValue0IA(src.NoXPos, valu.op, valu.t, valu.auxint, valu.aux)
171 }
172 }
173
174 f.Entry = blocks[entry]
175 for _, bloc := range blocs {
176 b := blocks[bloc.name]
177 c := bloc.control
178
179 if c.control != "" {
180 cval, ok := values[c.control]
181 if !ok {
182 f.Fatalf("control value for block %s missing", bloc.name)
183 }
184 b.SetControl(cval)
185 }
186
187 for _, valu := range bloc.valus {
188 v := values[valu.name]
189 for _, arg := range valu.args {
190 a, ok := values[arg]
191 if !ok {
192 b.Fatalf("arg %s missing for value %s in block %s",
193 arg, valu.name, bloc.name)
194 }
195 v.AddArg(a)
196 }
197 }
198
199 for _, succ := range c.succs {
200 b.AddEdgeTo(blocks[succ])
201 }
202 }
203 return fun{f, blocks, values}
204 }
205
206
207
208
209 func Bloc(name string, entries ...interface{}) bloc {
210 b := bloc{}
211 b.name = name
212 seenCtrl := false
213 for _, e := range entries {
214 switch v := e.(type) {
215 case ctrl:
216
217 if seenCtrl {
218 panic(fmt.Sprintf("already seen control for block %s", name))
219 }
220 b.control = v
221 seenCtrl = true
222 case valu:
223 b.valus = append(b.valus, v)
224 }
225 }
226 if !seenCtrl {
227 panic(fmt.Sprintf("block %s doesn't have control", b.name))
228 }
229 return b
230 }
231
232
233 func Valu(name string, op Op, t *types.Type, auxint int64, aux Aux, args ...string) valu {
234 return valu{name, op, t, auxint, aux, args}
235 }
236
237
238
239 func Goto(succ string) ctrl {
240 return ctrl{BlockPlain, "", []string{succ}}
241 }
242
243
244 func If(cond, sub, alt string) ctrl {
245 return ctrl{BlockIf, cond, []string{sub, alt}}
246 }
247
248
249 func Exit(arg string) ctrl {
250 return ctrl{BlockExit, arg, []string{}}
251 }
252
253
254 func Ret(arg string) ctrl {
255 return ctrl{BlockRet, arg, []string{}}
256 }
257
258
259 func Eq(cond, sub, alt string) ctrl {
260 return ctrl{BlockAMD64EQ, cond, []string{sub, alt}}
261 }
262
263
264
265
266 type bloc struct {
267 name string
268 control ctrl
269 valus []valu
270 }
271
272 type ctrl struct {
273 kind BlockKind
274 control string
275 succs []string
276 }
277
278 type valu struct {
279 name string
280 op Op
281 t *types.Type
282 auxint int64
283 aux Aux
284 args []string
285 }
286
287 func TestArgs(t *testing.T) {
288 c := testConfig(t)
289 fun := c.Fun("entry",
290 Bloc("entry",
291 Valu("a", OpConst64, c.config.Types.Int64, 14, nil),
292 Valu("b", OpConst64, c.config.Types.Int64, 26, nil),
293 Valu("sum", OpAdd64, c.config.Types.Int64, 0, nil, "a", "b"),
294 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
295 Goto("exit")),
296 Bloc("exit",
297 Exit("mem")))
298 sum := fun.values["sum"]
299 for i, name := range []string{"a", "b"} {
300 if sum.Args[i] != fun.values[name] {
301 t.Errorf("arg %d for sum is incorrect: want %s, got %s",
302 i, sum.Args[i], fun.values[name])
303 }
304 }
305 }
306
307 func TestEquiv(t *testing.T) {
308 cfg := testConfig(t)
309 equivalentCases := []struct{ f, g fun }{
310
311 {
312 cfg.Fun("entry",
313 Bloc("entry",
314 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
315 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
316 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
317 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
318 Goto("exit")),
319 Bloc("exit",
320 Exit("mem"))),
321 cfg.Fun("entry",
322 Bloc("entry",
323 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
324 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
325 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
326 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
327 Goto("exit")),
328 Bloc("exit",
329 Exit("mem"))),
330 },
331
332 {
333 cfg.Fun("entry",
334 Bloc("entry",
335 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
336 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
337 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
338 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
339 Goto("exit")),
340 Bloc("exit",
341 Exit("mem"))),
342 cfg.Fun("entry",
343 Bloc("exit",
344 Exit("mem")),
345 Bloc("entry",
346 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
347 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
348 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
349 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
350 Goto("exit"))),
351 },
352 }
353 for _, c := range equivalentCases {
354 if !Equiv(c.f.f, c.g.f) {
355 t.Error("expected equivalence. Func definitions:")
356 t.Error(c.f.f)
357 t.Error(c.g.f)
358 }
359 }
360
361 differentCases := []struct{ f, g fun }{
362
363 {
364 cfg.Fun("entry",
365 Bloc("entry",
366 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
367 Goto("exit")),
368 Bloc("exit",
369 Exit("mem"))),
370 cfg.Fun("entry",
371 Bloc("entry",
372 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
373 Exit("mem"))),
374 },
375
376 {
377 cfg.Fun("entry",
378 Bloc("entry",
379 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
380 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
381 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
382 Exit("mem"))),
383 cfg.Fun("entry",
384 Bloc("entry",
385 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
386 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
387 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
388 Exit("mem"))),
389 },
390
391 {
392 cfg.Fun("entry",
393 Bloc("entry",
394 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
395 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
396 Exit("mem"))),
397 cfg.Fun("entry",
398 Bloc("entry",
399 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
400 Valu("a", OpConst64, cfg.config.Types.Int64, 26, nil),
401 Exit("mem"))),
402 },
403
404 {
405 cfg.Fun("entry",
406 Bloc("entry",
407 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
408 Valu("a", OpConstString, cfg.config.Types.String, 0, StringToAux("foo")),
409 Exit("mem"))),
410 cfg.Fun("entry",
411 Bloc("entry",
412 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
413 Valu("a", OpConstString, cfg.config.Types.String, 0, StringToAux("bar")),
414 Exit("mem"))),
415 },
416
417 {
418 cfg.Fun("entry",
419 Bloc("entry",
420 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
421 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
422 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
423 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
424 Exit("mem"))),
425 cfg.Fun("entry",
426 Bloc("entry",
427 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
428 Valu("a", OpConst64, cfg.config.Types.Int64, 0, nil),
429 Valu("b", OpConst64, cfg.config.Types.Int64, 14, nil),
430 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "b", "a"),
431 Exit("mem"))),
432 },
433 }
434 for _, c := range differentCases {
435 if Equiv(c.f.f, c.g.f) {
436 t.Error("expected difference. Func definitions:")
437 t.Error(c.f.f)
438 t.Error(c.g.f)
439 }
440 }
441 }
442
443
444
445 func TestConstCache(t *testing.T) {
446 c := testConfig(t)
447 f := c.Fun("entry",
448 Bloc("entry",
449 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
450 Exit("mem")))
451 v1 := f.f.ConstBool(c.config.Types.Bool, false)
452 v2 := f.f.ConstBool(c.config.Types.Bool, true)
453 f.f.freeValue(v1)
454 f.f.freeValue(v2)
455 v3 := f.f.ConstBool(c.config.Types.Bool, false)
456 v4 := f.f.ConstBool(c.config.Types.Bool, true)
457 if v3.AuxInt != 0 {
458 t.Errorf("expected %s to have auxint of 0\n", v3.LongString())
459 }
460 if v4.AuxInt != 1 {
461 t.Errorf("expected %s to have auxint of 1\n", v4.LongString())
462 }
463
464 }
465
466
467
468 func opcodeMap(f *Func) map[Op]int {
469 m := map[Op]int{}
470 for _, b := range f.Blocks {
471 for _, v := range b.Values {
472 m[v.Op]++
473 }
474 }
475 return m
476 }
477
478
479
480 func checkOpcodeCounts(t *testing.T, f *Func, m map[Op]int) {
481 n := opcodeMap(f)
482 for op, cnt := range m {
483 if n[op] != cnt {
484 t.Errorf("%s appears %d times, want %d times", op, n[op], cnt)
485 }
486 }
487 }
488
View as plain text