Ejemplo n.º 1
0
    def visit_While(self, node: While):
        # Start insertion onto the current block
        self.builder.position_at_end(block=self.builder.block)

        # Create basic blocks in the current function to express the control flow
        cond_bb = ir.Block(self.builder.function, "while.cond")
        body_bb = ir.Block(self.builder.function, "while.body")
        end_bb = ir.Block(self.builder.function, "while.end")

        self.loop_end_blocks.append(end_bb)

        # Condition:
        self.builder.branch(target=cond_bb)
        self.builder.function.basic_blocks.append(cond_bb)
        self.builder.position_at_start(block=cond_bb)

        cond_value = self.visit(node.cond)
        self.builder.cbranch(cond=cond_value, truebr=body_bb, falsebr=end_bb)

        # Body:
        self.builder.function.basic_blocks.append(body_bb)
        self.builder.position_at_start(block=body_bb)

        self.visit(node.body)
        self.__terminate(target=cond_bb)

        # End:
        self.builder.function.basic_blocks.append(end_bb)
        self.builder.position_at_start(block=end_bb)
        self.loop_end_blocks.pop()
Ejemplo n.º 2
0
def codegen(self: IfElse, generator: LLVMCodeGenerator):
    builder = generator.builder
    cmp = self.condition().codegen(generator)

    trueBlock = builder.function.append_basic_block('true-block')
    falseBlock = ir.Block(builder.function, 'false-block')
    mergedBlock = ir.Block(builder.function, 'merged')

    builder.cbranch(cmp, trueBlock, falseBlock)

    # true block
    builder.position_at_start(trueBlock)
    self.trueBlock().codegen(generator)
    builder.branch(mergedBlock)
    trueBlock = generator.builder.block

    # false block
    builder.function.basic_blocks.append(falseBlock)
    builder.position_at_start(falseBlock)
    self.falseBlock().codegen(generator)
    builder.branch(mergedBlock)
    falseBlock = generator.builder.block

    builder.function.basic_blocks.append(mergedBlock)
    builder.position_at_start(mergedBlock)

    return mergedBlock
Ejemplo n.º 3
0
    def generate(self):
        cond_val = self.condition.generate()

        then_block = self.builder.function.append_basic_block('then')
        else_block = ir.Block(self.builder.function, 'else')
        merge_block = ir.Block(self.builder.function, 'after_if')
        self.builder.cbranch(cond_val, then_block, else_block)
        self.builder.position_at_start(then_block)
        then_val = None
        for stmt in self.then_body:
            then_val = stmt.generate()
        self.builder.branch(merge_block)

        self.builder.function.basic_blocks.append(else_block)
        self.builder.position_at_start(else_block)
        else_val = None
        for stmt in self.else_body:
            else_val = stmt.generate()
        self.builder.branch(merge_block)

        self.builder.function.basic_blocks.append(merge_block)
        self.builder.position_at_start(merge_block)
        phi = self.builder.phi(self.cg.int64, 'if_phi')
        phi.add_incoming(then_val, then_block)
        phi.add_incoming(else_val, else_block)
        return phi
Ejemplo n.º 4
0
    def _codegen_condop(self, node, func_symtab):
        cond_val = self._codegen(node.children[0], func_symtab)
        cmpr = self.builder.trunc(cond_val, ir.IntType(1))

        then_bb = self.builder.function.append_basic_block('then')
        else_bb = ir.Block(self.builder.function, 'else')
        merge_bb = ir.Block(self.builder.function, 'ifcont')
        self.builder.cbranch(cmpr, then_bb, else_bb)

        self.builder.position_at_start(then_bb)
        then_val = self._codegen(node.children[1], func_symtab)

        self.builder.branch(merge_bb)

        self.builder.function.basic_blocks.append(else_bb)
        self.builder.position_at_start(else_bb)
        else_val = self._codegen(node.children[2], func_symtab)

        self.builder.branch(merge_bb)

        self.builder.function.basic_blocks.append(merge_bb)
        self.builder.position_at_start(merge_bb)
        result = self.builder.phi(then_val.type)
        result.add_incoming(then_val, then_bb)
        result.add_incoming(else_val, else_bb)
        return result
Ejemplo n.º 5
0
    def _codegen_if_else(self, node, func_symtab):
        cond_val = self._codegen(node.children[0], func_symtab)
        cmpr = self.builder.trunc(cond_val, ir.IntType(1))

        then_bb = self.builder.function.append_basic_block('then')
        else_bb = ir.Block(self.builder.function, 'else')
        merge_bb = ir.Block(self.builder.function, 'ifcont')
        self.builder.cbranch(cmpr, then_bb, else_bb)

        self.builder.position_at_start(then_bb)
        then_val = self._codegen(node.children[1], func_symtab)
        if not self.builder.block.is_terminated:
            self.builder.branch(merge_bb)
        else:
            cont = self.builder.function.append_basic_block('contbr')
            self.builder.position_at_start(cont)
            self.builder.branch(merge_bb)

        self.builder.function.basic_blocks.append(else_bb)
        self.builder.position_at_start(else_bb)
        else_val = self._codegen(node.children[2], func_symtab)

        if not self.builder.block.is_terminated:
            self.builder.branch(merge_bb)
        else:
            cont = self.builder.function.append_basic_block('contbr')
            self.builder.position_at_start(cont)
            self.builder.branch(merge_bb)

        self.builder.function.basic_blocks.append(merge_bb)
        self.builder.position_at_start(merge_bb)
        pass
