1
2
3
4
5 package ssa
6
7 import (
8 "cmd/compile/internal/types"
9 "testing"
10 )
11
12 func TestLiveControlOps(t *testing.T) {
13 c := testConfig(t)
14 f := c.Fun("entry",
15 Bloc("entry",
16 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
17 Valu("x", OpAMD64MOVLconst, c.config.Types.Int8, 1, nil),
18 Valu("y", OpAMD64MOVLconst, c.config.Types.Int8, 2, nil),
19 Valu("a", OpAMD64TESTB, types.TypeFlags, 0, nil, "x", "y"),
20 Valu("b", OpAMD64TESTB, types.TypeFlags, 0, nil, "y", "x"),
21 Eq("a", "if", "exit"),
22 ),
23 Bloc("if",
24 Eq("b", "plain", "exit"),
25 ),
26 Bloc("plain",
27 Goto("exit"),
28 ),
29 Bloc("exit",
30 Exit("mem"),
31 ),
32 )
33 flagalloc(f.f)
34 regalloc(f.f)
35 checkFunc(f.f)
36 }
37
38
39
40 func TestNoGetgLoadReg(t *testing.T) {
41
51 c := testConfigARM64(t)
52 f := c.Fun("b1",
53 Bloc("b1",
54 Valu("v1", OpInitMem, types.TypeMem, 0, nil),
55 Valu("v6", OpArg, c.config.Types.Int64, 0, c.Temp(c.config.Types.Int64)),
56 Valu("v8", OpGetG, c.config.Types.Int64.PtrTo(), 0, nil, "v1"),
57 Valu("v11", OpARM64CMPconst, types.TypeFlags, 0, nil, "v6"),
58 Eq("v11", "b2", "b4"),
59 ),
60 Bloc("b4",
61 Goto("b3"),
62 ),
63 Bloc("b3",
64 Valu("v14", OpPhi, types.TypeMem, 0, nil, "v1", "v12"),
65 Valu("sb", OpSB, c.config.Types.Uintptr, 0, nil),
66 Valu("v16", OpARM64MOVDstore, types.TypeMem, 0, nil, "v8", "sb", "v14"),
67 Exit("v16"),
68 ),
69 Bloc("b2",
70 Valu("v12", OpARM64CALLstatic, types.TypeMem, 0, AuxCallLSym("_"), "v1"),
71 Goto("b3"),
72 ),
73 )
74 regalloc(f.f)
75 checkFunc(f.f)
76
77 r := f.f.RegAlloc
78 for _, b := range f.blocks {
79 for _, v := range b.Values {
80 if v.Op == OpLoadReg && r[v.ID].String() == "g" {
81 t.Errorf("Saw OpLoadReg targeting g register: %s", v.LongString())
82 }
83 }
84 }
85 }
86
87
88
89 func TestSpillWithLoop(t *testing.T) {
90 c := testConfig(t)
91 f := c.Fun("entry",
92 Bloc("entry",
93 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
94 Valu("ptr", OpArg, c.config.Types.Int64.PtrTo(), 0, c.Temp(c.config.Types.Int64)),
95 Valu("cond", OpArg, c.config.Types.Bool, 0, c.Temp(c.config.Types.Bool)),
96 Valu("ld", OpAMD64MOVQload, c.config.Types.Int64, 0, nil, "ptr", "mem"),
97 Goto("loop"),
98 ),
99 Bloc("loop",
100 Valu("memphi", OpPhi, types.TypeMem, 0, nil, "mem", "call"),
101 Valu("call", OpAMD64CALLstatic, types.TypeMem, 0, AuxCallLSym("_"), "memphi"),
102 Valu("test", OpAMD64CMPBconst, types.TypeFlags, 0, nil, "cond"),
103 Eq("test", "next", "exit"),
104 ),
105 Bloc("next",
106 Goto("loop"),
107 ),
108 Bloc("exit",
109 Valu("store", OpAMD64MOVQstore, types.TypeMem, 0, nil, "ptr", "ld", "call"),
110 Exit("store"),
111 ),
112 )
113 regalloc(f.f)
114 checkFunc(f.f)
115 for _, v := range f.blocks["loop"].Values {
116 if v.Op == OpStoreReg {
117 t.Errorf("spill inside loop %s", v.LongString())
118 }
119 }
120 }
121
122 func TestSpillMove1(t *testing.T) {
123 c := testConfig(t)
124 f := c.Fun("entry",
125 Bloc("entry",
126 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
127 Valu("x", OpArg, c.config.Types.Int64, 0, c.Temp(c.config.Types.Int64)),
128 Valu("p", OpArg, c.config.Types.Int64.PtrTo(), 0, c.Temp(c.config.Types.Int64.PtrTo())),
129 Valu("a", OpAMD64TESTQ, types.TypeFlags, 0, nil, "x", "x"),
130 Goto("loop1"),
131 ),
132 Bloc("loop1",
133 Valu("y", OpAMD64MULQ, c.config.Types.Int64, 0, nil, "x", "x"),
134 Eq("a", "loop2", "exit1"),
135 ),
136 Bloc("loop2",
137 Eq("a", "loop1", "exit2"),
138 ),
139 Bloc("exit1",
140
141 Valu("mem2", OpAMD64MOVQstore, types.TypeMem, 0, nil, "p", "y", "mem"),
142 Valu("mem3", OpAMD64CALLstatic, types.TypeMem, 0, AuxCallLSym("_"), "mem2"),
143 Exit("mem3"),
144 ),
145 Bloc("exit2",
146
147 Valu("mem4", OpAMD64CALLstatic, types.TypeMem, 0, AuxCallLSym("_"), "mem"),
148 Valu("mem5", OpAMD64MOVQstore, types.TypeMem, 0, nil, "p", "y", "mem4"),
149 Exit("mem5"),
150 ),
151 )
152 flagalloc(f.f)
153 regalloc(f.f)
154 checkFunc(f.f)
155
156 if numSpills(f.blocks["loop1"]) != 0 {
157 t.Errorf("spill present from loop1")
158 }
159 if numSpills(f.blocks["loop2"]) != 0 {
160 t.Errorf("spill present in loop2")
161 }
162 if numSpills(f.blocks["exit1"]) != 0 {
163 t.Errorf("spill present in exit1")
164 }
165 if numSpills(f.blocks["exit2"]) != 1 {
166 t.Errorf("spill missing in exit2")
167 }
168
169 }
170
171 func TestSpillMove2(t *testing.T) {
172 c := testConfig(t)
173 f := c.Fun("entry",
174 Bloc("entry",
175 Valu("mem", OpInitMem, types.TypeMem, 0, nil),
176 Valu("x", OpArg, c.config.Types.Int64, 0, c.Temp(c.config.Types.Int64)),
177 Valu("p", OpArg, c.config.Types.Int64.PtrTo(), 0, c.Temp(c.config.Types.Int64.PtrTo())),
178 Valu("a", OpAMD64TESTQ, types.TypeFlags, 0, nil, "x", "x"),
179 Goto("loop1"),
180 ),
181 Bloc("loop1",
182 Valu("y", OpAMD64MULQ, c.config.Types.Int64, 0, nil, "x", "x"),
183 Eq("a", "loop2", "exit1"),
184 ),
185 Bloc("loop2",
186 Eq("a", "loop1", "exit2"),
187 ),
188 Bloc("exit1",
189
190 Valu("mem2", OpAMD64CALLstatic, types.TypeMem, 0, AuxCallLSym("_"), "mem"),
191 Valu("mem3", OpAMD64MOVQstore, types.TypeMem, 0, nil, "p", "y", "mem2"),
192 Exit("mem3"),
193 ),
194 Bloc("exit2",
195
196 Valu("mem4", OpAMD64CALLstatic, types.TypeMem, 0, AuxCallLSym("_"), "mem"),
197 Valu("mem5", OpAMD64MOVQstore, types.TypeMem, 0, nil, "p", "y", "mem4"),
198 Exit("mem5"),
199 ),
200 )
201 flagalloc(f.f)
202 regalloc(f.f)
203 checkFunc(f.f)
204
205
206 if numSpills(f.blocks["loop1"]) != 1 {
207 t.Errorf("spill missing from loop1")
208 }
209 if numSpills(f.blocks["loop2"]) != 0 {
210 t.Errorf("spill present in loop2")
211 }
212 if numSpills(f.blocks["exit1"]) != 0 {
213 t.Errorf("spill present in exit1")
214 }
215 if numSpills(f.blocks["exit2"]) != 0 {
216 t.Errorf("spill present in exit2")
217 }
218
219 }
220
221 func numSpills(b *Block) int {
222 n := 0
223 for _, v := range b.Values {
224 if v.Op == OpStoreReg {
225 n++
226 }
227 }
228 return n
229 }
230
View as plain text