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 Eq(cond, sub, alt string) ctrl {
255 return ctrl{BlockAMD64EQ, cond, []string{sub, alt}}
256 }
257
258
259
260
261 type bloc struct {
262 name string
263 control ctrl
264 valus []valu
265 }
266
267 type ctrl struct {
268 kind BlockKind
269 control string
270 succs []string
271 }
272
273 type valu struct {
274 name string
275 op Op
276 t *types.Type
277 auxint int64
278 aux Aux
279 args []string
280 }
281
282 func TestArgs(t *testing.T) {
283 c := testConfig(t)
284 fun := c.Fun("entry",
285 Bloc("entry",
286 Valu("a", OpConst64, c.config.Types.Int64, 14, nil),
287 Valu("b", OpConst64, c.config.Types.Int64, 26, nil),
288 Valu("sum", OpAdd64, c.config.Types.Int64, 0, nil, "a", "b"),
289 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
290 Goto("exit")),
291 Bloc("exit",
292 Exit("mem")))
293 sum := fun.values["sum"]
294 for i, name := range []string{"a", "b"} {
295 if sum.Args[i] != fun.values[name] {
296 t.Errorf("arg %d for sum is incorrect: want %s, got %s",
297 i, sum.Args[i], fun.values[name])
298 }
299 }
300 }
301
302 func TestEquiv(t *testing.T) {
303 cfg := testConfig(t)
304 equivalentCases := []struct{ f, g fun }{
305
306 {
307 cfg.Fun("entry",
308 Bloc("entry",
309 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
310 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
311 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
312 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
313 Goto("exit")),
314 Bloc("exit",
315 Exit("mem"))),
316 cfg.Fun("entry",
317 Bloc("entry",
318 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
319 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
320 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
321 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
322 Goto("exit")),
323 Bloc("exit",
324 Exit("mem"))),
325 },
326
327 {
328 cfg.Fun("entry",
329 Bloc("entry",
330 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
331 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
332 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
333 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
334 Goto("exit")),
335 Bloc("exit",
336 Exit("mem"))),
337 cfg.Fun("entry",
338 Bloc("exit",
339 Exit("mem")),
340 Bloc("entry",
341 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
342 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
343 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
344 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
345 Goto("exit"))),
346 },
347 }
348 for _, c := range equivalentCases {
349 if !Equiv(c.f.f, c.g.f) {
350 t.Error("expected equivalence. Func definitions:")
351 t.Error(c.f.f)
352 t.Error(c.g.f)
353 }
354 }
355
356 differentCases := []struct{ f, g fun }{
357
358 {
359 cfg.Fun("entry",
360 Bloc("entry",
361 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
362 Goto("exit")),
363 Bloc("exit",
364 Exit("mem"))),
365 cfg.Fun("entry",
366 Bloc("entry",
367 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
368 Exit("mem"))),
369 },
370
371 {
372 cfg.Fun("entry",
373 Bloc("entry",
374 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
375 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
376 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
377 Exit("mem"))),
378 cfg.Fun("entry",
379 Bloc("entry",
380 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
381 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
382 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
383 Exit("mem"))),
384 },
385
386 {
387 cfg.Fun("entry",
388 Bloc("entry",
389 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
390 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
391 Exit("mem"))),
392 cfg.Fun("entry",
393 Bloc("entry",
394 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
395 Valu("a", OpConst64, cfg.config.Types.Int64, 26, nil),
396 Exit("mem"))),
397 },
398
399 {
400 cfg.Fun("entry",
401 Bloc("entry",
402 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
403 Valu("a", OpConstString, cfg.config.Types.String, 0, StringToAux("foo")),
404 Exit("mem"))),
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("bar")),
409 Exit("mem"))),
410 },
411
412 {
413 cfg.Fun("entry",
414 Bloc("entry",
415 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
416 Valu("a", OpConst64, cfg.config.Types.Int64, 14, nil),
417 Valu("b", OpConst64, cfg.config.Types.Int64, 26, nil),
418 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "a", "b"),
419 Exit("mem"))),
420 cfg.Fun("entry",
421 Bloc("entry",
422 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
423 Valu("a", OpConst64, cfg.config.Types.Int64, 0, nil),
424 Valu("b", OpConst64, cfg.config.Types.Int64, 14, nil),
425 Valu("sum", OpAdd64, cfg.config.Types.Int64, 0, nil, "b", "a"),
426 Exit("mem"))),
427 },
428 }
429 for _, c := range differentCases {
430 if Equiv(c.f.f, c.g.f) {
431 t.Error("expected difference. Func definitions:")
432 t.Error(c.f.f)
433 t.Error(c.g.f)
434 }
435 }
436 }
437
438
439
440 func TestConstCache(t *testing.T) {
441 c := testConfig(t)
442 f := c.Fun("entry",
443 Bloc("entry",
444 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
445 Exit("mem")))
446 v1 := f.f.ConstBool(c.config.Types.Bool, false)
447 v2 := f.f.ConstBool(c.config.Types.Bool, true)
448 f.f.freeValue(v1)
449 f.f.freeValue(v2)
450 v3 := f.f.ConstBool(c.config.Types.Bool, false)
451 v4 := f.f.ConstBool(c.config.Types.Bool, true)
452 if v3.AuxInt != 0 {
453 t.Errorf("expected %s to have auxint of 0\n", v3.LongString())
454 }
455 if v4.AuxInt != 1 {
456 t.Errorf("expected %s to have auxint of 1\n", v4.LongString())
457 }
458
459 }
460
461
462
463 func opcodeMap(f *Func) map[Op]int {
464 m := map[Op]int{}
465 for _, b := range f.Blocks {
466 for _, v := range b.Values {
467 m[v.Op]++
468 }
469 }
470 return m
471 }
472
473
474
475 func checkOpcodeCounts(t *testing.T, f *Func, m map[Op]int) {
476 n := opcodeMap(f)
477 for op, cnt := range m {
478 if n[op] != cnt {
479 t.Errorf("%s appears %d times, want %d times", op, n[op], cnt)
480 }
481 }
482 }
483
View as plain text