def test_sccp_dead_loop(self): simple = textwrap.dedent(""" #include <pykit_ir.h> Int32 f(Int32 i) { Int32 x, y, z; x = 2; y = 3; z = 4; while (y < x) { if (y < x) { x = 1; x = x + 1; y = x - z; } } return x + z; } """) mod = from_c(simple) f = mod.get_function("f") cfa.run(f) sccp.run(f) verify(f) verify(f) ops = list(f.ops) assert len(list(f.ops)) == 1 [op] = ops assert op.opcode == 'ret' assert isinstance(op.args[0], Const) self.assertEqual(op.args[0].const, 6)
def test_sccp_endless_loop(self): simple = textwrap.dedent(""" #include <pykit_ir.h> Int32 f(Int32 i) { Int32 x, y, z; x = 2; y = 3; z = 4; while (x < y) { if (x < y) { x = 2; } } return x + z; } """) mod = from_c(simple) f = mod.get_function("f") cfa.run(f) sccp.run(f) verify(f) assert len(f.blocks) == 2 start, loop = f.blocks assert start.terminator.opcode == 'jump' assert start.terminator.args[0] == loop assert loop.terminator.opcode == 'jump' assert loop.terminator.args[0] == loop
def test_swap(self): simple = textwrap.dedent(""" #include <pykit_ir.h> int f(int i) { int x = 1; int y = 2; int tmp; while (i > 0) { tmp = x; x = y; y = tmp; i = i - 1; } return x; } """) mod = from_c(simple) func = mod.get_function("f") cfa.run(func) verify(func) ssa_result1 = interp.run(func, args=[1]) ssa_result2 = interp.run(func, args=[2]) reg2mem.reg2mem(func) verify(func) stack_result1 = interp.run(func, args=[1]) stack_result2 = interp.run(func, args=[2]) self.assertEqual(ssa_result1, stack_result1) self.assertEqual(ssa_result2, stack_result2)
def test_inline2(self): harder = """ int callee(int i) { (void) print(i); while (i < 10) { i = i + 1; return i * 2; } return i; } int caller() { int x = 4; while (x < 10) { (void) print(x); x = call(callee, list(x)); } return x; } """ mod = from_c(harder) func = mod.get_function("caller") verify(func) result = interp.run(func) [callsite] = findallops(func, 'call') inline.inline(func, callsite) cfa.run(func) verify(func)
def test_ssa2(self): mod = from_c(source) f = mod.get_function('func') cfa.run(f) verify(f) codes = opcodes(f) self.assertEqual(codes.count('phi'), 3)
def test_sccp(self): simple = textwrap.dedent(""" #include <pykit_ir.h> Int32 f(Int32 i) { Int32 x, y, z; x = 2; y = 3; z = 4; if (x < y) x = y; else x = i; return x + z; } """) mod = from_c(simple) f = mod.get_function("f") cfa.run(f) sccp.run(f) verify(f) ops = list(f.ops) assert len(list(f.ops)) == 1 [op] = ops assert op.opcode == 'ret' assert isinstance(op.args[0], Const) self.assertEqual(op.args[0].const, 7)
def test_inline2(self): harder = textwrap.dedent(""" int callee(int i) { (void) print(i); while (i < 10) { i = i + 1; return i * 2; } return i; } int caller() { int x = 4; while (x < 10) { (void) print(x); x = call(callee, list(x)); } return x; } """) mod = from_c(harder) func = mod.get_function("caller") verify(func) result = interp.run(func) [callsite] = findallops(func, 'call') inline.inline(func, callsite) cfa.run(func) verify(func) # TODO: update phi when splitting blocks result2 = interp.run(func) assert result == result2
def test_inline2(self): harder = textwrap.dedent(""" int callee(int i) { (void) print(i); while (i < 10) { i = i + 1; return i * 2; } return i; } int caller() { int x = 4; while (x < 10) { (void) print(x); x = call(callee, list(x)); } return x; } """) mod = from_c(harder) func = mod.get_function("caller") verify(func) result = interp.run(func) [callsite] = findallops(func, 'call') inline.inline(func, callsite) cfa.run(func) verify(func)
def test_cfg(self): mod = from_c(source) f = mod.get_function('func_simple') verify(f) flow = cfa.cfg(f) cond_block = findop(f, 'cbranch').block self.assertEqual(len(flow[cond_block]), 2)
def inline(func, call, uses=None): """ Inline the call instruction into func. :param uses: defuse information """ callee = call.args[0] # assert_inlinable(func, call, callee, uses) builder = Builder(func) builder.position_before(call) inline_header, inline_exit = builder.splitblock() new_callee = copy_function(callee, temper=func.temp) result = rewrite_return(new_callee) # Fix up arguments for funcarg, arg in zip(new_callee.args, call.args[1]): funcarg.replace_uses(arg) # Copy blocks after = inline_header for block in new_callee.blocks: block.parent = None func.add_block(block, after=after) after = block # Fix up wiring builder.jump(new_callee.startblock) with builder.at_end(new_callee.exitblock): builder.jump(inline_exit) # Fix up final result of call if result is not None: # non-void return result.unlink() result.result = call.result call.replace(result) else: call.delete() func.reset_uses() verify(func)
def test_swap_loop(self): simple = textwrap.dedent(""" #include <pykit_ir.h> int f(int i, int j) { int x = 1; int y = 2; int tmp; while (i > 0) { while (j > 0) { tmp = x; x = y; y = tmp; j = j - 1; } i = i - 1; } return x; } """) mod = from_c(simple) func = mod.get_function("f") cfa.run(func) verify(func) ssa_results = [] for i in range(10): for j in range(10): ssa_result = interp.run(func, args=[i, j]) ssa_results.append(ssa_result) #print(func) reg2mem.reg2mem(func) verify(func) #print(func) stack_results = [] for i in range(10): for j in range(10): stack_result = interp.run(func, args=[i, j]) stack_results.append(stack_result)
def test_ops(self): source = textwrap.dedent(""" #include <pykit_ir.h> Int32 f(Int32 i) { Int32 x; x = 2; if (x < 3) x = x + 1; if (x <= 3) x = x + 1; if (x >= 3) x = x + 1; if (x >= 3) x = x + 1; if (x > 3) x = x + 1; return x; } """) mod = from_c(source) f = mod.get_function("f") remove_convert(f) cfa.run(f) sccp.run(f) verify(f) # print(f) ops = list(f.ops) assert len(list(f.ops)) == 1 [op] = ops assert op.opcode == 'ret' assert isinstance(op.args[0], Const) self.assertEqual(op.args[0].const, 7)
def test_inline(self): simple = """ #include <pykit_ir.h> int callee(int i) { return i * i; } int caller(int i) { int x = call(callee, list(i)); return x; } """ mod = from_c(simple) func = mod.get_function("caller") [callsite] = findallops(func, 'call') inline.inline(func, callsite) cfa.run(func) verify(func) assert interp.run(func, args=[10]) == 100 assert len(list(func.blocks)) == 1 assert opcodes(func) == ['mul', 'ret']
def test_ssa(self): mod = from_c(source) f = mod.get_function('func_simple') verify(f) self.assertEqual(opcodes(f.startblock), ['alloca', 'store', 'load', 'gt', 'cbranch']) # SSA CFG = cfa.cfg(f) cfa.ssa(f, CFG) assert len(f.blocks) == 4 blocks = list(f.blocks) self.assertEqual(opcodes(blocks[0]), ['gt', 'cbranch']) self.assertEqual(opcodes(blocks[1]), ['jump']) self.assertEqual(opcodes(blocks[2]), ['jump']) self.assertEqual(opcodes(blocks[3]), ['phi', 'convert', 'ret']) phi = findop(f, 'phi') iblocks, ivals = phi.args self.assertEqual(sorted(iblocks), sorted([blocks[1], blocks[2]])) self.assertEqual(len(ivals), 2)
def test_inline(self): simple = textwrap.dedent(""" #include <pykit_ir.h> int callee(int i) { return i * i; } int caller(int i) { int x = call(callee, list(i)); return x; } """) mod = from_c(simple) func = mod.get_function("caller") [callsite] = findallops(func, 'call') inline.inline(func, callsite) cfa.run(func) verify(func) assert interp.run(func, args=[10]) == 100 assert len(list(func.blocks)) == 1 assert opcodes(func) == ['mul', 'ret']
def test_ssa(self): mod = from_c(source) f = mod.get_function('func_simple') verify(f) self.assertEqual(opcodes(f.startblock), ['alloca', 'store', 'load', 'gt', 'cbranch']) # SSA CFG = cfa.cfg(f) cfa.ssa(f, CFG) assert len(f.blocks) == 4 blocks = list(f.blocks) self.assertEqual(opcodes(blocks[0]), ['gt', 'cbranch']) self.assertEqual(opcodes(blocks[1]), ['jump']) self.assertEqual(opcodes(blocks[2]), ['jump']) self.assertEqual(opcodes(blocks[3]), ['phi', 'ret']) phi = findop(f, 'phi') iblocks, ivals = phi.args self.assertEqual(sorted(iblocks), sorted([blocks[1], blocks[2]])) self.assertEqual(len(ivals), 2)
def test_inline(self): simple = textwrap.dedent(""" #include <pykit_ir.h> int callee(int i) { return i * i; } int caller(int i) { int x = call(callee, list(i)); return x; } """) mod = from_c(simple) func = mod.get_function("caller") [callsite] = findallops(func, 'call') inline.inline(func, callsite) cfa.run(func) verify(func) assert interp.run(func, args=[10]) == 100 assert len(list(func.blocks)) == 1 self.assertEqual([o for o in opcodes(func) if o != 'convert'], ['mul', 'ret'])
Int32 i, sum = 0; for (i = 0; i < 10; i = i + 1) { sum = sum + i; } return sum; } Int32 raise() { Exception exc = new_exc("TypeError", ""); exc_throw(exc); return 0; } """ mod = cirparser.from_c(source) verify(mod) class TestInterp(unittest.TestCase): def test_simple(self): f = mod.get_function('simple') result = interp.run(f, args=[10.0]) assert result == 100.0, result def test_loop(self): loop = mod.get_function('loop') result = interp.run(loop) assert result == 45, result def test_exceptions(self): f = mod.get_function('raise')
int i, sum = 0; for (i = 0; i < 10; i = i + 1) { sum = sum + i; } return sum; } int raise() { Exception exc = new_exc("TypeError", list()); exc_throw(exc); return 0; } """ mod = cirparser.from_c(source) verify(mod) class TestInterp(unittest.TestCase): def test_simple(self): f = mod.get_function('simple') result = interp.run(f, args=[10.0]) assert result == 100.0, result def test_loop(self): loop = mod.get_function('loop') result = interp.run(loop) assert result == 45, result def test_exceptions(self): f = mod.get_function('raise')
def test_parse(self): mod = cirparser.from_c(source) verify(mod) func = mod.get_function('myfunc') result = interp.run(func, args=[10.0]) self.assertEqual(result, 12)