def test_normal_use(self): alloc = self.builder.emit(ir.Alloc('A', 4, 4)) addr = self.builder.emit(ir.AddressOf(alloc, 'addr')) cnst = self.builder.emit(ir.Const(1, 'cnst', ir.i32)) self.builder.emit(ir.Store(cnst, addr)) self.builder.emit(ir.Load(addr, 'Ld', ir.i32)) self.builder.emit(ir.Exit()) self.mem2reg.run(self.module) self.assertNotIn(alloc, self.function.entry.instructions)
def test_byte_lift(self): """ Test byte data type to work """ alloc = self.builder.emit(ir.Alloc('A', 1, 1)) addr = self.builder.emit(ir.AddressOf(alloc, 'addr')) cnst = self.builder.emit(ir.Const(1, 'cnst', ir.i8)) self.builder.emit(ir.Store(cnst, addr)) self.builder.emit(ir.Load(addr, 'Ld', ir.i8)) self.builder.emit(ir.Exit()) self.mem2reg.run(self.module) self.assertNotIn(alloc, self.function.entry.instructions)
def test_different_type_not_lifted(self): """ different types must persist """ alloc = self.builder.emit(ir.Alloc('A', 1, 1)) addr = self.builder.emit(ir.AddressOf(alloc, 'addr')) cnst = self.builder.emit(ir.Const(1, 'cnst', ir.i32)) self.builder.emit(ir.Store(cnst, addr)) self.builder.emit(ir.Load(addr, 'Ld', ir.i8)) self.builder.emit(ir.Exit()) self.mem2reg.run(self.module) self.assertIn(alloc, self.function.entry.instructions)
def test_bug1(self): """ This is the bug: function XXX sleep(i32 ms) entry: JUMP block12 block12: i32 loaded = load global_tick i32 binop = loaded + ms JUMP block14 block14: i32 loaded_2 = load global_tick IF binop > loaded_2 THEN block14 ELSE epilog epilog: exit Selection graph for function XXX sleep(i32 ms) entry: MOVI32[vreg0ms](REGI32[R1]) JMP[bsp_sleep_block12:] block12: MOVI32[vreg1loaded](LDRI32(LABEL[bsp_global_tick])) JMP[bsp_sleep_block14:] block14: MOVI32[vreg4loaded_2](LDRI32(LABEL[bsp_global_tick])) CJMP[('>', bsp_sleep_block14:, bsp_sleep_epilog:)] (REGI32[vreg5binop], REGI32[vreg4loaded_2]) epilog: """ builder = Builder() module = ir.Module('fuzz') global_tick = ir.Variable('global_tick', ir.Binding.GLOBAL, 4, 4) module.add_variable(global_tick) builder.module = module function = builder.new_procedure('sleep', ir.Binding.GLOBAL) ms = ir.Parameter('ms', ir.i32) function.add_parameter(ms) builder.set_function(function) entry = builder.new_block() function.entry = entry builder.set_block(entry) block12 = builder.new_block() builder.emit(ir.Jump(block12)) builder.set_block(block12) loaded = builder.emit(ir.Load(global_tick, 'loaded', ir.i32)) binop = builder.emit(ir.Binop(loaded, '+', ms, 'binop', ir.i32)) block14 = builder.new_block() builder.emit(ir.Jump(block14)) builder.set_block(block14) loaded2 = builder.emit(ir.Load(global_tick, 'loaded2', ir.i32)) epilog = builder.new_block() builder.emit(ir.CJump(binop, '>', loaded2, block14, epilog)) builder.set_block(epilog) builder.emit(ir.Exit()) # print('module:') # print_module(module) # Target generation target = ExampleArch() frame = target.new_frame('a', function) function_info = FunctionInfo(frame) debug_db = DebugDb() prepare_function_info(target, function_info, function) dag_builder = SelectionGraphBuilder(target) sgraph = dag_builder.build(function, function_info, debug_db) dag_splitter = DagSplitter(target) # print(function_info.value_map) for b in function: # root = function_info.block_roots[b] #print('root=', root) #for tree in dag_splitter.split_into_trees(root, frame): # print('tree=', tree) pass
def load_var(self, var_name): mem_loc = self.variables[var_name] return self.emit(ir.Load(mem_loc, var_name, self.int_type))
def generate_function(self, wasm_function, debug_db): stack = [] block_stack = [] ppci_function = self.builder.new_function('main', self.get_ir_type('')) self.builder.set_function(ppci_function) db_float = debuginfo.DebugBaseType('double', 8, 1) db_function_info = debuginfo.DebugFunction( 'main', common.SourceLocation('main.wasm', 1, 1, 1), db_float, ()) debug_db.enter(ppci_function, db_function_info) entryblock = self.new_block() self.builder.set_block(entryblock) ppci_function.entry = entryblock localmap = {} for i, local in enumerate(wasm_function.locals): localmap[i] = self.emit(ir.Alloc(f'local{i}', 8)) for nr, instruction in enumerate(wasm_function.instructions, start=1): inst = instruction.type print(f'{nr}/{len(wasm_function.instructions)} {inst}') if inst in ('f64.add', 'f64.sub', 'f64.mul', 'f64.div'): itype, opname = inst.split('.') op = dict(add='+', sub='-', mul='*', div='/')[opname] b, a = stack.pop(), stack.pop() value = self.emit( ir.Binop(a, op, b, opname, self.get_ir_type(itype))) stack.append(value) elif inst in ('f64.eq', 'f64.ne', 'f64.ge', 'f64.gt', 'f64.le', 'f64.lt'): b, a = stack.pop(), stack.pop() stack.append(( inst.split('.')[1], a, b)) # todo: hack; we assume this is the only test in an if elif inst == 'f64.floor': value1 = self.emit(ir.Cast(stack.pop(), 'floor_cast_1', ir.i64)) value2 = self.emit(ir.Cast(value1, 'floor_cast_2', ir.f64)) stack.append(value2) elif inst == 'f64.const': value = self.emit( ir.Const(instruction.args[0], 'const', self.get_ir_type(inst))) stack.append(value) elif inst == 'set_local': value = stack.pop() self.emit(ir.Store(value, localmap[instruction.args[0]])) elif inst == 'get_local': value = self.emit( ir.Load(localmap[instruction.args[0]], 'getlocal', self.get_ir_type(inst))) stack.append(value) elif inst == 'f64.neg': zero = self.emit(ir.Const(0, 'zero', self.get_ir_type(inst))) value = self.emit( ir.sub(zero, stack.pop(), 'neg', self.get_ir_type(inst))) stack.append(value) elif inst == 'block': innerblock = self.new_block() continueblock = self.new_block() self.emit(ir.Jump(innerblock)) self.builder.set_block(innerblock) block_stack.append(('block', continueblock, innerblock)) elif inst == 'loop': innerblock = self.new_block() continueblock = self.new_block() self.emit(ir.Jump(innerblock)) self.builder.set_block(innerblock) block_stack.append(('loop', continueblock, innerblock)) elif inst == 'br': depth = instruction.args[0] blocktype, continueblock, innerblock = block_stack[-depth - 1] targetblock = innerblock if blocktype == 'loop' else continueblock self.emit(ir.Jump(targetblock)) falseblock = self.new_block() # unreachable self.builder.set_block(falseblock) elif inst == 'br_if': opmap = dict(eq='==', ne='!=', ge='>=', le='<=', gt='>', lt='<') op, a, b = stack.pop() depth = instruction.args[0] blocktype, continueblock, innerblock = block_stack[-depth - 1] targetblock = innerblock if blocktype == 'loop' else continueblock falseblock = self.new_block() self.emit(ir.CJump(a, opmap[op], b, targetblock, falseblock)) self.builder.set_block(falseblock) elif inst == 'if': # todo: we assume that the test is a comparison opmap = dict(ge='>=', le='<=', eq='==', gt='>', lt='<') op, a, b = stack.pop() trueblock = self.new_block() continueblock = self.new_block() self.emit(ir.CJump(a, opmap[op], b, trueblock, continueblock)) self.builder.set_block(trueblock) block_stack.append(('if', continueblock)) elif inst == 'else': blocktype, continueblock = block_stack.pop() assert blocktype == 'if' elseblock = continueblock # continueblock becomes elseblock continueblock = self.new_block() self.emit(ir.Jump(continueblock)) self.builder.set_block(elseblock) block_stack.append(('else', continueblock)) elif inst == 'end': continueblock = block_stack.pop()[1] self.emit(ir.Jump(continueblock)) self.builder.set_block(continueblock) elif inst == 'return': self.emit(ir.Return(stack.pop())) # after_return_block = self.new_block() # self.builder.set_block(after_return_block) # todo: assert that this was the last instruction else: raise NotImplementedError(inst) ppci_function.delete_unreachable()