class TestBuilder(unittest.TestCase): def setUp(self): self.f = Function("testfunc", ['a'], types.Function(types.Float32, [types.Int32])) self.b = Builder(self.f) self.b.position_at_end(self.f.add_block('entry')) self.a = self.f.get_arg('a') def test_basic_builder(self): v = self.b.alloca(types.Pointer(types.Float32), []) result = self.b.mul(types.Int32, [self.a, self.a], result='r') c = self.b.convert(types.Float32, [result]) self.b.store(c, v) val = self.b.load(types.Float32, [v]) self.b.ret(val) # print(string(self.f)) self.assertEqual(str(self.f).strip(), basic_expected) def test_splitblock(self): old, new = self.b.splitblock('newblock') with self.b.at_front(old): self.b.add(types.Int32, [self.a, self.a]) with self.b.at_end(new): self.b.div(types.Int32, [self.a, self.a]) # print(string(self.f)) self.assertEqual(split_expected, string(self.f)) def test_loop_builder(self): square = self.b.mul(types.Int32, [self.a, self.a]) c = self.b.convert(types.Float32, [square]) self.b.position_after(square) _, block = self.b.splitblock('start', terminate=True) self.b.position_at_end(block) const = partial(Const, type=types.Int32) cond, body, exit = self.b.gen_loop(const(5), const(10), const(2)) with self.b.at_front(body): self.b.print_(c) with self.b.at_end(exit): self.b.ret(c) # print(string(self.f)) # verify.verify(self.f) # self.assertEqual(loop_expected, string(self.f)) # TestBuilder('test_basic_builder').debug() # TestBuilder('test_splitblock').debug() # TestBuilder('test_loop_builder').debug() # unittest.main()
def run(func, env=None, return_block=None): """ Rewrite 'ret' operations into jumps to a return block and assignments to a return variable. """ b = Builder(func) return_block = return_block or func.new_block("pykit.return") # Allocate return variable if not func.type.restype.is_void: with b.at_front(func.startblock): return_var = b.alloca(types.Pointer(func.type.restype), []) b.store(Undef(func.type.restype), return_var) else: return_var = None # Repace 'ret' instructions with jumps and assignments for op in func.ops: if op.opcode == "ret": b.position_after(op) if return_var: b.store(op.args[0], return_var) b.jump(return_block) op.delete() with b.at_end(return_block): if return_var: result = b.load(return_var.type.base, [return_var]) else: result = None b.ret(result)
def run(func, env=None, return_block=None): """ Rewrite 'ret' operations into jumps to a return block and assignments to a return variable. """ b = Builder(func) return_block = return_block or func.new_block("pykit.return") # Allocate return variable if not func.type.restype.is_void: with b.at_front(func.startblock): return_var = b.alloca(types.Pointer(func.type.restype)) b.store(Undef(func.type.restype), return_var) else: return_var = None # Repace 'ret' instructions with jumps and assignments for op in func.ops: if op.opcode == "ret": b.position_after(op) if return_var: b.store(op.args[0], return_var) b.jump(return_block) op.delete() with b.at_end(return_block): if return_var: result = b.load(return_var) else: result = None b.ret(result)
class TestBuilder(unittest.TestCase): def setUp(self): self.f = Function("testfunc", ['a'], types.Function(types.Float32, [types.Int32])) self.b = Builder(self.f) self.b.position_at_end(self.f.new_block('entry')) self.a = self.f.get_arg('a') def test_basic_builder(self): v = self.b.alloca(types.Pointer(types.Float32), []) result = self.b.mul(types.Int32, [self.a, self.a], result='r') c = self.b.convert(types.Float32, [result]) self.b.store(c, v) val = self.b.load(types.Float32, [v]) self.b.ret(val) # print(string(self.f)) assert interp.run(self.f, args=[10]) == 100 def test_splitblock(self): old, new = self.b.splitblock('newblock') with self.b.at_front(old): self.b.add(types.Int32, [self.a, self.a]) with self.b.at_end(new): self.b.div(types.Int32, [self.a, self.a]) self.assertEqual(opcodes(self.f), ['add', 'div']) def test_loop_builder(self): square = self.b.mul(types.Int32, [self.a, self.a]) c = self.b.convert(types.Float32, [square]) self.b.position_after(square) _, block = self.b.splitblock('start', terminate=True) self.b.position_at_end(block) const = partial(Const, type=types.Int32) cond, body, exit = self.b.gen_loop(const(5), const(10), const(2)) with self.b.at_front(body): self.b.print(c) with self.b.at_end(exit): self.b.ret(c) self.assertEqual(interp.run(self.f, args=[10]), 100.0)
def move_generator(func, consumer, empty_body): gen = consumer.generator gen.unlink() b = Builder(func) b.position_at_end(empty_body) b.emit(gen) with b.at_end(empty_body): loop_exit = determine_loop_exit(consumer.loop) b.jump(loop_exit)
def inline(func, call): """ Inline the call instruction into func. :return: { old_op : new_op } """ callee = call.args[0] callblock = call.block # assert_inlinable(func, call, callee, uses) builder = Builder(func) builder.position_before(call) inline_header, inline_exit = builder.splitblock() new_callee, valuemap = 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 new_blocks = list(new_callee.blocks) after = inline_header for block in new_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) stretch_exception_block(builder, callblock, new_blocks) # 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) return valuemap
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)
class TestBuilder(unittest.TestCase): def setUp(self): self.f = Function("testfunc", ['a'], types.Function(types.Float32, [types.Int32], False)) self.b = Builder(self.f) self.b.position_at_end(self.f.new_block('entry')) self.a = self.f.get_arg('a') def test_basic_builder(self): v = self.b.alloca(types.Pointer(types.Float32)) result = self.b.mul(self.a, self.a, result='r') c = self.b.convert(types.Float32, result) self.b.store(c, v) val = self.b.load(v) self.b.ret(val) # print(string(self.f)) assert interp.run(self.f, args=[10]) == 100 def test_splitblock(self): old, new = self.b.splitblock('newblock') with self.b.at_front(old): self.b.add(self.a, self.a) with self.b.at_end(new): self.b.div(self.a, self.a) self.assertEqual(opcodes(self.f), ['add', 'div']) def test_loop_builder(self): square = self.b.mul(self.a, self.a) c = self.b.convert(types.Float32, square) self.b.position_after(square) _, block = self.b.splitblock('start', terminate=True) self.b.position_at_end(block) const = partial(Const, type=types.Int32) cond, body, exit = self.b.gen_loop(const(5), const(10), const(2)) with self.b.at_front(body): self.b.print(c) with self.b.at_end(exit): self.b.ret(c) self.assertEqual(interp.run(self.f, args=[10]), 100.0) def test_splitblock_preserve_phis(self): """ block1: %0 = mul a a jump(newblock) newblock: %1 = phi([block1], [%0]) ret %1 """ square = self.b.mul(self.a, self.a) old, new = self.b.splitblock('newblock', terminate=True) with self.b.at_front(new): phi = self.b.phi(types.Int32, [self.f.startblock], [square]) self.b.ret(phi) # Now split block1 self.b.position_after(square) block1, split = self.b.splitblock(terminate=True) phi, ret = new.ops blocks, values = phi.args self.assertEqual(blocks, [split])