Ejemplo n.º 6
0
    def visitWhile_stmt(self, ctx: EasyParser.While_stmtContext):
        """
        We generate while cycle code
        :param ctx:
        :return:
        """
        testb = ir.Block(self.builder.function, 'test')
        cycleb = ir.Block(self.builder.function, 'cycle')
        endb = ir.Block(self.builder.function, 'end')
        self.builder.branch(testb)
        # Test while
        self.builder.function.basic_blocks.append(testb)
        self.builder.position_at_start(testb)
        test_val = self.generateCode(ctx.test())
        cmp = self.builder.icmp_signed('==', test_val,
                                       ir.Constant(self.int1, 0))
        self.builder.cbranch(cmp, endb, cycleb)

        # While block
        self.builder.function.basic_blocks.append(cycleb)
        self.builder.position_at_start(cycleb)
        self.generateCode(ctx.block())
        if not self.builder.block.is_terminated:
            self.builder.branch(testb)

        # end of cycle
        self.builder.function.basic_blocks.append(endb)
        self.builder.position_at_start(endb)

        return
Ejemplo n.º 7
0
def codegen(self: While, generator: LLVMCodeGenerator):
    builder = generator.builder

    conditionBlock = builder.function.append_basic_block(
        'while-condition-block')
    bodyBlock = ir.Block(builder.function, 'while-body-block')
    mergedBlock = ir.Block(builder.function, 'while-merged')

    builder.branch(conditionBlock)

    # condition block
    builder.position_at_start(conditionBlock)
    cmp = self.condition().codegen(generator)
    builder.cbranch(cmp, bodyBlock, mergedBlock)
    conditionBlock = generator.builder.block

    # body block
    builder.function.basic_blocks.append(bodyBlock)
    builder.position_at_start(bodyBlock)
    self.body().codegen(generator)
    builder.branch(conditionBlock)
    conditionBlock = generator.builder.block

    # merged section
    builder.function.basic_blocks.append(mergedBlock)
    builder.position_at_start(mergedBlock)

    return mergedBlock
Ejemplo n.º 8
0
 def _codegen_binary_logical_operator(self, node, func_symtab):
     if node.leaf == '&&':
         check1_bb = self.builder.function.append_basic_block('check1')
         check2_bb = ir.Block(self.builder.function, 'check2')
         ret_bb = ir.Block(self.builder.function, 'afterLAND')
         self.builder.branch(check1_bb)
         self.builder.position_at_start(check1_bb)
         lhs = self._codegen(node.children[0], func_symtab)
         check1_bb = self.builder.block
         cmpr = self.builder.trunc(lhs, ir.IntType(1))
         self.builder.cbranch(cmpr, check2_bb, ret_bb)
         self.builder.function.basic_blocks.append(check2_bb)
         self.builder.position_at_start(check2_bb)
         rhs = self._codegen(node.children[1], func_symtab)
         check2_bb = self.builder.block
         out = self.builder.and_(lhs, rhs, 'landtmp')
         self.builder.branch(ret_bb)
         self.builder.function.basic_blocks.append(ret_bb)
         self.builder.position_at_start(ret_bb)
         phi = self.builder.phi(boolean)
         phi.add_incoming(lhs, check1_bb)
         phi.add_incoming(out, check2_bb)
         return phi
     elif node.leaf == '||':
         check1_bb = self.builder.function.append_basic_block('check1')
         check2_bb = ir.Block(self.builder.function, 'check2')
         ret_bb = ir.Block(self.builder.function, 'afterLOR')
         self.builder.branch(check1_bb)
         self.builder.position_at_start(check1_bb)
         lhs = self._codegen(node.children[0], func_symtab)
         check1_bb = self.builder.block
         cmpr = self.builder.trunc(lhs, ir.IntType(1))
         self.builder.cbranch(cmpr, ret_bb, check2_bb)
         self.builder.function.basic_blocks.append(check2_bb)
         self.builder.position_at_start(check2_bb)
         rhs = self._codegen(node.children[1], func_symtab)
         check2_bb = self.builder.block
         out = self.builder.or_(lhs, rhs, 'landtmp')
         self.builder.branch(ret_bb)
         self.builder.function.basic_blocks.append(ret_bb)
         self.builder.position_at_start(ret_bb)
         phi = self.builder.phi(boolean)
         phi.add_incoming(lhs, check1_bb)
         phi.add_incoming(out, check2_bb)
         return phi
     else:
         lhs = self._codegen(node.children[0], func_symtab)
         rhs = self._codegen(node.children[1], func_symtab)
         return rhs
