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()
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)
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)
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)
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])
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)
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)
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)
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)
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