Exemple #1
0
    def _gen_Power(self, expr):
        # TODO (int_type, int_type) power
        leaves = expr.get_leaves()
        if len(leaves) != 2:
            raise CompileError()

        # convert exponent
        exponent = self._gen_ir(leaves[1])
        if exponent.type == int_type:
            exponent = self.int_to_real(exponent)
        elif exponent.type == void_type:
            return exponent

        # E ^ exponent
        if leaves[0].same(Symbol('E')) and exponent.type == real_type:
            return self.call_fp_intr('llvm.exp', [exponent])

        # 2 ^ exponent
        if leaves[0].get_int_value() == 2 and exponent.type == real_type:
            return self.call_fp_intr('llvm.exp2', [exponent])

        # convert base
        base = self._gen_ir(leaves[0])
        if base.type == int_type:
            base = self.int_to_real(base)
        elif base.type == void_type:
            return base

        # base ^ exponent
        if base.type == real_type and exponent.type == real_type:
            return self.call_fp_intr('llvm.pow', [base, exponent])
        else:
            raise CompileError()
Exemple #2
0
    def _gen_ir(self, expr):
        '''
        walks an expression tree and constructs the ir block
        '''
        if isinstance(expr, Symbol):
            try:
                arg = self.lookup_args[expr.get_name()]
            except KeyError:
                raise CompileError()
            return arg
        elif isinstance(expr, Integer):
            return int_type(expr.get_int_value())
        elif isinstance(expr, Real):
            return real_type(expr.round_to_float())
        elif not isinstance(expr, Expression):
            raise CompileError()

        head_name = expr.get_head_name()
        if head_name.startswith('System`'):
            head_name = head_name[7:]
            method = getattr(self, '_gen_' + head_name, None)
        else:
            method = None

        if method is None:
            raise CompileError()

        return method(expr)
Exemple #3
0
 def wrapped_f(self, expr):
     leaves = expr.get_leaves()
     if len(leaves) < minargs:
         raise CompileError()
     args = [self._gen_ir(leaf) for leaf in leaves]
     for arg in args:
         if arg.type == void_type:
             return arg
     if any(arg.type not in (real_type, int_type) for arg in args):
         raise CompileError()
     if all(arg.type == int_type for arg in args):
         ret_type = int_type
     else:
         ret_type = real_type
         for i, arg in enumerate(args):
             if arg.type == int_type:
                 args[i] = self.int_to_real(arg)
     return f(self, args, ret_type)
Exemple #4
0
 def _gen_GreaterEqual(self, args, ret_type):
     result = []
     for lhs, rhs in pairwise(args):
         if ret_type == real_type:
             result.append(self.builder.fcmp_ordered('>=', lhs, rhs))
         elif ret_type == int_type:
             result.append(self.builder.icmp_signed('>=', lhs, rhs))
         else:
             raise CompileError()
     return reduce(self.builder.and_, result)
Exemple #5
0
 def wrapped_f(self, expr):
     leaves = expr.get_leaves()
     if len(leaves) != 1:
         raise CompileError()
     arg = self._gen_ir(leaves[0])
     if arg.type == void_type:
         return arg
     elif arg.type == int_type:
         arg = self.int_to_real(arg)
     return f(self, [arg])
Exemple #6
0
 def _gen_Abs(self, args, ret_type):
     if len(args) != 1:
         raise CompileError()
     arg = args[0]
     if ret_type == int_type:
         # FIXME better way to do this?
         neg_arg = self.builder.mul(arg, int_type(-1))
         cond = self.builder.icmp_signed('<', arg, int_type(0))
         return self.builder.select(cond, neg_arg, arg)
     elif ret_type == real_type:
         return self.call_fp_intr('llvm.fabs', args)
Exemple #7
0
 def wrapped_f(self, expr):
     leaves = expr.get_leaves()
     args = [self._gen_ir(leaf) for leaf in leaves]
     for arg in args:
         if arg.type == void_type:
             return arg
     for i, arg in enumerate(args):
         if arg.type == int_type:
             args[i] = self.int_to_bool(arg)
     if any(arg.type != bool_type for arg in args):
         raise CompileError()
     return f(self, args)
Exemple #8
0
 def _gen_Unequal(self, args, ret_type):
     result = []
     # Unequal[e1, e2, ... en] gives True only if none of the ei are equal.
     result = []
     for lhs, rhs in itertools.combinations(args, 2):
         if ret_type == real_type:
             result.append(self.builder.fcmp_ordered('!=', lhs, rhs))
         elif ret_type == int_type:
             result.append(self.builder.icmp_signed('!=', lhs, rhs))
         else:
             raise CompileError()
     return reduce(self.builder.and_, result)
Exemple #9
0
    def _gen_Return(self, expr):
        leaves = expr.get_leaves()
        if len(leaves) != 1:
            raise CompileError()

        arg = self._gen_ir(leaves[0])
        if arg.type == void_type:
            return arg

        if self._returned_type == arg.type:
            pass
        elif self._returned_type is None:
            self._returned_type = arg.type
        elif self._returned_type == real_type and arg.type == int_type:
            arg = self.int_to_real(arg)
        elif self._returned_type == int_type and arg.type == real_type:
            self._returned_type = arg.type
        else:
            raise CompileError('Conflicting return types {} and {}.'.format(
                self._returned_type, arg.type))
        return self.builder.ret(arg)
Exemple #10
0
    def _gen_If(self, expr):
        if not expr.has_form('If', 3):
            raise CompileError()

        builder = self.builder
        args = expr.get_leaves()

        # condition
        cond = self._gen_ir(args[0])
        if cond.type == int_type:
            cond = self.int_to_bool(cond)
        if cond.type != bool_type:
            raise CompileError()

        # construct new blocks
        then_block = builder.append_basic_block()
        else_block = builder.append_basic_block()

        # branch to then or else block
        builder.cbranch(cond, then_block, else_block)

        # results for both block
        with builder.goto_block(then_block):
            then_result = self._gen_ir(args[1])
        with builder.goto_block(else_block):
            else_result = self._gen_ir(args[2])

        # type check both blocks - determine resulting type
        if then_result.type == void_type and else_result.type == void_type:
            # both blocks terminate so no continuation block
            return then_result
        elif then_result.type == else_result.type:
            ret_type = then_result.type
        elif then_result.type == int_type and else_result.type == real_type:
            builder.position_at_end(then_block)
            then_result = self.int_to_real(then_result)
            ret_type = real_type
        elif then_result.type == real_type and else_result.type == int_type:
            builder.position_at_end(else_block)
            else_result = self.int_to_real(else_result)
            ret_type = real_type
        elif then_result.type == void_type and else_result.type != void_type:
            ret_type = else_result.type
        elif then_result.type != void_type and else_result.type == void_type:
            ret_type = then_result.type
        else:
            raise CompileError()

        # continuation block
        cont_block = builder.append_basic_block()
        builder.position_at_start(cont_block)
        result = builder.phi(ret_type)

        # both blocks branch to continuation block (unless they terminate)
        if then_result.type != void_type:
            with builder.goto_block(then_block):
                builder.branch(cont_block)
            result.add_incoming(then_result, then_block)
        if else_result.type != void_type:
            with builder.goto_block(else_block):
                builder.branch(cont_block)
            result.add_incoming(else_result, else_block)
        return result