Ejemplo n.º 9
0
    def visitFor_stmt(self, ctx: EasyParser.For_stmtContext):
        """
        We generate code for fo cycle, now it just support integer
        ineration
        :param ctx:
        :return:
        """
        name = str(ctx.NAME())
        init = self.generateCode(ctx.expr(0))
        end = self.generateCode(ctx.expr(1))
        step = self.generateCode(ctx.expr(2))

        i_ptr = self.alloc(name, self.int32)
        self.builder.store(init, i_ptr)

        checkb = ir.Block(self.builder.function, 'check')
        cycleb = ir.Block(self.builder.function, 'cycle')
        endb = ir.Block(self.builder.function, 'end')

        #Jump tp loop
        self.builder.branch(checkb)
        self.funcs_symtab.set(ctx, name, i_ptr)

        #Check condition
        self.builder.function.basic_blocks.append(checkb)
        self.builder.position_at_start(checkb)
        i_value = self.builder.load(i_ptr)
        cmp = self.builder.icmp_signed('==', i_value, end, "comp")
        self.builder.cbranch(cmp, endb, cycleb)

        #Generate inner block code
        self.builder.function.basic_blocks.append(cycleb)
        self.builder.position_at_start(cycleb)
        self.generateCode(ctx.block())

        #step
        added = self.builder.add(i_value, step)
        self.builder.store(added, i_ptr)

        #Jump to loop
        self.builder.branch(checkb)

        #endblock
        self.builder.function.basic_blocks.append(endb)
        self.builder.position_at_start(endb)
        self.funcs_symtab.pop(name)
Ejemplo n.º 10
0
    def visit_Assert(self, node: Assert):
        expr_value = self.visit(node.expr)

        true_bb = ir.Block(self.builder.function, "assert.true")
        false_bb = ir.Block(self.builder.function, "assert.false")
        self.builder.cbranch(cond=expr_value, truebr=true_bb, falsebr=false_bb)

        # False:
        self.builder.function.basic_blocks.append(false_bb)
        self.builder.position_at_start(block=false_bb)

        self.__printf(f"Assertion failed {node.coord}", "assert.msg")
        self.builder.branch(target=self.func_exit_block)

        # True:
        self.builder.function.basic_blocks.append(true_bb)
        self.builder.position_at_start(true_bb)
Ejemplo n.º 11
0
 def _codegen_Match(self, node):
     cond_item = self._codegen(node.cond_item)
     default = ir.Block(self.builder.function, 'defaultmatch')
     exit = ir.Block(self.builder.function, 'endmatch')
     switch_instr = self.builder.switch(cond_item, default)
     cases = []
     exprs = {}
     values = set()
     for value, expr in node.match_list:
         val_codegen = self._codegen(value)
         if not isinstance(val_codegen, ir.values.Constant):
             raise CodegenError(
                 f'Match parameter must be a constant, not an expression',
                 value.position)
         if val_codegen.type != cond_item.type:
             raise CodegenError(
                 f'Type of match object ("{cond_item.type.describe()}") and match parameter ("{val_codegen.type.describe()}") must be consistent)',
                 value.position)
         if val_codegen.constant in values:
             raise CodegenError(f'Match parameter {value} duplicated',
                                value.position)
         values.add(val_codegen.constant)
         if expr in exprs:
             switch_instr.add_case(val_codegen, exprs[expr])
         else:
             n = ir.Block(self.builder.function, 'match')
             switch_instr.add_case(val_codegen, n)
             exprs[expr] = n
             cases.append([n, expr])
     for block, expr in cases:
         self.builder.function.basic_blocks.append(block)
         self.builder.position_at_start(block)
         result = self._codegen(expr, False)
         #if result and not self.builder.block.is_terminated:
         if not self.builder.block.is_terminated:
             self.builder.branch(exit)
     self.builder.function.basic_blocks.append(default)
     self.builder.position_at_start(default)
     if node.default:
         self._codegen(node.default, False)
     if not self.builder.block.is_terminated:
         self.builder.branch(exit)
     self.builder.function.basic_blocks.append(exit)
     self.builder.position_at_start(exit)
     return cond_item
Ejemplo n.º 12
0
def codegen(self: For, generator: LLVMCodeGenerator):
    builder = generator.builder

    initBlock = builder.function.append_basic_block('for-init-block')
    conditionBlock = ir.Block(builder.function, 'for-condition')
    bodyBlock = ir.Block(builder.function, 'for-body-block')
    mergedBlock = ir.Block(builder.function, 'for-merged')

    builder.branch(initBlock)

    # init block
    builder.position_at_start(initBlock)
    left, right = self.range().codegen(generator)
    name = self.id().name()
    alloca = builder.alloca(irIntType(), name=name)
    builder.store(left, alloca)
    generator.symbolTable.put(name, alloca)
    builder.branch(conditionBlock)
    initBlock = generator.builder.block

    # condition block
    builder.function.basic_blocks.append(conditionBlock)
    builder.position_at_start(conditionBlock)
    current = builder.load(alloca)
    current = generator.builder.sitofp(current, irDoubleType())
    limit = generator.builder.sitofp(right, irDoubleType())
    cmp = generator.builder.fcmp_unordered('<=', current, limit, 'for-cmp')
    builder.cbranch(cmp, bodyBlock, mergedBlock)
    conditionBlock = generator.builder.block

    # body block
    builder.function.basic_blocks.append(bodyBlock)
    builder.position_at_start(bodyBlock)
    self.body().codegen(generator)
    current = builder.load(alloca)
    current = builder.add(current, ir.Constant(irIntType(), 1))
    builder.store(current, alloca)
    builder.branch(conditionBlock)
    conditionBlock = generator.builder.block

    # merged block
    builder.function.basic_blocks.append(mergedBlock)
    builder.position_at_start(mergedBlock)

    return mergedBlock
