Skip to content

Commit 9ffbc58

Browse files
GH-98831: Add some tests for generate_cases.py (#100763)
- This doesn't cover everything (far from it) but it's a start. - This uses pytest, which isn't ideal, but was quickest to get started. Co-authored-by: Kumar Aditya <[email protected]>
1 parent 0e64026 commit 9ffbc58

File tree

1 file changed

+310
-0
lines changed

1 file changed

+310
-0
lines changed
+310
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,310 @@
1+
# Sorry for using pytest, these tests are mostly just for me.
2+
# Use pytest -vv for best results.
3+
4+
import tempfile
5+
6+
import generate_cases
7+
8+
9+
def run_cases_test(input: str, expected: str):
10+
temp_input = tempfile.NamedTemporaryFile("w+")
11+
temp_input.write(generate_cases.BEGIN_MARKER)
12+
temp_input.write(input)
13+
temp_input.write(generate_cases.END_MARKER)
14+
temp_input.flush()
15+
temp_output = tempfile.NamedTemporaryFile("w+")
16+
a = generate_cases.Analyzer(temp_input.name, temp_output.name)
17+
a.parse()
18+
a.analyze()
19+
if a.errors:
20+
raise RuntimeError(f"Found {a.errors} errors")
21+
a.write_instructions()
22+
temp_output.seek(0)
23+
lines = temp_output.readlines()
24+
while lines and lines[0].startswith("// "):
25+
lines.pop(0)
26+
actual = "".join(lines)
27+
assert actual.rstrip() == expected.rstrip()
28+
29+
def test_legacy():
30+
input = """
31+
inst(OP) {
32+
spam();
33+
}
34+
"""
35+
output = """
36+
TARGET(OP) {
37+
spam();
38+
DISPATCH();
39+
}
40+
"""
41+
run_cases_test(input, output)
42+
43+
def test_inst_no_args():
44+
input = """
45+
inst(OP, (--)) {
46+
spam();
47+
}
48+
"""
49+
output = """
50+
TARGET(OP) {
51+
spam();
52+
DISPATCH();
53+
}
54+
"""
55+
run_cases_test(input, output)
56+
57+
def test_inst_one_pop():
58+
input = """
59+
inst(OP, (value --)) {
60+
spam();
61+
}
62+
"""
63+
output = """
64+
TARGET(OP) {
65+
PyObject *value = PEEK(1);
66+
spam();
67+
STACK_SHRINK(1);
68+
DISPATCH();
69+
}
70+
"""
71+
run_cases_test(input, output)
72+
73+
def test_inst_one_push():
74+
input = """
75+
inst(OP, (-- res)) {
76+
spam();
77+
}
78+
"""
79+
output = """
80+
TARGET(OP) {
81+
PyObject *res;
82+
spam();
83+
STACK_GROW(1);
84+
POKE(1, res);
85+
DISPATCH();
86+
}
87+
"""
88+
run_cases_test(input, output)
89+
90+
def test_inst_one_push_one_pop():
91+
input = """
92+
inst(OP, (value -- res)) {
93+
spam();
94+
}
95+
"""
96+
output = """
97+
TARGET(OP) {
98+
PyObject *value = PEEK(1);
99+
PyObject *res;
100+
spam();
101+
POKE(1, res);
102+
DISPATCH();
103+
}
104+
"""
105+
run_cases_test(input, output)
106+
107+
def test_binary_op():
108+
input = """
109+
inst(OP, (left, right -- res)) {
110+
spam();
111+
}
112+
"""
113+
output = """
114+
TARGET(OP) {
115+
PyObject *right = PEEK(1);
116+
PyObject *left = PEEK(2);
117+
PyObject *res;
118+
spam();
119+
STACK_SHRINK(1);
120+
POKE(1, res);
121+
DISPATCH();
122+
}
123+
"""
124+
run_cases_test(input, output)
125+
126+
def test_predictions():
127+
input = """
128+
inst(OP1, (--)) {
129+
}
130+
inst(OP2, (--)) {
131+
}
132+
inst(OP3, (--)) {
133+
DEOPT_IF(xxx, OP1);
134+
PREDICT(OP2);
135+
}
136+
"""
137+
output = """
138+
TARGET(OP1) {
139+
PREDICTED(OP1);
140+
DISPATCH();
141+
}
142+
143+
TARGET(OP2) {
144+
PREDICTED(OP2);
145+
DISPATCH();
146+
}
147+
148+
TARGET(OP3) {
149+
DEOPT_IF(xxx, OP1);
150+
PREDICT(OP2);
151+
DISPATCH();
152+
}
153+
"""
154+
run_cases_test(input, output)
155+
156+
def test_error_if_plain():
157+
input = """
158+
inst(OP, (--)) {
159+
ERROR_IF(cond, label);
160+
}
161+
"""
162+
output = """
163+
TARGET(OP) {
164+
if (cond) goto label;
165+
DISPATCH();
166+
}
167+
"""
168+
run_cases_test(input, output)
169+
170+
def test_error_if_pop():
171+
input = """
172+
inst(OP, (left, right -- res)) {
173+
ERROR_IF(cond, label);
174+
}
175+
"""
176+
output = """
177+
TARGET(OP) {
178+
PyObject *right = PEEK(1);
179+
PyObject *left = PEEK(2);
180+
PyObject *res;
181+
if (cond) goto pop_2_label;
182+
STACK_SHRINK(1);
183+
POKE(1, res);
184+
DISPATCH();
185+
}
186+
"""
187+
run_cases_test(input, output)
188+
189+
def test_cache_effect():
190+
input = """
191+
inst(OP, (counter/1, extra/2, value --)) {
192+
}
193+
"""
194+
output = """
195+
TARGET(OP) {
196+
PyObject *value = PEEK(1);
197+
uint16_t counter = read_u16(&next_instr[0].cache);
198+
uint32_t extra = read_u32(&next_instr[1].cache);
199+
STACK_SHRINK(1);
200+
JUMPBY(3);
201+
DISPATCH();
202+
}
203+
"""
204+
run_cases_test(input, output)
205+
206+
def test_suppress_dispatch():
207+
input = """
208+
inst(OP, (--)) {
209+
goto somewhere;
210+
}
211+
"""
212+
output = """
213+
TARGET(OP) {
214+
goto somewhere;
215+
}
216+
"""
217+
run_cases_test(input, output)
218+
219+
def test_super_instruction():
220+
# TODO: Test cache effect
221+
input = """
222+
inst(OP1, (counter/1, arg --)) {
223+
op1();
224+
}
225+
inst(OP2, (extra/2, arg --)) {
226+
op2();
227+
}
228+
super(OP) = OP1 + OP2;
229+
"""
230+
output = """
231+
TARGET(OP1) {
232+
PyObject *arg = PEEK(1);
233+
uint16_t counter = read_u16(&next_instr[0].cache);
234+
op1();
235+
STACK_SHRINK(1);
236+
JUMPBY(1);
237+
DISPATCH();
238+
}
239+
240+
TARGET(OP2) {
241+
PyObject *arg = PEEK(1);
242+
uint32_t extra = read_u32(&next_instr[0].cache);
243+
op2();
244+
STACK_SHRINK(1);
245+
JUMPBY(2);
246+
DISPATCH();
247+
}
248+
249+
TARGET(OP) {
250+
PyObject *_tmp_1 = PEEK(1);
251+
PyObject *_tmp_2 = PEEK(2);
252+
{
253+
PyObject *arg = _tmp_1;
254+
uint16_t counter = read_u16(&next_instr[0].cache);
255+
op1();
256+
}
257+
JUMPBY(1);
258+
NEXTOPARG();
259+
JUMPBY(1);
260+
{
261+
PyObject *arg = _tmp_2;
262+
uint32_t extra = read_u32(&next_instr[0].cache);
263+
op2();
264+
}
265+
JUMPBY(2);
266+
STACK_SHRINK(2);
267+
DISPATCH();
268+
}
269+
"""
270+
run_cases_test(input, output)
271+
272+
def test_macro_instruction():
273+
input = """
274+
inst(OP1, (counter/1, arg --)) {
275+
op1();
276+
}
277+
op(OP2, (extra/2, arg --)) {
278+
op2();
279+
}
280+
macro(OP) = OP1 + cache/2 + OP2;
281+
"""
282+
output = """
283+
TARGET(OP1) {
284+
PyObject *arg = PEEK(1);
285+
uint16_t counter = read_u16(&next_instr[0].cache);
286+
op1();
287+
STACK_SHRINK(1);
288+
JUMPBY(1);
289+
DISPATCH();
290+
}
291+
292+
TARGET(OP) {
293+
PyObject *_tmp_1 = PEEK(1);
294+
PyObject *_tmp_2 = PEEK(2);
295+
{
296+
PyObject *arg = _tmp_1;
297+
uint16_t counter = read_u16(&next_instr[0].cache);
298+
op1();
299+
}
300+
{
301+
PyObject *arg = _tmp_2;
302+
uint32_t extra = read_u32(&next_instr[3].cache);
303+
op2();
304+
}
305+
JUMPBY(5);
306+
STACK_SHRINK(2);
307+
DISPATCH();
308+
}
309+
"""
310+
run_cases_test(input, output)

0 commit comments

Comments
 (0)