From 4ca7e231a16ba26bac222f9baf40a7ec50dafc66 Mon Sep 17 00:00:00 2001 From: Kenneth Moon Date: Thu, 16 May 2024 15:47:00 -0400 Subject: [PATCH] Add new metaprogramming tests --- src/exo/frontend/pyparser.py | 10 +- .../test_quote_complex_expr.txt | 16 ++ .../test_quote_elision.txt | 17 ++ .../test_scope_collision1.txt | 18 ++ .../test_scope_collision2.txt | 17 ++ .../test_statement_assignment.txt | 19 ++ .../test_type_quote_elision.txt | 18 ++ .../test_unquote_elision.txt | 16 ++ .../test_unquote_in_slice.txt | 25 +++ .../test_unquote_index_tuple.txt | 26 +++ .../test_unquote_slice_object1.txt | 31 +++ tests/test_metaprogramming.py | 198 ++++++++++++++++++ 12 files changed, 408 insertions(+), 3 deletions(-) create mode 100644 tests/golden/test_metaprogramming/test_quote_complex_expr.txt create mode 100644 tests/golden/test_metaprogramming/test_quote_elision.txt create mode 100644 tests/golden/test_metaprogramming/test_scope_collision1.txt create mode 100644 tests/golden/test_metaprogramming/test_scope_collision2.txt create mode 100644 tests/golden/test_metaprogramming/test_statement_assignment.txt create mode 100644 tests/golden/test_metaprogramming/test_type_quote_elision.txt create mode 100644 tests/golden/test_metaprogramming/test_unquote_elision.txt create mode 100644 tests/golden/test_metaprogramming/test_unquote_in_slice.txt create mode 100644 tests/golden/test_metaprogramming/test_unquote_index_tuple.txt create mode 100644 tests/golden/test_metaprogramming/test_unquote_slice_object1.txt diff --git a/src/exo/frontend/pyparser.py b/src/exo/frontend/pyparser.py index 04f8c47af..7593192c4 100644 --- a/src/exo/frontend/pyparser.py +++ b/src/exo/frontend/pyparser.py @@ -1260,7 +1260,7 @@ def parse_array_indexing(self, node): def unquote_to_index(unquoted, ref_node, srcinfo, top_level): if isinstance(unquoted, (int, float)): - return self.AST.Const(unquoted, self.getsrcinfo(e)) + return self.AST.Const(unquoted, srcinfo) elif isinstance(unquoted, ExoExpression) and isinstance( unquoted._inner, self.AST.expr ): @@ -1271,12 +1271,16 @@ def unquote_to_index(unquoted, ref_node, srcinfo, top_level): ( None if unquoted.start is None - else unquote_to_index(unquoted.start, False) + else unquote_to_index( + unquoted.start, ref_node, srcinfo, False + ) ), ( None if unquoted.stop is None - else unquote_to_index(unquoted.stop, False) + else unquote_to_index( + unquoted.stop, ref_node, srcinfo, False + ) ), srcinfo, ) diff --git a/tests/golden/test_metaprogramming/test_quote_complex_expr.txt b/tests/golden/test_metaprogramming/test_quote_complex_expr.txt new file mode 100644 index 000000000..f92456404 --- /dev/null +++ b/tests/golden/test_metaprogramming/test_quote_complex_expr.txt @@ -0,0 +1,16 @@ +#include "test.h" + + + +#include +#include + + + +// foo( +// a : i32 @DRAM +// ) +void foo( void *ctxt, int32_t* a ) { +*a = *a + ((int32_t) 1) + ((int32_t) 1); +} + diff --git a/tests/golden/test_metaprogramming/test_quote_elision.txt b/tests/golden/test_metaprogramming/test_quote_elision.txt new file mode 100644 index 000000000..90a35203f --- /dev/null +++ b/tests/golden/test_metaprogramming/test_quote_elision.txt @@ -0,0 +1,17 @@ +#include "test.h" + + + +#include +#include + + + +// foo( +// a : i32 @DRAM, +// b : i32 @DRAM +// ) +void foo( void *ctxt, const int32_t* a, int32_t* b ) { +*b = *a; +} + diff --git a/tests/golden/test_metaprogramming/test_scope_collision1.txt b/tests/golden/test_metaprogramming/test_scope_collision1.txt new file mode 100644 index 000000000..78ac1e832 --- /dev/null +++ b/tests/golden/test_metaprogramming/test_scope_collision1.txt @@ -0,0 +1,18 @@ +#include "test.h" + + + +#include +#include + + + +// foo( +// a : i32 @DRAM +// ) +void foo( void *ctxt, int32_t* a ) { +int32_t b; +b = ((int32_t) 2); +*a = ((int32_t) 1); +} + diff --git a/tests/golden/test_metaprogramming/test_scope_collision2.txt b/tests/golden/test_metaprogramming/test_scope_collision2.txt new file mode 100644 index 000000000..90a35203f --- /dev/null +++ b/tests/golden/test_metaprogramming/test_scope_collision2.txt @@ -0,0 +1,17 @@ +#include "test.h" + + + +#include +#include + + + +// foo( +// a : i32 @DRAM, +// b : i32 @DRAM +// ) +void foo( void *ctxt, const int32_t* a, int32_t* b ) { +*b = *a; +} + diff --git a/tests/golden/test_metaprogramming/test_statement_assignment.txt b/tests/golden/test_metaprogramming/test_statement_assignment.txt new file mode 100644 index 000000000..a289e8c8a --- /dev/null +++ b/tests/golden/test_metaprogramming/test_statement_assignment.txt @@ -0,0 +1,19 @@ +#include "test.h" + + + +#include +#include + + + +// foo( +// a : i32 @DRAM +// ) +void foo( void *ctxt, int32_t* a ) { +*a += ((int32_t) 1); +*a += ((int32_t) 2); +*a += ((int32_t) 1); +*a += ((int32_t) 2); +} + diff --git a/tests/golden/test_metaprogramming/test_type_quote_elision.txt b/tests/golden/test_metaprogramming/test_type_quote_elision.txt new file mode 100644 index 000000000..70514d6cd --- /dev/null +++ b/tests/golden/test_metaprogramming/test_type_quote_elision.txt @@ -0,0 +1,18 @@ +#include "test.h" + + + +#include +#include + + + +// foo( +// a : i8 @DRAM, +// x : i8[2] @DRAM +// ) +void foo( void *ctxt, int8_t* a, const int8_t* x ) { +*a += x[0]; +*a += x[1]; +} + diff --git a/tests/golden/test_metaprogramming/test_unquote_elision.txt b/tests/golden/test_metaprogramming/test_unquote_elision.txt new file mode 100644 index 000000000..96f1bfedc --- /dev/null +++ b/tests/golden/test_metaprogramming/test_unquote_elision.txt @@ -0,0 +1,16 @@ +#include "test.h" + + + +#include +#include + + + +// foo( +// a : i32 @DRAM +// ) +void foo( void *ctxt, int32_t* a ) { +*a = *a * ((int32_t) 2); +} + diff --git a/tests/golden/test_metaprogramming/test_unquote_in_slice.txt b/tests/golden/test_metaprogramming/test_unquote_in_slice.txt new file mode 100644 index 000000000..ef1b0745f --- /dev/null +++ b/tests/golden/test_metaprogramming/test_unquote_in_slice.txt @@ -0,0 +1,25 @@ +#include "test.h" + + + +#include +#include + + + +// bar( +// a : i8[10, 10] @DRAM +// ) +void bar( void *ctxt, int8_t* a ) { +for (int_fast32_t i = 0; i < 5; i++) { + foo(ctxt,(struct exo_win_1i8){ &a[(i) * (10) + 2], { 1 } }); +} +} + +// foo( +// a : [i8][2] @DRAM +// ) +void foo( void *ctxt, struct exo_win_1i8 a ) { +a.data[0] += a.data[a.strides[0]]; +} + diff --git a/tests/golden/test_metaprogramming/test_unquote_index_tuple.txt b/tests/golden/test_metaprogramming/test_unquote_index_tuple.txt new file mode 100644 index 000000000..0e7a23536 --- /dev/null +++ b/tests/golden/test_metaprogramming/test_unquote_index_tuple.txt @@ -0,0 +1,26 @@ +#include "test.h" + + + +#include +#include + + + +// bar( +// a : i8[10, 10, 10] @DRAM +// ) +void bar( void *ctxt, int8_t* a ) { +for (int_fast32_t i = 0; i < 7; i++) { + foo(ctxt,(struct exo_win_2i8){ &a[(i) * (100) + (i) * (10) + i + 1], { 10, 1 } }); +} +} + +// foo( +// a : [i8][2, 2] @DRAM +// ) +void foo( void *ctxt, struct exo_win_2i8 a ) { +a.data[0] += a.data[a.strides[1]]; +a.data[a.strides[0]] += a.data[a.strides[0] + a.strides[1]]; +} + diff --git a/tests/golden/test_metaprogramming/test_unquote_slice_object1.txt b/tests/golden/test_metaprogramming/test_unquote_slice_object1.txt new file mode 100644 index 000000000..e58a29815 --- /dev/null +++ b/tests/golden/test_metaprogramming/test_unquote_slice_object1.txt @@ -0,0 +1,31 @@ +#include "test.h" + + + +#include +#include + + + +// bar( +// a : i8[10, 10] @DRAM +// ) +void bar( void *ctxt, int8_t* a ) { +for (int_fast32_t i = 0; i < 10; i++) { + foo(ctxt,(struct exo_win_1i8){ &a[(i) * (10) + 1], { 1 } }); +} +for (int_fast32_t i = 0; i < 10; i++) { + foo(ctxt,(struct exo_win_1i8){ &a[(i) * (10) + 5], { 1 } }); +} +for (int_fast32_t i = 0; i < 10; i++) { + foo(ctxt,(struct exo_win_1i8){ &a[(i) * (10) + 2], { 1 } }); +} +} + +// foo( +// a : [i8][2] @DRAM +// ) +void foo( void *ctxt, struct exo_win_1i8 a ) { +a.data[0] += a.data[a.strides[0]]; +} + diff --git a/tests/test_metaprogramming.py b/tests/test_metaprogramming.py index 93bfe7459..8157f6d6a 100644 --- a/tests/test_metaprogramming.py +++ b/tests/test_metaprogramming.py @@ -1,6 +1,8 @@ from __future__ import annotations from exo import proc, compile_procs_to_strings from exo.API_scheduling import rename +from exo.pyparser import ParseError +import pytest def test_unrolling(golden): @@ -140,3 +142,199 @@ def foo(a: i32): c_file, _ = compile_procs_to_strings([foo], "test.h") assert c_file == golden + + +def test_quote_elision(golden): + @proc + def foo(a: i32, b: i32): + with meta: + + def bar(): + return a + + with ~meta: + b = {bar()} + + c_file, _ = compile_procs_to_strings([foo], "test.h") + assert c_file == golden + + +def test_unquote_elision(golden): + @proc + def foo(a: i32): + with meta: + x = 2 + with ~meta: + a = a * x + + c_file, _ = compile_procs_to_strings([foo], "test.h") + assert c_file == golden + + +def test_scope_collision1(golden): + @proc + def foo(a: i32): + with meta: + b = 1 + with ~meta: + b: i32 + b = 2 + with meta: + c = b + with ~meta: + a = c + + c_file, _ = compile_procs_to_strings([foo], "test.h") + assert c_file == golden + + +def test_scope_collision2(golden): + @proc + def foo(a: i32, b: i32): + with meta: + a = 1 + with ~meta: + b = a + + c_file, _ = compile_procs_to_strings([foo], "test.h") + assert c_file == golden + + +def test_scope_collision3(): + with pytest.raises( + NameError, + match="free variable 'x' referenced before assignment in enclosing scope", + ): + + @proc + def foo(a: i32, b: i32): + with meta: + with ~meta: + a = b * x + x = 1 + + +def test_type_quote_elision(golden): + T = "i8" + + @proc + def foo(a: T, x: T[2]): + a += x[0] + a += x[1] + + c_file, _ = compile_procs_to_strings([foo], "test.h") + assert c_file == golden + + +def test_unquote_in_slice(golden): + @proc + def foo(a: [i8][2]): + a[0] += a[1] + + @proc + def bar(a: i8[10, 10]): + with meta: + x = 2 + with ~meta: + for i in seq(0, 5): + foo(a[i, {x} : {2 * x}]) + + c_file, _ = compile_procs_to_strings([foo, bar], "test.h") + assert c_file == golden + + +def test_unquote_slice_object1(golden): + @proc + def foo(a: [i8][2]): + a[0] += a[1] + + @proc + def bar(a: i8[10, 10]): + with meta: + for s in [slice(1, 3), slice(5, 7), slice(2, 4)]: + with ~meta: + for i in seq(0, 10): + foo(a[i, s]) + + c_file, _ = compile_procs_to_strings([foo, bar], "test.h") + assert c_file == golden + + +def test_unquote_slice_object2(): + with pytest.raises( + ParseError, match="cannot perform windowing on left-hand-side of an assignment" + ): + + @proc + def foo(a: i8[10, 10]): + with meta: + for s in [slice(1, 3), slice(5, 7), slice(2, 4)]: + with ~meta: + for i in seq(0, 10): + a[i, s] = 2 + + +def test_unquote_index_tuple(golden): + @proc + def foo(a: [i8][2, 2]): + a[0, 0] += a[0, 1] + a[1, 0] += a[1, 1] + + @proc + def bar(a: i8[10, 10, 10]): + with meta: + + def get_index(i): + return slice(i, ~{i + 2}), slice(~{i + 1}, ~{i + 3}) + + with ~meta: + for i in seq(0, 7): + foo(a[i, {get_index(i)}]) + + c_file, _ = compile_procs_to_strings([foo, bar], "test.h") + assert c_file == golden + + +def test_unquote_err(): + with pytest.raises( + ParseError, match="Unquote computation did not yield valid type" + ): + T = 1 + + @proc + def foo(a: T): + a += 1 + + +def test_quote_complex_expr(golden): + @proc + def foo(a: i32): + with meta: + + def bar(x): + return ~{x + 1} + + with ~meta: + a = {bar(~{a + 1})} + + c_file, _ = compile_procs_to_strings([foo], "test.h") + assert c_file == golden + + +def test_statement_assignment(golden): + @proc + def foo(a: i32): + with meta: + with ~meta as s1: + a += 1 + a += 2 + with ~meta as s2: + a += 3 + a += 4 + s = s1 if True else s2 + with ~meta: + {s} + {s} + + c_file, _ = compile_procs_to_strings([foo], "test.h") + assert c_file == golden