Ejemplo n.º 13
0
    def visitIf_stmt(self, ctx: EasyParser.If_stmtContext):
        """
        generate if statement code
        :param ctx:
        :return:
        """
        cond_val = self.generateCode(ctx.test())
        is_else = ctx.block(1) is not None
        cmp = self.builder.icmp_signed('!=', cond_val,
                                       ir.Constant(self.int1, 0), 'notnull')
        thenb = ir.Block(self.builder.function, 'then')
        #Do we have else statement?
        if is_else:
            elseb = ir.Block(self.builder.function, 'else')

        mergeb = ir.Block(self.builder.function, 'merge')

        if is_else:
            self.builder.cbranch(cmp, thenb, elseb)
        else:
            self.builder.cbranch(cmp, thenb, mergeb)

        #Generate then block
        self.builder.function.basic_blocks.append(thenb)
        self.builder.position_at_start(thenb)
        self.generateCode(ctx.block(0))
        # Maybe we add return statement in this block
        if not self.builder.block.is_terminated:
            self.builder.branch(mergeb)

        #Generate else block
        if is_else:
            self.builder.function.basic_blocks.append(elseb)
            self.builder.position_at_start(elseb)
            self.generateCode(ctx.block(1))
            # Maybe we add return statement in this block
            if not self.builder.block.is_terminated:
                self.builder.branch(mergeb)

        # End of if
        self.builder.function.basic_blocks.append(mergeb)
        self.builder.position_at_start(mergeb)

        return
Ejemplo n.º 14
0
    def visitFunction(self, ctx: SoLangParser.FunctionContext):
        name = ctx.Ident().getText()
        block_name = 'entry'
        self.current_function = name
        self.variables[self.current_function] = {}

        params = []
        paramnames = []
        if ctx.paramdefs() is not None:
            for paramdef in self.visit(ctx.paramdefs()):
                params.append(self.i64)
                paramnames.append(paramdef)

        # register function
        ftype = ir.FunctionType(self.i64, params)
        func = ir.Function(self.module, ftype, name=name)
        entrybb = func.append_basic_block(name=block_name)
        retbb = ir.Block(entrybb, name='_ret')
        # retbb = func.append_basic_block(name='ret')
        self.functions[name] = {
            'func': func,
            'entrybb': entrybb,
            'retbb': retbb
        }

        # make a block for func entry
        self.builder = ir.IRBuilder(entrybb)

        # define variables for the paramnames
        for paramname in paramnames:
            var = self.builder.alloca(self.i64, size=8, name=paramname)
            self.variables[self.current_function][paramname] = var

        # create _ret variable
        var = self.builder.alloca(self.i64, size=8, name='_ret')
        self.variables[self.current_function]['_ret'] = var

        # store parameter values to the variables
        i = 0
        for paramname in paramnames:
            ptr = self.variables[self.current_function][paramname]
            value = func.args[i]
            self.builder.store(value, ptr)
            i += 1

        ret = self.visitChildren(ctx)

        # make a block for ret
        func.basic_blocks.append(retbb)
        self.builder = ir.IRBuilder(retbb)
        ptr = self.variables[self.current_function]['_ret']
        value = self.builder.load(ptr, name)
        self.builder.ret(value)

        # ret is always None
        return ret
Ejemplo n.º 15
0
    def codegen_If(self, node):

        node.show()
        cond_val, _ = self.codegen(node.cond)
        cmp = self.builder.fcmp_ordered('!=', cond_val,
                                        ir.Constant(ir.DoubleType(), 0.0))

        then_bb = self.builder.function.append_basic_block('then')
        else_bb = ir.Block(self.builder.function, 'else')
        merge_bb = ir.Block(self.builder.function, 'ifend')

        self.builder.cbranch(cmp, then_bb, else_bb)
        self.builder.position_at_start(then_bb)
        if_return = False
        else_return = False
        then_val, _ = self.codegen(node.iftrue)
        # if return at it we don't branch
        if not self.return_in_branch:
            self.builder.branch(merge_bb)
        else:
            self.return_in_branch.pop()
            if_return = True
        then_bb = self.builder.block
        # Emit the 'else' part
        self.builder.function.basic_blocks.append(else_bb)
        self.builder.position_at_start(else_bb)
        if node.iffalse:
            else_val, _ = self.codegen(node.iffalse)
            else_bb = self.builder.block

        if not self.return_in_branch:
            self.builder.branch(merge_bb)
        else:
            self.return_in_branch.pop()
            else_return = True

        # Emit the merge ('ifend') block
        if if_return and else_return:
            pass
        else:
            self.builder.function.basic_blocks.append(merge_bb)
        self.builder.position_at_start(merge_bb)
        return None, None
