summaryrefslogtreecommitdiffstats
path: root/Tools/cases_generator
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2023-01-06 16:04:20 (GMT)
committerGitHub <noreply@github.com>2023-01-06 16:04:20 (GMT)
commit9ffbc58f5cb6d2b002f8785886588d646af517db (patch)
treeaa7a2197118955b81ab8494c8f713a28628e6a24 /Tools/cases_generator
parent0e640260dac2db081e56f52f8efb0e43e463ff2f (diff)
downloadcpython-9ffbc58f5cb6d2b002f8785886588d646af517db.zip
cpython-9ffbc58f5cb6d2b002f8785886588d646af517db.tar.gz
cpython-9ffbc58f5cb6d2b002f8785886588d646af517db.tar.bz2
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 <59607654+kumaraditya303@users.noreply.github.com>
Diffstat (limited to 'Tools/cases_generator')
-rw-r--r--Tools/cases_generator/test_generator.py310
1 files changed, 310 insertions, 0 deletions
diff --git a/Tools/cases_generator/test_generator.py b/Tools/cases_generator/test_generator.py
new file mode 100644
index 0000000..e707a53
--- /dev/null
+++ b/Tools/cases_generator/test_generator.py
@@ -0,0 +1,310 @@
+# Sorry for using pytest, these tests are mostly just for me.
+# Use pytest -vv for best results.
+
+import tempfile
+
+import generate_cases
+
+
+def run_cases_test(input: str, expected: str):
+ temp_input = tempfile.NamedTemporaryFile("w+")
+ temp_input.write(generate_cases.BEGIN_MARKER)
+ temp_input.write(input)
+ temp_input.write(generate_cases.END_MARKER)
+ temp_input.flush()
+ temp_output = tempfile.NamedTemporaryFile("w+")
+ a = generate_cases.Analyzer(temp_input.name, temp_output.name)
+ a.parse()
+ a.analyze()
+ if a.errors:
+ raise RuntimeError(f"Found {a.errors} errors")
+ a.write_instructions()
+ temp_output.seek(0)
+ lines = temp_output.readlines()
+ while lines and lines[0].startswith("// "):
+ lines.pop(0)
+ actual = "".join(lines)
+ assert actual.rstrip() == expected.rstrip()
+
+def test_legacy():
+ input = """
+ inst(OP) {
+ spam();
+ }
+ """
+ output = """
+ TARGET(OP) {
+ spam();
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_inst_no_args():
+ input = """
+ inst(OP, (--)) {
+ spam();
+ }
+ """
+ output = """
+ TARGET(OP) {
+ spam();
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_inst_one_pop():
+ input = """
+ inst(OP, (value --)) {
+ spam();
+ }
+ """
+ output = """
+ TARGET(OP) {
+ PyObject *value = PEEK(1);
+ spam();
+ STACK_SHRINK(1);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_inst_one_push():
+ input = """
+ inst(OP, (-- res)) {
+ spam();
+ }
+ """
+ output = """
+ TARGET(OP) {
+ PyObject *res;
+ spam();
+ STACK_GROW(1);
+ POKE(1, res);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_inst_one_push_one_pop():
+ input = """
+ inst(OP, (value -- res)) {
+ spam();
+ }
+ """
+ output = """
+ TARGET(OP) {
+ PyObject *value = PEEK(1);
+ PyObject *res;
+ spam();
+ POKE(1, res);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_binary_op():
+ input = """
+ inst(OP, (left, right -- res)) {
+ spam();
+ }
+ """
+ output = """
+ TARGET(OP) {
+ PyObject *right = PEEK(1);
+ PyObject *left = PEEK(2);
+ PyObject *res;
+ spam();
+ STACK_SHRINK(1);
+ POKE(1, res);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_predictions():
+ input = """
+ inst(OP1, (--)) {
+ }
+ inst(OP2, (--)) {
+ }
+ inst(OP3, (--)) {
+ DEOPT_IF(xxx, OP1);
+ PREDICT(OP2);
+ }
+ """
+ output = """
+ TARGET(OP1) {
+ PREDICTED(OP1);
+ DISPATCH();
+ }
+
+ TARGET(OP2) {
+ PREDICTED(OP2);
+ DISPATCH();
+ }
+
+ TARGET(OP3) {
+ DEOPT_IF(xxx, OP1);
+ PREDICT(OP2);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_error_if_plain():
+ input = """
+ inst(OP, (--)) {
+ ERROR_IF(cond, label);
+ }
+ """
+ output = """
+ TARGET(OP) {
+ if (cond) goto label;
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_error_if_pop():
+ input = """
+ inst(OP, (left, right -- res)) {
+ ERROR_IF(cond, label);
+ }
+ """
+ output = """
+ TARGET(OP) {
+ PyObject *right = PEEK(1);
+ PyObject *left = PEEK(2);
+ PyObject *res;
+ if (cond) goto pop_2_label;
+ STACK_SHRINK(1);
+ POKE(1, res);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_cache_effect():
+ input = """
+ inst(OP, (counter/1, extra/2, value --)) {
+ }
+ """
+ output = """
+ TARGET(OP) {
+ PyObject *value = PEEK(1);
+ uint16_t counter = read_u16(&next_instr[0].cache);
+ uint32_t extra = read_u32(&next_instr[1].cache);
+ STACK_SHRINK(1);
+ JUMPBY(3);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_suppress_dispatch():
+ input = """
+ inst(OP, (--)) {
+ goto somewhere;
+ }
+ """
+ output = """
+ TARGET(OP) {
+ goto somewhere;
+ }
+ """
+ run_cases_test(input, output)
+
+def test_super_instruction():
+ # TODO: Test cache effect
+ input = """
+ inst(OP1, (counter/1, arg --)) {
+ op1();
+ }
+ inst(OP2, (extra/2, arg --)) {
+ op2();
+ }
+ super(OP) = OP1 + OP2;
+ """
+ output = """
+ TARGET(OP1) {
+ PyObject *arg = PEEK(1);
+ uint16_t counter = read_u16(&next_instr[0].cache);
+ op1();
+ STACK_SHRINK(1);
+ JUMPBY(1);
+ DISPATCH();
+ }
+
+ TARGET(OP2) {
+ PyObject *arg = PEEK(1);
+ uint32_t extra = read_u32(&next_instr[0].cache);
+ op2();
+ STACK_SHRINK(1);
+ JUMPBY(2);
+ DISPATCH();
+ }
+
+ TARGET(OP) {
+ PyObject *_tmp_1 = PEEK(1);
+ PyObject *_tmp_2 = PEEK(2);
+ {
+ PyObject *arg = _tmp_1;
+ uint16_t counter = read_u16(&next_instr[0].cache);
+ op1();
+ }
+ JUMPBY(1);
+ NEXTOPARG();
+ JUMPBY(1);
+ {
+ PyObject *arg = _tmp_2;
+ uint32_t extra = read_u32(&next_instr[0].cache);
+ op2();
+ }
+ JUMPBY(2);
+ STACK_SHRINK(2);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)
+
+def test_macro_instruction():
+ input = """
+ inst(OP1, (counter/1, arg --)) {
+ op1();
+ }
+ op(OP2, (extra/2, arg --)) {
+ op2();
+ }
+ macro(OP) = OP1 + cache/2 + OP2;
+ """
+ output = """
+ TARGET(OP1) {
+ PyObject *arg = PEEK(1);
+ uint16_t counter = read_u16(&next_instr[0].cache);
+ op1();
+ STACK_SHRINK(1);
+ JUMPBY(1);
+ DISPATCH();
+ }
+
+ TARGET(OP) {
+ PyObject *_tmp_1 = PEEK(1);
+ PyObject *_tmp_2 = PEEK(2);
+ {
+ PyObject *arg = _tmp_1;
+ uint16_t counter = read_u16(&next_instr[0].cache);
+ op1();
+ }
+ {
+ PyObject *arg = _tmp_2;
+ uint32_t extra = read_u32(&next_instr[3].cache);
+ op2();
+ }
+ JUMPBY(5);
+ STACK_SHRINK(2);
+ DISPATCH();
+ }
+ """
+ run_cases_test(input, output)