Exemplo n.º 1
0
    def test_glue_with_phi(self):
        """
            After replacing the predecessor, the use info of a phi is messed
            up.
        """
        block1 = self.builder.new_block()
        block4 = self.builder.new_block()  # This one must be eliminated
        block6 = self.builder.new_block()
        self.builder.emit(ir.Jump(block1))
        self.builder.set_block(block1)
        cnst = self.builder.emit(ir.Const(0, 'const', ir.i16))
        self.builder.emit(ir.Jump(block4))
        self.builder.set_block(block4)
        self.builder.emit(ir.Jump(block6))
        self.builder.set_block(block6)
        phi = self.builder.emit(ir.Phi('res24', ir.i16))
        phi.set_incoming(block4, cnst)
        cnst2 = self.builder.emit(ir.Const(2, 'cnst2', ir.i16))
        binop = self.builder.emit(ir.add(phi, cnst2, 'binop', ir.i16))
        phi.set_incoming(block6, binop)
        self.builder.emit(ir.Jump(block6))
        verify_module(self.module)

        # Act:
        self.clean_pass.run(self.module)
        self.assertNotIn(block4, self.function)
Exemplo n.º 2
0
 def test_add0(self):
     f = self.b.new_procedure("test", ir.Binding.GLOBAL)
     self.b.set_function(f)
     self.b.set_block(self.b.new_block())
     v1 = ir.Const(12, "const", ir.i32)
     self.b.emit(v1)
     v2 = ir.Const(0, "const", ir.i32)
     self.b.emit(v2)
     v3 = ir.add(v1, v2, "add", ir.i32)
     self.b.emit(v3)
Exemplo n.º 3
0
 def test_builder(self):
     f = self.b.new_procedure("test", ir.Binding.GLOBAL)
     self.b.set_function(f)
     entry = self.b.new_block()
     f.entry = entry
     self.b.set_block(entry)
     bb = self.b.new_block()
     self.b.emit(ir.Jump(bb))
     self.b.set_block(bb)
     v1 = self.b.emit(ir.Const(5, "const", ir.i32))
     v2 = self.b.emit(ir.Const(7, "const", ir.i32))
     self.b.emit(ir.add(v1, v2, "add", ir.i32))
     self.b.emit(ir.Exit())
     self.cf.run(self.m)
Exemplo n.º 4
0
    def test_bug2(self):
        """ Check that if blocks are in function in strange order, the dag
        builder works """
        module = ir.Module('dut')
        function = ir.Procedure('tst', ir.Binding.GLOBAL)
        module.add_function(function)
        block1 = ir.Block('b1')
        block2 = ir.Block('b2')
        function.add_block(block1)
        function.add_block(block2)
        function.entry = block2
        con = ir.Const(2, 'con', ir.i32)
        block2.add_instruction(con)
        block2.add_instruction(ir.Jump(block1))
        block1.add_instruction(ir.Cast(con, 'con_cast', ir.i8))
        block1.add_instruction(ir.Exit())

        # Target generation
        target = get_arch('arm')
        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)
Exemplo n.º 5
0
    def test_function_tailcall(self):
        """ Test if a tailcall in a function works out nicely """
        # Prepare an optimizable module:
        builder = irutils.Builder()
        module = ir.Module('test')
        builder.set_module(module)
        function = builder.new_function('x', ir.Binding.GLOBAL, ir.i8)
        builder.set_function(function)
        entry = builder.new_block()
        function.entry = entry
        a = ir.Parameter('a', ir.i8)
        function.add_parameter(a)
        b = ir.Parameter('b', ir.i8)
        function.add_parameter(b)
        builder.set_block(entry)
        one = builder.emit(ir.Const(1, 'const', ir.i8))
        a2 = builder.emit(ir.add(a, one, 'a2', ir.i8))
        b2 = builder.emit(ir.add(b, one, 'b2', ir.i8))
        result = builder.emit(ir.FunctionCall(function, [a2, b2], 'rv', ir.i8))
        builder.emit(ir.Return(result))

        # Verify first version:
        module.display()
        verify_module(module)
        self.assertFalse(function.is_leaf())

        # Run optimizer:
        self.opt.run(module)

        # Verify again:
        module.display()
        verify_module(module)
        self.assertTrue(function.is_leaf())
Exemplo n.º 6
0
    def test_use(self):
        """ Check if use def information is correctly administered """
        c1 = ir.Const(1, "one", ir.i32)
        c2 = ir.Const(2, "two", ir.i32)
        c3 = ir.Const(3, "three", ir.i32)
        c4 = ir.Const(4, "four", ir.i32)
        add = ir.add(c1, c2, "add", ir.i32)
        self.assertEqual({c1, c2}, add.uses)

        # Replace usage by setting the variable:
        add.a = c3
        self.assertEqual({c3, c2}, add.uses)

        # Replace use by changing value:
        add.replace_use(c2, c4)
        self.assertEqual({c3, c4}, add.uses)
        self.assertEqual(c4, add.b)
 def get_value(self, value):
     if isinstance(value, int):
         ir_value = self.emit(ir.Const(value, 'constant', self.int_type))
     elif isinstance(value, str):
         ir_value = self.load_var(value)
     else:
         ir_value = value.ir_value
     return ir_value
Exemplo n.º 8
0
 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)
Exemplo n.º 9
0
 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)
Exemplo n.º 10
0
 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)
Exemplo n.º 11
0
 def test_builder(self):
     f = self.b.new_procedure("add", ir.Binding.GLOBAL)
     self.b.set_function(f)
     entry = self.b.new_block()
     f.entry = entry
     self.b.set_block(entry)
     bb = self.b.new_block()
     self.b.emit(ir.Jump(bb))
     self.b.set_block(bb)
     self.b.emit(ir.Const(0, "const", ir.i32))
     self.b.emit(ir.Exit())
Exemplo n.º 12
0
 def gen_ins(self, i):
     c1 = self.builder.emit(ir.Const(i, 'cnsta{}'.format(i), ir.i32))
     c2 = self.builder.emit(ir.Const(i + 2, 'cnstb{}'.format(i), ir.i32))
     self.builder.emit(ir.Binop(c1, '+', c2, 'op{}'.format(i), ir.i32))
Exemplo n.º 13
0
 def test_add(self):
     """ See if the ir classes can be constructed """
     v1 = ir.Const(1, "const", ir.i32)
     v2 = ir.Const(2, "const", ir.i32)
     ir.add(v1, v2, "add", ir.i32)
Exemplo n.º 14
0
    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()