Ejemplo n.º 16
0
    def visit_For(self, node: For):
        # Start insertion onto the current block
        self.builder.position_at_end(block=self.builder.block)

        # Create basic blocks in the current function to express the control flow
        cond_bb = ir.Block(self.builder.function, "for.cond")
        body_bb = ir.Block(self.builder.function, "for.body")
        end_bb = ir.Block(self.builder.function, "for.end")

        self.loop_end_blocks.append(end_bb)

        # Init:
        if node.init is not None:
            self.visit(node.init)

        # Condition:
        self.builder.branch(target=cond_bb)

        self.builder.function.basic_blocks.append(cond_bb)
        self.builder.position_at_start(block=cond_bb)

        if node.cond is None:
            self.builder.branch(target=body_bb)
        else:
            cond_value = self.visit(node.cond)
            self.builder.cbranch(cond=cond_value,
                                 truebr=body_bb,
                                 falsebr=end_bb)

        # Body:
        self.builder.function.basic_blocks.append(body_bb)
        self.builder.position_at_start(block=body_bb)

        self.visit(node.body)
        if node.next is not None:
            self.visit(node.next)

        self.__terminate(target=cond_bb)

        # End:
        self.builder.function.basic_blocks.append(end_bb)
        self.builder.position_at_start(block=end_bb)
        self.loop_end_blocks.pop()
Ejemplo n.º 17
0
 def emit_BR(self, cond, label, else_label='fallthrough'):
     if label not in self.bbs:
         target = ir.Block(self.builder.function, label)
         self.bbs[label] = target
     else:
         target = self.bbs[label]
     fall_bb = self.builder.function.append_basic_block(else_label)
     self.builder.cbranch(cond, target, fall_bb)
     self.builder.position_at_start(fall_bb)
     return
Ejemplo n.º 18
0
 def emit_JMP(self, label):
     if label not in self.bbs:
         target = ir.Block(self.builder.function, label)
         self.bbs[label] = target
     else:
         target = self.bbs[label]
     fall_bb = self.builder.function.append_basic_block('fallthrough')
     self.builder.branch(target)
     self.builder.position_at_start(fall_bb)
     return
Ejemplo n.º 19
0
    def _codegen_for(self, node, func_symtab):
        if node.children[0].type != 'no_expression':
            start_val = self._codegen(node.children[0], func_symtab)

        endcond_bb = self.builder.function.append_basic_block('endcond')
        loop_bb = ir.Block(self.builder.function, 'loop')
        step_bb = ir.Block(self.builder.function, 'step')
        afterloop_bb = ir.Block(self.builder.function, 'afterloop')
        temp = self.label['_1']
        self.label['_1'] = [step_bb, afterloop_bb]

        self.builder.branch(endcond_bb)
        self.builder.position_at_start(endcond_bb)

        if node.children[1].type == 'no_expression':
            self.builder.branch(loop_bb)
        else:
            endcond = self._codegen(node.children[1], func_symtab)
            cmpr = self.builder.trunc(endcond, ir.IntType(1))
            self.builder.cbranch(cmpr, loop_bb, afterloop_bb)
        self.builder.function.basic_blocks.append(loop_bb)
        self.builder.position_at_start(loop_bb)

        self._codegen(node.children[3], func_symtab)
        if not self.builder.block.is_terminated:
            self.builder.branch(step_bb)
        else:
            cont = self.builder.function.append_basic_block('contbr')
            self.builder.position_at_start(cont)
            self.builder.branch(step_bb)
        self.builder.function.basic_blocks.append(step_bb)
        self.builder.position_at_start(step_bb)

        if node.children[2].type != 'no_expression':
            stepval = self._codegen(node.children[2], func_symtab)

        self.builder.branch(endcond_bb)
        self.builder.function.basic_blocks.append(afterloop_bb)
        self.builder.position_at_end(afterloop_bb)
        self.label['_1'] = temp

        pass
Ejemplo n.º 20
0
    def _codegen_IfExprAST(self, node):
        # Emit comparison value
        cond_val = self._codegen(node.cond_expr)
        cmp = self.builder.fcmp_ordered('!=', cond_val,
                                        ir.Constant(ir.DoubleType(), 0.0))

        # Create basic blocks to express the control flow, with a conditional
        # branch to either then_bb or else_bb depending on cmp. else_bb and
        # merge_bb are not yet attached to the function's list of BBs because
        # if a nested IfExpr is generated we want to have a reasonably nested
        # order of BBs generated into the function.
        then_bb = self.builder.function.append_basic_block('then')
        else_bb = ir.Block(self.builder.function, 'else')
        merge_bb = ir.Block(self.builder.function, 'ifcont')
        self.builder.cbranch(cmp, then_bb, else_bb)

        # Emit the 'then' part
        self.builder.position_at_start(then_bb)
        then_val = self._codegen(node.then_expr)
        self.builder.branch(merge_bb)

        # Emission of then_val could have modified the current basic block. To
        # properly set up the PHI, remember which block the 'then' part ends in.
        then_bb = self.builder.block

        # Emit the 'else' part
        self.builder.function.basic_blocks.append(else_bb)
        self.builder.position_at_start(else_bb)
        else_val = self._codegen(node.else_expr)

        # Emission of else_val could have modified the current basic block.
        else_bb = self.builder.block
        self.builder.branch(merge_bb)

        # Emit the merge ('ifcnt') block
        self.builder.function.basic_blocks.append(merge_bb)
        self.builder.position_at_start(merge_bb)
        phi = self.builder.phi(ir.DoubleType(), 'iftmp')
        phi.add_incoming(then_val, then_bb)
        phi.add_incoming(else_val, else_bb)
        return phi
