1
2
3
4
5 package ssacompile
6
7 import (
8 "testing"
9
10 "cmd/compile/internal/ssa"
11 "cmd/compile/internal/ssa/ssaop"
12 "cmd/compile/internal/types"
13 )
14
15 func TestSchedule(t *testing.T) {
16 c := testConfig(t)
17 cases := []fun{
18 c.Fun("entry",
19 Bloc("entry",
20 Valu("mem0", ssaop.OpInitMem, types.TypeMem, 0, nil),
21 Valu("ptr", ssaop.OpConst64, c.config.Types.Int64, 0xABCD, nil),
22 Valu("v", ssaop.OpConst64, c.config.Types.Int64, 12, nil),
23 Valu("mem1", ssaop.OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "v", "mem0"),
24 Valu("mem2", ssaop.OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "v", "mem1"),
25 Valu("mem3", ssaop.OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "sum", "mem2"),
26 Valu("l1", ssaop.OpLoad, c.config.Types.Int64, 0, nil, "ptr", "mem1"),
27 Valu("l2", ssaop.OpLoad, c.config.Types.Int64, 0, nil, "ptr", "mem2"),
28 Valu("sum", ssaop.OpAdd64, c.config.Types.Int64, 0, nil, "l1", "l2"),
29 Goto("exit")),
30 Bloc("exit",
31 Exit("mem3"))),
32 }
33 for _, c := range cases {
34 schedule(c.f)
35 if !isSingleLiveMem(c.f) {
36 t.Error("single-live-mem restriction not enforced by schedule for func:")
37 ssa.PrintFunc(c.f)
38 }
39 }
40 }
41
42 func isSingleLiveMem(f *ssa.Func) bool {
43 for _, b := range f.Blocks {
44 var liveMem *ssa.Value
45 for _, v := range b.Values {
46 for _, w := range v.Args {
47 if w.Type.IsMemory() {
48 if liveMem == nil {
49 liveMem = w
50 continue
51 }
52 if w != liveMem {
53 return false
54 }
55 }
56 }
57 if v.Type.IsMemory() {
58 liveMem = v
59 }
60 }
61 }
62 return true
63 }
64
65 func TestStoreOrder(t *testing.T) {
66
67
68 c := testConfig(t)
69 fun := c.Fun("entry",
70 Bloc("entry",
71 Valu("mem0", ssaop.OpInitMem, types.TypeMem, 0, nil),
72 Valu("a", ssaop.OpAdd64, c.config.Types.Int64, 0, nil, "b", "c"),
73 Valu("b", ssaop.OpLoad, c.config.Types.Int64, 0, nil, "ptr", "mem1"),
74 Valu("c", ssaop.OpNeg64, c.config.Types.Int64, 0, nil, "b"),
75 Valu("mem1", ssaop.OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "v", "mem0"),
76 Valu("mem2", ssaop.OpStore, types.TypeMem, 0, c.config.Types.Int64, "ptr", "a", "mem1"),
77 Valu("ptr", ssaop.OpConst64, c.config.Types.Int64, 0xABCD, nil),
78 Valu("v", ssaop.OpConst64, c.config.Types.Int64, 12, nil),
79 Goto("exit")),
80 Bloc("exit",
81 Exit("mem2")))
82
83 CheckFunc(fun.f)
84 order := storeOrder(fun.f.Blocks[0].Values, fun.f.NewSparseSet(fun.f.NumValues()), make([]int32, fun.f.NumValues()))
85
86
87 var ai, bi, ci, si int
88 for i, v := range order {
89 switch v.ID {
90 case 2:
91 ai = i
92 case 3:
93 bi = i
94 case 4:
95 ci = i
96 case 5:
97 si = i
98 }
99 }
100 if ai < si || bi < si || ci < si {
101 t.Logf("Func: %s", fun.f)
102 t.Errorf("store order is wrong: got %v, want v2 v3 v4 after v5", order)
103 }
104 }
105
106 func TestCarryChainOrder(t *testing.T) {
107
108
109
110 c := testConfigARM64(t)
111 fun := c.Fun("entry",
112 Bloc("entry",
113 Valu("mem0", ssaop.OpInitMem, types.TypeMem, 0, nil),
114 Valu("x", ssaop.OpARM64MOVDconst, c.config.Types.UInt64, 5, nil),
115 Valu("y", ssaop.OpARM64MOVDconst, c.config.Types.UInt64, 6, nil),
116 Valu("z", ssaop.OpARM64MOVDconst, c.config.Types.UInt64, 7, nil),
117 Valu("A1", ssaop.OpARM64ADDSflags, types.NewTuple(c.config.Types.UInt64, types.TypeFlags), 0, nil, "x", "z"),
118 Valu("A1carry", ssaop.OpSelect1, types.TypeFlags, 0, nil, "A1"),
119 Valu("A2", ssaop.OpARM64ADDSflags, types.NewTuple(c.config.Types.UInt64, types.TypeFlags), 0, nil, "y", "z"),
120 Valu("A2carry", ssaop.OpSelect1, types.TypeFlags, 0, nil, "A2"),
121 Valu("A1value", ssaop.OpSelect0, c.config.Types.UInt64, 0, nil, "A1"),
122 Valu("A1Carryvalue", ssaop.OpARM64ADCzerocarry, c.config.Types.UInt64, 0, nil, "A1carry"),
123 Valu("A2value", ssaop.OpSelect0, c.config.Types.UInt64, 0, nil, "A2"),
124 Valu("A2Carryvalue", ssaop.OpARM64ADCzerocarry, c.config.Types.UInt64, 0, nil, "A2carry"),
125 Valu("ValueSum", ssaop.OpARM64ADD, c.config.Types.UInt64, 0, nil, "A1value", "A2value"),
126 Valu("CarrySum", ssaop.OpARM64ADD, c.config.Types.UInt64, 0, nil, "A1Carryvalue", "A2Carryvalue"),
127 Valu("Sum", ssaop.OpARM64AND, c.config.Types.UInt64, 0, nil, "ValueSum", "CarrySum"),
128 Goto("exit")),
129 Bloc("exit",
130 Exit("mem0")),
131 )
132
133 CheckFunc(fun.f)
134 schedule(fun.f)
135
136
137
138
139
140 var ai, bi, ci, di, ei, fi int
141 for i, v := range fun.f.Blocks[0].Values {
142 switch {
143 case fun.values["A1"] == v:
144 ai = i
145 case fun.values["A1carry"] == v:
146 bi = i
147 case fun.values["A1Carryvalue"] == v:
148 ci = i
149 case fun.values["A2"] == v:
150 di = i
151 case fun.values["A2carry"] == v:
152 ei = i
153 case fun.values["A2Carryvalue"] == v:
154 fi = i
155 }
156 }
157 if !(ai < bi && bi < ci && ci < di && di < ei && ei < fi) {
158 t.Logf("Func: %s", fun.f)
159 t.Errorf("carry chain order is wrong: got %v, want V%d after V%d after V%d after V%d after V%d after V%d,",
160 fun.f.Blocks[0], fun.values["A1"].ID, fun.values["A1carry"].ID, fun.values["A1Carryvalue"].ID,
161 fun.values["A2"].ID, fun.values["A2carry"].ID, fun.values["A2Carryvalue"].ID)
162 }
163 }
164
View as plain text