def test_unroll_for_loop(self): program = """ def main() { real x = 1.0; for (int i = 0; i < 9; i = i + 1) { x = x + 2.0; } return x; } """ x = Variable('x', real_type) fix_expr = flow_to_meta_state(parse(program))[x] depth = 3 unrolled = list(unroll_fix_expr(fix_expr, depth)) program = """ def main() { real x = 1.0; for (int i = 0; i < 8; i = i + 2) { x = (x + 2.0) + 2.0; } x = x + 2.0; return x; } """ test_expr = flow_to_meta_state(parse(program))[x] self.assertEqual(test_expr, unrolled[1]) inputs = BoxState(bottom=True) for unrolled_expr in unrolled: self.assertEqual( arith_eval(fix_expr, inputs), arith_eval(unrolled_expr, inputs))
def test_unroll_fix_expr(self): program = """ def main() { real x = 0.0; while (x < 10) { x = x + 1.0; } return x; } """ x = Variable('x', real_type) fix_expr = flow_to_meta_state(parse(program))[x] unrolled = list(unroll_fix_expr(fix_expr, 2)) self.assertEqual(fix_expr, unrolled[0]) program = """ def main() { real x = 0.0; while (x < 10) { if (x + 1.0 < 10) { x = (x + 1.0) + 1.0; } else { x = x + 1.0; } } return x; } """ test_expr = flow_to_meta_state(parse(program))[x] self.assertEqual(test_expr, unrolled[1])
def test_nested_loop(self): program = """ def main(real[30] a) { for (int i = 1; i < 10; i = i + 1) { for (int j = 0; j < 20; j = j + 3) { a[i] = a[i - j] + 1; } } return a; } """ flow = parse(program) meta_state = flow_to_meta_state(flow) a = flow.outputs[0] i = Variable('i', int_type) j = Variable('j', int_type) fix_expr = meta_state[a] for_loop = ForLoopNestExtractor(fix_expr) expect_for_loop = { 'iter_vars': [i, j], 'iter_slices': [slice(1, 10, 1), slice(0, 20, 3)], 'kernel': fix_expr.loop_state[a].loop_state, } self.compare(for_loop, expect_for_loop)
def test_loop_nest_flow(self): program = """ def main(real[30] a) { int j = 0; while (j < 10) { int i = 0; while (i < 10) { a[i + j + 3] = a[i + j] + i; i = i + 1; } j = j + 1; } return a; } """ meta_state = flow_to_meta_state(parse(program)) latency = latency_eval(meta_state[self.a], [self.a]) distance = 3 trip_count = 10 * 10 depth = LATENCY_TABLE[real_type, operators.INDEX_ACCESS_OP] depth += LATENCY_TABLE[real_type, operators.ADD_OP] depth += LATENCY_TABLE[ArrayType, operators.INDEX_UPDATE_OP] expect_ii = depth / distance add_latency = LATENCY_TABLE[int_type, operators.ADD_OP] expect_latency = expect_ii * (trip_count - 1) + depth + add_latency self.assertAlmostEqual(latency, expect_latency)
def test_array_independence_initiation(self): program = """ def main(real[30] a) { for (int i = 0; i < 9; i = i + 1) { a[i] = a[i] + 1; } return a; } """ fix_expr = flow_to_meta_state(parse(program))[self.a] graph = LoopLatencyDependenceGraph(fix_expr) ii = graph.initiation_interval() expect_ii = 1 self.assertEqual(ii, expect_ii)
def test_simple_array_initiation(self): program = """ def main(real[30] a) { for (int i = 0; i < 9; i = i + 1) { a[i] = a[i - 3] + 1; } return a; } """ fix_expr = flow_to_meta_state(parse(program))[self.a] graph = LoopLatencyDependenceGraph(fix_expr) ii = graph.initiation_interval() expect_ii = LATENCY_TABLE[real_type, operators.INDEX_ACCESS_OP] expect_ii += LATENCY_TABLE[real_type, operators.ADD_OP] expect_ii += LATENCY_TABLE[ArrayType, operators.INDEX_UPDATE_OP] expect_ii /= 3 self.assertAlmostEqual(ii, expect_ii)
def test_full_flow(self): program = """ def main(real[30] a) { for (int i = 0; i < 10; i = i + 1) { a[i + 3] = a[i] + i; } return a; } """ meta_state = flow_to_meta_state(parse(program)) distance = 3 trip_count = 10 latency = latency_eval(meta_state, [self.a]) depth = LATENCY_TABLE[real_type, operators.INDEX_ACCESS_OP] depth += LATENCY_TABLE[real_type, operators.ADD_OP] depth += LATENCY_TABLE[ArrayType, operators.INDEX_UPDATE_OP] expect_ii = depth / distance expect_latency = expect_ii * (trip_count - 1) + depth self.assertAlmostEqual(latency, expect_latency)
def test_multi_dim_flow(self): program = """ def main(real[30, 30] b, int j) { for (int i = 0; i < 10; i = i + 1) { b[i + 3, j] = (b[i, j] + i) + j; } return b; } """ meta_state = flow_to_meta_state(parse(program)) latency = latency_eval(meta_state[self.b], [self.b]) distance = 3 trip_count = 10 depth = LATENCY_TABLE[real_type, operators.INDEX_ACCESS_OP] depth += LATENCY_TABLE[real_type, operators.ADD_OP] depth += LATENCY_TABLE[real_type, operators.ADD_OP] depth += LATENCY_TABLE[ArrayType, operators.INDEX_UPDATE_OP] expect_ii = depth / distance expect_latency = expect_ii * (trip_count - 1) + depth self.assertAlmostEqual(latency, expect_latency)
def test_function(self): expr = expression_factory( operators.ADD_OP, expression_factory(operators.ADD_OP, self.x, self.y), self.z) body = CompositionalFlow([ AssignFlow(self.z, expr), ReturnFlow([self.z]), ]) flow = FunctionFlow(Variable('main', function_type), [ (self.x, self.i1), (self.y, ErrorSemantics([3.0, 4.0])), (self.z, ErrorSemantics([5, 6], [0, 0])), ], body) prog = """ def main(int x=1, real y=[3.0, 4.0], real z=[5.0, 6.0][0, 0]) { z = x + y + z; return z; } """ parsed_flow = parse(prog) self.assertEqual(flow, parsed_flow)
def test_simple_loop(self): program = """ def main(real[30] a) { for (int i = 1; i < 10; i = i + 1) { a[i] = a[i - 1] + 1; } return a; } """ flow = parse(program) meta_state = flow_to_meta_state(flow) fix_expr = meta_state[flow.outputs[0]] for_loop = ForLoopExtractor(fix_expr) expect_for_loop = { 'iter_var': self.i, 'start': IntegerInterval(1), 'stop': IntegerInterval(10), 'step': IntegerInterval(1), 'has_inner_loops': False, } self.compare(for_loop, expect_for_loop)
def test_resource_constraint_on_ii(self): program = """ def main(real[30] a) { for (int i = 0; i < 10; i = i + 1) { a[i] = a[i] + a[i + 1] + a[i + 2] + a[i + 3]; } return a; } """ meta_state = flow_to_meta_state(parse(program)) latency = latency_eval(meta_state[self.a], [self.a]) trip_count = 10 depth = LATENCY_TABLE[int_type, operators.ADD_OP] depth += LATENCY_TABLE[real_type, operators.INDEX_ACCESS_OP] depth += LATENCY_TABLE[real_type, operators.ADD_OP] depth += LATENCY_TABLE[real_type, operators.ADD_OP] depth += LATENCY_TABLE[real_type, operators.ADD_OP] depth += LATENCY_TABLE[ArrayType, operators.INDEX_UPDATE_OP] expect_ii = 5 / 2 expect_latency = (trip_count - 1) * expect_ii + depth self.assertAlmostEqual(latency, expect_latency)
def test_variable_initiation(self): program = """ def main(real x) { for (int i = 0; i < 9; i = i + 1) { x = x + 1; } return x; } """ fix_expr = flow_to_meta_state(parse(program))[self.x] graph = LoopLatencyDependenceGraph(fix_expr) ii = graph.initiation_interval() expect_ii = LATENCY_TABLE[real_type, operators.ADD_OP] self.assertAlmostEqual(ii, expect_ii) trip_count = graph.trip_count() self.assertEqual(trip_count, 9) latency = graph.latency() expect_latency = (trip_count - 1) * ii + graph.depth() self.assertAlmostEqual(latency, expect_latency)