Ejemplo n.º 21
0
    def visit_ForExpr(self, expr):
        start_val = self.visit(expr.start)
        alloca = self.add_alloca(expr.name, _llvm_ty(expr.decl_ty))
        ok = True

        if alloca and start_val:
            self.builder.store(start_val, alloca)
        else:
            ok = False
        self.decl_values[expr] = alloca

        # generate loop
        for_block = self.builder.append_basic_block('for')
        exit_block = ir.Block(self.builder.function, name='for.exit')

        self.builder.branch(for_block)
        self.builder.position_at_end(for_block)

        # generate loop test
        end_val = self.visit(expr.end)
        if end_val:
            end_val_bool = self.builder.fcmp_ordered(
                '==', end_val, ir.Constant(ir.DoubleType(), 0.0))
        else:
            end_val_bool = ir.Constant(ir.IntType(1), 0)
            ok = False

        with self.builder.if_then(end_val_bool):
            self.builder.branch(exit_block)

        # generate loop body
        if not self.visit(expr.body):
            ok = False

        # generate increment
        if alloca:
            indvar_val = self.builder.load(alloca)
            step_val = self.visit(expr.step)
            new_indvar_val = self.builder.fadd(indvar_val, step_val, expr.name)
            self.builder.store(new_indvar_val, alloca)

        # branch to loop entry
        self.builder.branch(for_block)

        self.builder.function.blocks.append(exit_block)
        self.builder.position_at_end(exit_block)

        if not ok:
            return None

        return ir.Constant(ir.DoubleType(), 0.0)
Ejemplo n.º 22
0
    def visit_if_else(self, if_else):
        meta_cond = if_else.cond_expr.visit(self)
        val = self.env.builder.load(meta_cond.ir_value)
        meta_type = self.env.scope.get_type('bool')
        cond = self.env.builder.icmp_signed('!=',
                                            ir.Constant(meta_type.ir_type, 0),
                                            val)

        then_bb = self.env.builder.function.append_basic_block('then')
        else_bb = ir.Block(self.env.builder.function, 'else')
        merge_bb = ir.Block(self.env.builder.function, 'ifcont')

        if if_else.has_else:
            self.env.builder.cbranch(cond, then_bb, else_bb)
        else:
            self.env.builder.cbranch(cond, then_bb, merge_bb)

        # then
        self.env.builder.position_at_start(then_bb)
        if_else.then_block.visit(self)

        # save block may have been modified
        then_bb = self.env.builder.block
        self.env.builder.branch(merge_bb)

        if if_else.has_else:
            # else
            self.env.builder.function.basic_blocks.append(else_bb)
            self.env.builder.position_at_start(else_bb)
            if_else.else_block.visit(self)
            else_bb = self.env.builder.block

            # block may have been modified
            else_bb = self.env.builder.block
            self.env.builder.branch(merge_bb)

        self.env.builder.function.basic_blocks.append(merge_bb)
        self.env.builder.position_at_start(merge_bb)
    def _codegen_If(self, node):
        # Emit comparison value
        cond_val = self._codegen(node.cond_expr)
        cmp = self.builder.fcmp_ordered('!=', cond_val, irdouble(0.0),
                                        'notnull')

        # Create basic blocks to express the control flow
        then_bb = ir.Block(self.builder.function, 'then')
        else_bb = ir.Block(self.builder.function, 'else')
        merge_bb = ir.Block(self.builder.function, 'endif')

        # branch to either then_bb or else_bb depending on cmp.
        self.builder.cbranch(cmp, then_bb, else_bb)

        # Emit the 'then' part
        self.builder.function.basic_blocks.append(then_bb)
        self.builder.position_at_start(then_bb)
        then_val = self._codegen(node.then_expr)
        self.builder.branch(merge_bb)
        # Emission of then_val could have generated a new basic block
        # (and thus modified the current basic block).
        # To properly set up the PHI, remember which block the 'then' part ends in.
        then_bb = self.builder.block

        # Emit the 'else' part
        self.builder.function.basic_blocks.append(else_bb)
        self.builder.position_at_start(else_bb)
        else_val = self._codegen(node.else_expr)
        self.builder.branch(merge_bb)
        else_bb = self.builder.block

        # Emit the merge block
        self.builder.function.basic_blocks.append(merge_bb)
        self.builder.position_at_start(merge_bb)
        phi = self.builder.phi(ir.DoubleType(), 'ifval')
        phi.add_incoming(then_val, then_bb)
        phi.add_incoming(else_val, else_bb)
        return phi
