Exemple #1
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)
Exemple #2
0
 def test_store_uses_alloc_as_value(self):
     """ When only stores and loads use the alloc, the store can use the
     alloc as a value. In this case, the store must remain """
     alloc = self.builder.emit(ir.Alloc('A', 4, 4))
     addr = self.builder.emit(ir.AddressOf(alloc, 'addr'))
     self.builder.emit(ir.Store(addr, addr))
     self.builder.emit(ir.Exit())
     self.mem2reg.run(self.module)
     self.assertIn(alloc, self.function.entry.instructions)
Exemple #3
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)
Exemple #4
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)
    def handle_assignment(self, assignment):
        self.logger.debug('assign %s = %s', assignment.var, assignment.expr)
        name = assignment.var
        assert isinstance(name, str)

        # Create the variable on stack if not already present
        if name not in self.variables:
            alloc = self.emit(
                ir.Alloc(name + '_alloc', self.int_size, self.int_size))
            addr = self.emit(ir.AddressOf(alloc, name + '_addr'))
            self.variables[name] = addr
        mem_loc = self.variables[name]
        value = assignment.expr.ir_value
        self.emit(ir.Store(value, mem_loc))
Exemple #6
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()