Ejemplo n.º 24
0
Archivo: ir.py Proyecto: Delaunay/Kiwi
    def block(self, block: Block, depth=0) -> Any:
        trace(depth, 'block')
        blk = ir.Block(self.parent)

        old = self.builder
        old_p = self.parent
        self.builder = ir.IRBuilder(block)

        for expr in block.expressions:
            self.visit(expr, depth + 1)

        self.builder = old
        self.parent = old_p
        return blk
Ejemplo n.º 25
0
    def visit_FuncDef(self, node: FuncDef):
        _ass(isinstance(node.spec, Type))
        _ass(isinstance(node.decl, Decl))
        _ass(isinstance(
            node.body,
            Compound))  # TODO double check for empty/single-line functions

        # Reset the current function symbol table
        self.func_symtab = {}

        # Generate an ir.Function from the prototype (i.e. the function declaration)
        fn: ir.Function = self.visit(node.decl)

        # Create a new basic block to start insertion into
        func_entry_block = fn.append_basic_block(name="entry")
        self.builder = ir.IRBuilder(block=func_entry_block)

        if fn.ftype.return_type is not UCLLVM.Type.Void:
            self.func_return_addr = self.__alloca(var_name="retval",
                                                  ir_type=fn.ftype.return_type)
            self.builder.store(value=UCLLVM.Const.zero(fn.ftype.return_type),
                               ptr=self.func_return_addr)

        # Add the function arguments to the stack (and the symbol table)
        for arg in fn.args:
            arg_addr = self.__alloca(var_name=arg.name, ir_type=arg.type)
            self.builder.store(value=arg, ptr=arg_addr)

        self.func_exit_block = ir.Block(self.builder.function, "exit")

        # Finish off generating the function
        self.visit(node.body)

        # Return
        self.__terminate(target=self.func_exit_block)

        self.builder.function.basic_blocks.append(self.func_exit_block)
        self.builder.position_at_start(block=self.func_exit_block)

        if self.func_return_addr is not None:
            ret_value = self.builder.load(self.func_return_addr, "retval")
            self.builder.ret(ret_value)
        else:
            self.builder.ret_void()

        self.func_exit_block = None
        self.func_return_addr = None
        self.builder = None
        return fn
Ejemplo n.º 26
0
    def visit_If(self, node: If):
        # Start insertion onto the current block
        self.builder.position_at_end(block=self.builder.block)

        # Create basic blocks in the current function to express the control flow
        then_bb = ir.Block(self.builder.function, "if.then")
        if node.ifelse is not None:
            else_bb = ir.Block(self.builder.function, "if.else")
        end_bb = ir.Block(self.builder.function, "if.end")

        # Condition:
        cond_value = self.visit(node.cond)

        self.builder.cbranch(
            cond=cond_value,
            truebr=then_bb,
            falsebr=end_bb if node.ifelse is None else else_bb)

        # Then:
        self.builder.function.basic_blocks.append(then_bb)
        self.builder.position_at_start(block=then_bb)

        self.visit(node.ifthen)
        self.__terminate(target=end_bb)

        # Else:
        if node.ifelse is not None:
            self.builder.function.basic_blocks.append(else_bb)
            self.builder.position_at_start(block=else_bb)

            self.visit(node.ifelse)
            self.__terminate(target=end_bb)

        # End:
        self.builder.function.basic_blocks.append(end_bb)
        self.builder.position_at_start(block=end_bb)
Ejemplo n.º 27
0
 def test_attributes(self):
     func = self.function()
     block = ir.Block(parent=func, name='start')
     self.assertIs(block.parent, func)
     self.assertFalse(block.is_terminated)
    def _codegen_For(self, node):
        # Output this as:
        #   ...
        #   start = startexpr
        #   goto loopcond
        # loopcond:
        #   variable = phi [start, loopheader], [nextvariable, loopbody]
        #   step = stepexpr (or variable + 1)
        #   nextvariable = step
        #   endcond = endexpr
        #   br endcond, loopbody, loopafter
        # loopbody:
        #   bodyexpr
        #   jmp loopcond
        # loopafter:
        #   return variable

        # Define blocks
        loopcond_bb = ir.Block(self.builder.function, 'loopcond')
        loopbody_bb = ir.Block(self.builder.function, 'loopbody')
        loopafter_bb = ir.Block(self.builder.function, 'loopafter')

        # ###########
        # loop header
        #############

        # Allocate the variable on the stack
        var_addr = self._alloca(node.id_name)

        # Evaluate the starting value for the counter and store it
        start_val = self._codegen(node.start_expr)
        self.builder.store(start_val, var_addr)

        # Save the current block to tell the loop cond where we are coming from
        loopheader_bb = self.builder.block

        # Jump to loop cond
        self.builder.branch(loopcond_bb)

        ###########
        # loop cond
        ###########

        self.builder.function.basic_blocks.append(loopcond_bb)
        self.builder.position_at_start(loopcond_bb)

        # Set the symbol table to to reach de local counting variable.
        # If it shadows an existing variable, save it before and restore it later.
        oldval = self.func_symtab.get(node.id_name)
        self.func_symtab[node.id_name] = var_addr

        # Compute the end condition
        endcond = self._codegen(node.end_expr)
        cmp = self.builder.fcmp_ordered('!=', endcond, irdouble(0.0),
                                        'loopcond')

        # Goto loop body if condition satisfied, otherwise, exit.
        self.builder.cbranch(cmp, loopbody_bb, loopafter_bb)

        ############
        # loop body
        ############

        self.builder.function.basic_blocks.append(loopbody_bb)
        self.builder.position_at_start(loopbody_bb)

        # Emit the body of the loop.
        # Note that we ignore the value computed by the body.
        body_val = self._codegen(node.body)

        # If the step is unknown, make it increment by 1
        if node.step_expr is None:
            node.step_expr = Binary("+", Variable(node.id_name), Number(1.0))

        # Evaluate the step and update the counter
        nextval = self._codegen(node.step_expr)
        self.builder.store(nextval, var_addr)

        # Goto loop cond
        self.builder.branch(loopcond_bb)

        #############
        # loop after
        #############

        # New code will be inserted into a new block
        self.builder.function.basic_blocks.append(loopafter_bb)
        self.builder.position_at_start(loopafter_bb)

        # Remove the loop variable from the symbol table;
        # if it shadowed an existing variable, restore that.
        if oldval is None:
            del self.func_symtab[node.id_name]
        else:
            self.func_symtab[node.id_name] = oldval

        # The 'for' expression returns the last value of the counter
        return self.builder.load(var_addr)
Ejemplo n.º 29
0
def jit(pgm):
    module = ir.Module(name="brainfuck_jit")

    # declare the getchar/putchar C functions
    # they are available in the cpython runtime so don't need any linking
    getchar = ir.Function(module, ir.FunctionType(int32, []), name="getchar")
    putchar = ir.Function(module, ir.FunctionType(ir.VoidType(), [int32]), name="putchar")
    memset = module.declare_intrinsic('llvm.memset', [int8ptr, int32])

    # our program
    bfrun = ir.Function(module, ir.FunctionType(ir.VoidType(), []), name="bfrun")

    block = bfrun.append_basic_block(name="entry")
    builder = ir.IRBuilder(block)

    # initialise the brainfuck memory space: the "tape"
    tape = builder.alloca(int32, 30000, name="tape")
    tape_ptr = builder.ptrtoint(tape, int64)
    tape8 = builder.inttoptr(tape_ptr, int8ptr)
    builder.call(memset, [tape8, int8(0), int32(4 * 30000), bit(0)])

    # current position on the "tape"
    idx = builder.alloca(int32, name="idx")
    builder.store(int32(0), idx)

    # a stack to store nested block
    bracket_blocks = []

    # generate llvm-ir for each opcode in the program
    for opcode in pgm:
        if opcode == '>':
            # idx++
            idxval = builder.load(idx, "idxval")
            inc = builder.add(idxval, int32(1), name="inc")
            builder.store(inc, idx)

        elif opcode == '<':
            # idx--
            idxval = builder.load(idx, "idxval")
            dec = builder.add(idxval, int32(-1), name="dec")
            builder.store(dec, idx)

        elif opcode == '+':
            # tape[idx] +=1
            idxval = builder.load(idx, "idxval")
            cell = builder.gep(tape, [idxval], name="cell")
            data = builder.load(cell, 'data')
            incr = builder.add(data, int32(1), name="incr")
            builder.store(incr, cell)

        elif opcode == '-':
            # tape[idx] -=1
            idxval = builder.load(idx, "idxval")
            cell = builder.gep(tape, [idxval], name="cell")
            data = builder.load(cell, 'data')
            decr = builder.add(data, int32(-1), name="decr")
            builder.store(decr, cell)

        elif opcode == '[':
            # while tape[idx] != 0:
            idxval = builder.load(idx, "idxval")
            cell = builder.gep(tape, [idxval], name="cell")
            data = builder.load(cell, 'data')
            cmp = builder.icmp_signed('!=', data, int32(0))

            inner = bfrun.append_basic_block(name='inner')
            after = ir.Block(parent=bfrun, name='after')
            builder.cbranch(cmp, inner, after)

            # next instructions are written inside the loop now
            builder.position_at_start(inner)

            # save the "after" block for later
            bracket_blocks.append((inner, after))

        elif opcode == ']':
            idxval = builder.load(idx, "idxval")
            cell = builder.gep(tape, [idxval], name="cell")
            data = builder.load(cell, 'data')
            cmp = builder.icmp_signed('!=', data, int32(0))

            # blocks saved from matching '['
            inner, after = bracket_blocks.pop()
            builder.cbranch(cmp, inner, after)

            bfrun.blocks.append(after)
            builder.position_at_start(after)
    
        elif opcode == '.':
            idxval = builder.load(idx, "idxval")
            cell = builder.gep(tape, [idxval], name="cell")
            data = builder.load(cell, 'data')
            builder.call(putchar, [data])

        elif opcode == ',':
            data = builder.call(getchar, [])
            idxval = builder.load(idx, "idxval")
            cell = builder.gep(tape, [idxval], name="cell")
            builder.store(data, cell)

    builder.ret_void()
    return module
Ejemplo n.º 30
0
 def basic_block(self, func, name):
     block = BasicBlock()
     block.block = ir.Block(parent=func, name=name)
     if self.basic_blocks:
         self.basic_blocks[-1].blocks.append(block)
     return block