switch to llvmlite

This commit is contained in:
Sebastien Bourdeauducq 2014-12-05 17:05:43 +08:00
parent b93b969e2a
commit 159f632a65
16 changed files with 258 additions and 303 deletions

View File

@ -1,14 +1,15 @@
import os import os
from fractions import Fraction
from llvm import core as lc import llvmlite.ir as ll
from llvm import target as lt import llvmlite.binding as llvm
from artiq.py2llvm import base_types from artiq.py2llvm import base_types
from artiq.language import units from artiq.language import units
lt.initialize_all() llvm.initialize()
llvm.initialize_all_targets()
llvm.initialize_all_asmprinters()
_syscalls = { _syscalls = {
"rpc": "i+:i", "rpc": "i+:i",
@ -23,10 +24,10 @@ _syscalls = {
} }
_chr_to_type = { _chr_to_type = {
"n": lambda: lc.Type.void(), "n": lambda: ll.VoidType(),
"b": lambda: lc.Type.int(1), "b": lambda: ll.IntType(1),
"i": lambda: lc.Type.int(32), "i": lambda: ll.IntType(32),
"I": lambda: lc.Type.int(64) "I": lambda: ll.IntType(64)
} }
_chr_to_value = { _chr_to_value = {
@ -45,45 +46,50 @@ def _str_to_functype(s):
type_args = [] type_args = []
for n, c in enumerate(s[:-2]): for n, c in enumerate(s[:-2]):
if c == "+": if c == "+":
type_args.append(lc.Type.int()) type_args.append(ll.IntType(32))
var_arg_fixcount = n var_arg_fixcount = n
elif c != "n": elif c != "n":
type_args.append(_chr_to_type[c]()) type_args.append(_chr_to_type[c]())
return (var_arg_fixcount, return (var_arg_fixcount,
lc.Type.function(type_ret, type_args, ll.FunctionType(type_ret, type_args,
var_arg=var_arg_fixcount is not None)) var_arg=var_arg_fixcount is not None))
class LinkInterface: class LinkInterface:
def init_module(self, module): def init_module(self, module):
self.llvm_module = module.llvm_module self.module = module
llvm_module = self.module.llvm_module
# syscalls # syscalls
self.syscalls = dict()
self.var_arg_fixcount = dict() self.var_arg_fixcount = dict()
for func_name, func_type_str in _syscalls.items(): for func_name, func_type_str in _syscalls.items():
var_arg_fixcount, func_type = _str_to_functype(func_type_str) var_arg_fixcount, func_type = _str_to_functype(func_type_str)
if var_arg_fixcount is not None: if var_arg_fixcount is not None:
self.var_arg_fixcount[func_name] = var_arg_fixcount self.var_arg_fixcount[func_name] = var_arg_fixcount
self.llvm_module.add_function(func_type, "__syscall_"+func_name) self.syscalls[func_name] = ll.Function(
llvm_module, func_type, "__syscall_" + func_name)
# exception handling # exception handling
func_type = lc.Type.function(lc.Type.int(), [lc.Type.pointer(lc.Type.int(8))]) func_type = ll.FunctionType(ll.IntType(32),
function = self.llvm_module.add_function(func_type, "__eh_setjmp") [ll.PointerType(ll.IntType(8))])
function.add_attribute(lc.ATTR_NO_UNWIND) self.eh_setjmp = ll.Function(llvm_module, func_type,
function.add_attribute(lc.ATTR_RETURNS_TWICE) "__eh_setjmp")
self.eh_setjmp.attributes.add("nounwind")
self.eh_setjmp.attributes.add("returns_twice")
func_type = lc.Type.function(lc.Type.pointer(lc.Type.int(8)), []) func_type = ll.FunctionType(ll.PointerType(ll.IntType(8)), [])
self.llvm_module.add_function(func_type, "__eh_push") self.eh_push = ll.Function(llvm_module, func_type, "__eh_push")
func_type = lc.Type.function(lc.Type.void(), [lc.Type.int()]) func_type = ll.FunctionType(ll.VoidType(), [ll.IntType(32)])
self.llvm_module.add_function(func_type, "__eh_pop") self.eh_pop = ll.Function(llvm_module, func_type, "__eh_pop")
func_type = lc.Type.function(lc.Type.int(), []) func_type = ll.FunctionType(ll.IntType(32), [])
self.llvm_module.add_function(func_type, "__eh_getid") self.eh_getid = ll.Function(llvm_module, func_type, "__eh_getid")
func_type = lc.Type.function(lc.Type.void(), [lc.Type.int()]) func_type = ll.FunctionType(ll.VoidType(), [ll.IntType(32)])
function = self.llvm_module.add_function(func_type, "__eh_raise") self.eh_raise = ll.Function(llvm_module, func_type, "__eh_raise")
function.add_attribute(lc.ATTR_NO_RETURN) self.eh_raise.attributes.add("noreturn")
def build_syscall(self, syscall_name, args, builder): def build_syscall(self, syscall_name, args, builder):
r = _chr_to_value[_syscalls[syscall_name][-1]]() r = _chr_to_value[_syscalls[syscall_name][-1]]()
@ -92,33 +98,27 @@ class LinkInterface:
if syscall_name in self.var_arg_fixcount: if syscall_name in self.var_arg_fixcount:
fixcount = self.var_arg_fixcount[syscall_name] fixcount = self.var_arg_fixcount[syscall_name]
args = args[:fixcount] \ args = args[:fixcount] \
+ [lc.Constant.int(lc.Type.int(), len(args) - fixcount)] \ + [ll.Constant(ll.IntType(32), len(args) - fixcount)] \
+ args[fixcount:] + args[fixcount:]
llvm_function = self.llvm_module.get_function_named( r.auto_store(builder, builder.call(self.syscalls[syscall_name],
"__syscall_" + syscall_name) args))
r.auto_store(builder, builder.call(llvm_function, args))
return r return r
def build_catch(self, builder): def build_catch(self, builder):
eh_setjmp = self.llvm_module.get_function_named("__eh_setjmp") jmpbuf = builder.call(self.eh_push, [])
eh_push = self.llvm_module.get_function_named("__eh_push") exception_occured = builder.call(self.eh_setjmp, [jmpbuf])
jmpbuf = builder.call(eh_push, []) return builder.icmp_signed("!=",
exception_occured = builder.call(eh_setjmp, [jmpbuf])
return builder.icmp(lc.ICMP_NE,
exception_occured, exception_occured,
lc.Constant.int(lc.Type.int(), 0)) ll.Constant(ll.IntType(32), 0))
def build_pop(self, builder, levels): def build_pop(self, builder, levels):
eh_pop = self.llvm_module.get_function_named("__eh_pop") builder.call(self.eh_pop, [ll.Constant(ll.IntType(32), levels)])
builder.call(eh_pop, [lc.Constant.int(lc.Type.int(), levels)])
def build_getid(self, builder): def build_getid(self, builder):
eh_getid = self.llvm_module.get_function_named("__eh_getid") return builder.call(self.eh_getid, [])
return builder.call(eh_getid, [])
def build_raise(self, builder, eid): def build_raise(self, builder, eid):
eh_raise = self.llvm_module.get_function_named("__eh_raise") builder.call(self.eh_raise, [eid])
builder.call(eh_raise, [eid])
def _debug_dump_obj(obj): def _debug_dump_obj(obj):
@ -148,8 +148,8 @@ class Environment(LinkInterface):
self.warmup_time = 1*units.ms self.warmup_time = 1*units.ms
def emit_object(self): def emit_object(self):
tm = lt.TargetMachine.new(triple=self.cpu_type, cpu="generic") tm = llvm.Target.from_triple(self.cpu_type).create_target_machine()
obj = tm.emit_object(self.llvm_module) obj = tm.emit_object(self.module.llvm_module)
_debug_dump_obj(obj) _debug_dump_obj(obj)
return obj return obj

View File

@ -1,4 +1,4 @@
from llvm import core as lc import llvmlite.ir as ll
from artiq.py2llvm.values import VGeneric from artiq.py2llvm.values import VGeneric
from artiq.py2llvm.base_types import VInt from artiq.py2llvm.base_types import VInt
@ -13,7 +13,7 @@ class VArray(VGeneric):
raise TypeError("Arrays must have at least one element") raise TypeError("Arrays must have at least one element")
def get_llvm_type(self): def get_llvm_type(self):
return lc.Type.array(self.el_init.get_llvm_type(), self.count) return ll.ArrayType(self.el_init.get_llvm_type(), self.count)
def __repr__(self): def __repr__(self):
return "<VArray:{} x{}>".format(repr(self.el_init), self.count) return "<VArray:{} x{}>".format(repr(self.el_init), self.count)
@ -42,7 +42,7 @@ class VArray(VGeneric):
i = VInt() i = VInt()
i.alloca(builder, "ai_i") i.alloca(builder, "ai_i")
i.auto_store(builder, lc.Constant.int(lc.Type.int(), 0)) i.auto_store(builder, ll.Constant(ll.IntType(32), 0))
function = builder.basic_block.function function = builder.basic_block.function
copy_block = function.append_basic_block("ai_copy") copy_block = function.append_basic_block("ai_copy")
@ -52,10 +52,10 @@ class VArray(VGeneric):
builder.position_at_end(copy_block) builder.position_at_end(copy_block)
self.o_subscript(i, builder).set_value(builder, v.el_init) self.o_subscript(i, builder).set_value(builder, v.el_init)
i.auto_store(builder, builder.add( i.auto_store(builder, builder.add(
i.auto_load(builder), lc.Constant.int(lc.Type.int(), 1))) i.auto_load(builder), ll.Constant(ll.IntType(32), 1)))
cont = builder.icmp( cont = builder.icmp_signed(
lc.ICMP_SLT, i.auto_load(builder), "<", i.auto_load(builder),
lc.Constant.int(lc.Type.int(), self.count)) ll.Constant(ll.IntType(32), self.count))
builder.cbranch(cont, copy_block, end_block) builder.cbranch(cont, copy_block, end_block)
builder.position_at_end(end_block) builder.position_at_end(end_block)
@ -65,6 +65,6 @@ class VArray(VGeneric):
if builder is not None: if builder is not None:
index = index.o_int(builder).auto_load(builder) index = index.o_int(builder).auto_load(builder)
ssa_r = builder.gep(self.llvm_value, [ ssa_r = builder.gep(self.llvm_value, [
lc.Constant.int(lc.Type.int(), 0), index]) ll.Constant(ll.IntType(32), 0), index])
r.auto_store(builder, ssa_r) r.auto_store(builder, ssa_r)
return r return r

View File

@ -1,5 +1,6 @@
import ast import ast
from llvm import core as lc
import llvmlite.ir as ll
from artiq.py2llvm import values, base_types, fractions, arrays, iterators from artiq.py2llvm import values, base_types, fractions, arrays, iterators
from artiq.py2llvm.tools import is_terminated from artiq.py2llvm.tools import is_terminated
@ -368,13 +369,13 @@ class Visitor:
if self._active_exception_stack: if self._active_exception_stack:
finally_block, propagate, propagate_eid = ( finally_block, propagate, propagate_eid = (
self._active_exception_stack[-1]) self._active_exception_stack[-1])
self.builder.store(lc.Constant.int(lc.Type.int(1), 1), propagate) self.builder.store(ll.Constant(ll.IntType(1), 1), propagate)
if node.exc is not None: if node.exc is not None:
eid = lc.Constant.int(lc.Type.int(), node.exc.args[0].n) eid = ll.Constant(ll.IntType(32), node.exc.args[0].n)
self.builder.store(eid, propagate_eid) self.builder.store(eid, propagate_eid)
self.builder.branch(finally_block) self.builder.branch(finally_block)
else: else:
eid = lc.Constant.int(lc.Type.int(), node.exc.args[0].n) eid = ll.Constant(ll.IntType(32), node.exc.args[0].n)
self.env.build_raise(self.builder, eid) self.env.build_raise(self.builder, eid)
def _handle_exception(self, function, finally_block, def _handle_exception(self, function, finally_block,
@ -382,7 +383,7 @@ class Visitor:
eid = self.env.build_getid(self.builder) eid = self.env.build_getid(self.builder)
self._active_exception_stack.append( self._active_exception_stack.append(
(finally_block, propagate, propagate_eid)) (finally_block, propagate, propagate_eid))
self.builder.store(lc.Constant.int(lc.Type.int(1), 1), propagate) self.builder.store(ll.Constant(ll.IntType(1), 1), propagate)
self.builder.store(eid, propagate_eid) self.builder.store(eid, propagate_eid)
for handler in handlers: for handler in handlers:
@ -392,23 +393,23 @@ class Visitor:
self.builder.branch(handled_exc_block) self.builder.branch(handled_exc_block)
else: else:
if isinstance(handler.type, ast.Tuple): if isinstance(handler.type, ast.Tuple):
match = self.builder.icmp( match = self.builder.icmp_signed(
lc.ICMP_EQ, eid, "==", eid,
lc.Constant.int(lc.Type.int(), ll.Constant(ll.IntType(32),
handler.type.elts[0].args[0].n)) handler.type.elts[0].args[0].n))
for elt in handler.type.elts[1:]: for elt in handler.type.elts[1:]:
match = self.builder.or_( match = self.builder.or_(
match, match,
self.builder.icmp( self.builder.icmp_signed(
lc.ICMP_EQ, eid, "==", eid,
lc.Constant.int(lc.Type.int(), elt.args[0].n))) ll.Constant(ll.IntType(32), elt.args[0].n)))
else: else:
match = self.builder.icmp( match = self.builder.icmp_signed(
lc.ICMP_EQ, eid, "==", eid,
lc.Constant.int(lc.Type.int(), handler.type.args[0].n)) ll.Constant(ll.IntType(32), handler.type.args[0].n))
self.builder.cbranch(match, handled_exc_block, cont_exc_block) self.builder.cbranch(match, handled_exc_block, cont_exc_block)
self.builder.position_at_end(handled_exc_block) self.builder.position_at_end(handled_exc_block)
self.builder.store(lc.Constant.int(lc.Type.int(1), 0), propagate) self.builder.store(ll.Constant(ll.IntType(1), 0), propagate)
self.visit_statements(handler.body) self.visit_statements(handler.body)
if not self._bb_terminated(): if not self._bb_terminated():
self.builder.branch(finally_block) self.builder.branch(finally_block)
@ -423,10 +424,10 @@ class Visitor:
exc_block = function.append_basic_block("try_exc") exc_block = function.append_basic_block("try_exc")
finally_block = function.append_basic_block("try_finally") finally_block = function.append_basic_block("try_finally")
propagate = self.builder.alloca(lc.Type.int(1), propagate = self.builder.alloca(ll.IntType(1),
name="propagate") name="propagate")
self.builder.store(lc.Constant.int(lc.Type.int(1), 0), propagate) self.builder.store(ll.Constant(ll.IntType(1), 0), propagate)
propagate_eid = self.builder.alloca(lc.Type.int(), propagate_eid = self.builder.alloca(ll.IntType(32),
name="propagate_eid") name="propagate_eid")
exception_occured = self.env.build_catch(self.builder) exception_occured = self.env.build_catch(self.builder)
self.builder.cbranch(exception_occured, exc_block, noexc_block) self.builder.cbranch(exception_occured, exc_block, noexc_block)

View File

@ -1,11 +1,11 @@
from llvm import core as lc import llvmlite.ir as ll
from artiq.py2llvm.values import VGeneric from artiq.py2llvm.values import VGeneric
class VNone(VGeneric): class VNone(VGeneric):
def get_llvm_type(self): def get_llvm_type(self):
return lc.Type.void() return ll.VoidType()
def alloca(self, builder, name): def alloca(self, builder, name):
pass pass
@ -29,7 +29,7 @@ class VInt(VGeneric):
self.nbits = nbits self.nbits = nbits
def get_llvm_type(self): def get_llvm_type(self):
return lc.Type.int(self.nbits) return ll.IntType(self.nbits)
def __repr__(self): def __repr__(self):
return "<VInt:{}>".format(self.nbits) return "<VInt:{}>".format(self.nbits)
@ -50,16 +50,16 @@ class VInt(VGeneric):
builder, n.o_intx(self.nbits, builder).auto_load(builder)) builder, n.o_intx(self.nbits, builder).auto_load(builder))
def set_const_value(self, builder, n): def set_const_value(self, builder, n):
self.auto_store(builder, lc.Constant.int(self.get_llvm_type(), n)) self.auto_store(builder, ll.Constant(self.get_llvm_type(), n))
def o_bool(self, builder, inv=False): def o_bool(self, builder, inv=False):
r = VBool() r = VBool()
if builder is not None: if builder is not None:
r.auto_store( r.auto_store(
builder, builder.icmp( builder, builder.icmp_signed(
lc.ICMP_EQ if inv else lc.ICMP_NE, "==" if inv else "!=",
self.auto_load(builder), self.auto_load(builder),
lc.Constant.int(self.get_llvm_type(), 0))) ll.Constant(self.get_llvm_type(), 0)))
return r return r
def o_float(self, builder): def o_float(self, builder):
@ -82,7 +82,7 @@ class VInt(VGeneric):
r.auto_store( r.auto_store(
builder, builder.mul( builder, builder.mul(
self.auto_load(builder), self.auto_load(builder),
lc.Constant.int(self.get_llvm_type(), -1))) ll.Constant(self.get_llvm_type(), -1)))
return r return r
def o_intx(self, target_bits, builder): def o_intx(self, target_bits, builder):
@ -157,7 +157,7 @@ def _make_vint_cmp_method(icmp_val):
right = other.o_intx(target_bits, builder) right = other.o_intx(target_bits, builder)
r.auto_store( r.auto_store(
builder, builder,
builder.icmp( builder.icmp_signed(
icmp_val, left.auto_load(builder), icmp_val, left.auto_load(builder),
right.auto_load(builder))) right.auto_load(builder)))
return r return r
@ -165,12 +165,12 @@ def _make_vint_cmp_method(icmp_val):
return NotImplemented return NotImplemented
return cmp_method return cmp_method
for _method_name, _icmp_val in (("o_eq", lc.ICMP_EQ), for _method_name, _icmp_val in (("o_eq", "=="),
("o_ne", lc.ICMP_NE), ("o_ne", "!="),
("o_lt", lc.ICMP_SLT), ("o_lt", "<"),
("o_le", lc.ICMP_SLE), ("o_le", "<="),
("o_gt", lc.ICMP_SGT), ("o_gt", ">"),
("o_ge", lc.ICMP_SGE)): ("o_ge", ">=")):
setattr(VInt, _method_name, _make_vint_cmp_method(_icmp_val)) setattr(VInt, _method_name, _make_vint_cmp_method(_icmp_val))
@ -188,7 +188,7 @@ class VBool(VInt):
class VFloat(VGeneric): class VFloat(VGeneric):
def get_llvm_type(self): def get_llvm_type(self):
return lc.Type.double() return ll.DoubleType()
def set_value(self, builder, v): def set_value(self, builder, v):
if not isinstance(v, VFloat): if not isinstance(v, VFloat):
@ -196,7 +196,7 @@ class VFloat(VGeneric):
self.auto_store(builder, v.auto_load(builder)) self.auto_store(builder, v.auto_load(builder))
def set_const_value(self, builder, n): def set_const_value(self, builder, n):
self.auto_store(builder, lc.Constant.real(self.get_llvm_type(), n)) self.auto_store(builder, ll.Constant(self.get_llvm_type(), n))
def o_float(self, builder): def o_float(self, builder):
r = VFloat() r = VFloat()
@ -208,10 +208,10 @@ class VFloat(VGeneric):
r = VBool() r = VBool()
if builder is not None: if builder is not None:
r.auto_store( r.auto_store(
builder, builder.fcmp( builder, builder.fcmp_ordered(
lc.FCMP_UEQ if inv else lc.FCMP_UNE, "==" if inv else "!=",
self.auto_load(builder), self.auto_load(builder),
lc.Constant.real(self.get_llvm_type(), 0.0))) ll.Constant(self.get_llvm_type(), 0.0)))
return r return r
def o_not(self, builder): def o_not(self, builder):
@ -223,7 +223,7 @@ class VFloat(VGeneric):
r.auto_store( r.auto_store(
builder, builder.fmul( builder, builder.fmul(
self.auto_load(builder), self.auto_load(builder),
lc.Constant.real(self.get_llvm_type(), -1.0))) ll.Constant(self.get_llvm_type(), -1.0)))
return r return r
def o_intx(self, target_bits, builder): def o_intx(self, target_bits, builder):
@ -244,10 +244,10 @@ class VFloat(VGeneric):
half.alloca(builder, "half") half.alloca(builder, "half")
half.set_const_value(builder, 0.5) half.set_const_value(builder, 0.5)
condition = builder.icmp( condition = builder.fcmp_ordered(
lc.FCMP_OLT, "<",
self.auto_load(builder), self.auto_load(builder),
lc.Constant.real(self.get_llvm_type(), 0.0)) ll.Constant(self.get_llvm_type(), 0.0))
builder.cbranch(condition, neg_block, merge_block) builder.cbranch(condition, neg_block, merge_block)
builder.position_at_end(neg_block) builder.position_at_end(neg_block)
@ -299,16 +299,16 @@ def _make_vfloat_cmp_method(fcmp_val):
right = other.o_float(builder) right = other.o_float(builder)
r.auto_store( r.auto_store(
builder, builder,
builder.fcmp( builder.fcmp_ordered(
fcmp_val, left.auto_load(builder), fcmp_val, left.auto_load(builder),
right.auto_load(builder))) right.auto_load(builder)))
return r return r
return cmp_method return cmp_method
for _method_name, _fcmp_val in (("o_eq", lc.FCMP_OEQ), for _method_name, _fcmp_val in (("o_eq", "=="),
("o_ne", lc.FCMP_ONE), ("o_ne", "!="),
("o_lt", lc.FCMP_OLT), ("o_lt", "<"),
("o_le", lc.FCMP_OLE), ("o_le", "<="),
("o_gt", lc.FCMP_OGT), ("o_gt", ">"),
("o_ge", lc.FCMP_OGE)): ("o_ge", ">=")):
setattr(VFloat, _method_name, _make_vfloat_cmp_method(_fcmp_val)) setattr(VFloat, _method_name, _make_vfloat_cmp_method(_fcmp_val))

View File

@ -1,7 +1,7 @@
import inspect import inspect
import ast import ast
from llvm import core as lc import llvmlite.ir as ll
from artiq.py2llvm.values import VGeneric, operators from artiq.py2llvm.values import VGeneric, operators
from artiq.py2llvm.base_types import VBool, VInt, VFloat from artiq.py2llvm.base_types import VBool, VInt, VFloat
@ -21,11 +21,15 @@ def init_module(module):
func_def = ast.parse(inspect.getsource(_gcd)).body[0] func_def = ast.parse(inspect.getsource(_gcd)).body[0]
function, _ = module.compile_function(func_def, function, _ = module.compile_function(func_def,
{"a": VInt(64), "b": VInt(64)}) {"a": VInt(64), "b": VInt(64)})
function.linkage = lc.LINKAGE_INTERNAL function.linkage = "internal"
def _reduce(builder, a, b): def _reduce(builder, a, b):
gcd_f = builder.basic_block.function.module.get_function_named("_gcd") module = builder.basic_block.function.module
for f in module.functions:
if f.name == "_gcd":
gcd_f = f
break
gcd = builder.call(gcd_f, [a, b]) gcd = builder.call(gcd_f, [a, b])
a = builder.sdiv(a, gcd) a = builder.sdiv(a, gcd)
b = builder.sdiv(b, gcd) b = builder.sdiv(b, gcd)
@ -38,21 +42,21 @@ def _signnum(builder, a, b):
swap_block = function.append_basic_block("sn_swap") swap_block = function.append_basic_block("sn_swap")
merge_block = function.append_basic_block("sn_merge") merge_block = function.append_basic_block("sn_merge")
condition = builder.icmp( condition = builder.icmp_signed(
lc.ICMP_SLT, b, lc.Constant.int(lc.Type.int(64), 0)) "<", b, ll.Constant(ll.IntType(64), 0))
builder.cbranch(condition, swap_block, merge_block) builder.cbranch(condition, swap_block, merge_block)
builder.position_at_end(swap_block) builder.position_at_end(swap_block)
minusone = lc.Constant.int(lc.Type.int(64), -1) minusone = ll.Constant(ll.IntType(64), -1)
a_swp = builder.mul(minusone, a) a_swp = builder.mul(minusone, a)
b_swp = builder.mul(minusone, b) b_swp = builder.mul(minusone, b)
builder.branch(merge_block) builder.branch(merge_block)
builder.position_at_end(merge_block) builder.position_at_end(merge_block)
a_phi = builder.phi(lc.Type.int(64)) a_phi = builder.phi(ll.IntType(64))
a_phi.add_incoming(a, orig_block) a_phi.add_incoming(a, orig_block)
a_phi.add_incoming(a_swp, swap_block) a_phi.add_incoming(a_swp, swap_block)
b_phi = builder.phi(lc.Type.int(64)) b_phi = builder.phi(ll.IntType(64))
b_phi.add_incoming(b, orig_block) b_phi.add_incoming(b, orig_block)
b_phi.add_incoming(b_swp, swap_block) b_phi.add_incoming(b_swp, swap_block)
@ -60,24 +64,20 @@ def _signnum(builder, a, b):
def _make_ssa(builder, n, d): def _make_ssa(builder, n, d):
value = lc.Constant.undef(lc.Type.vector(lc.Type.int(64), 2)) value = ll.Constant(ll.ArrayType(ll.IntType(64), 2), ll.Undefined)
value = builder.insert_element( value = builder.insert_value(value, n, 0)
value, n, lc.Constant.int(lc.Type.int(), 0)) value = builder.insert_value(value, d, 1)
value = builder.insert_element(
value, d, lc.Constant.int(lc.Type.int(), 1))
return value return value
class VFraction(VGeneric): class VFraction(VGeneric):
def get_llvm_type(self): def get_llvm_type(self):
return lc.Type.vector(lc.Type.int(64), 2) return ll.ArrayType(ll.IntType(64), 2)
def _nd(self, builder): def _nd(self, builder):
ssa_value = self.auto_load(builder) ssa_value = self.auto_load(builder)
a = builder.extract_element( a = builder.extract_value(ssa_value, 0)
ssa_value, lc.Constant.int(lc.Type.int(), 0)) b = builder.extract_value(ssa_value, 1)
b = builder.extract_element(
ssa_value, lc.Constant.int(lc.Type.int(), 1))
return a, b return a, b
def set_value_nd(self, builder, a, b): def set_value_nd(self, builder, a, b):
@ -101,19 +101,16 @@ class VFraction(VGeneric):
raise AttributeError raise AttributeError
r = VInt(64) r = VInt(64)
if builder is not None: if builder is not None:
elt = builder.extract_element( elt = builder.extract_value(self.auto_load(builder), idx)
self.auto_load(builder),
lc.Constant.int(lc.Type.int(), idx))
r.auto_store(builder, elt) r.auto_store(builder, elt)
return r return r
def o_bool(self, builder): def o_bool(self, builder):
r = VBool() r = VBool()
if builder is not None: if builder is not None:
zero = lc.Constant.int(lc.Type.int(64), 0) zero = ll.Constant(ll.IntType(64), 0)
a = builder.extract_element( a = builder.extract_element(self.auto_load(builder), 0)
self.auto_load(builder), lc.Constant.int(lc.Type.int(), 0)) r.auto_store(builder, builder.icmp_signed("!=", a, zero))
r.auto_store(builder, builder.icmp(lc.ICMP_NE, a, zero))
return r return r
def o_intx(self, target_bits, builder): def o_intx(self, target_bits, builder):
@ -131,15 +128,15 @@ class VFraction(VGeneric):
else: else:
r = VInt(64) r = VInt(64)
a, b = self._nd(builder) a, b = self._nd(builder)
h_b = builder.ashr(b, lc.Constant.int(lc.Type.int(64), 1)) h_b = builder.ashr(b, ll.Constant(ll.IntType(64), 1))
function = builder.basic_block.function function = builder.basic_block.function
add_block = function.append_basic_block("fr_add") add_block = function.append_basic_block("fr_add")
sub_block = function.append_basic_block("fr_sub") sub_block = function.append_basic_block("fr_sub")
merge_block = function.append_basic_block("fr_merge") merge_block = function.append_basic_block("fr_merge")
condition = builder.icmp( condition = builder.icmp_signed(
lc.ICMP_SLT, a, lc.Constant.int(lc.Type.int(64), 0)) "<", a, ll.Constant(ll.IntType(64), 0))
builder.cbranch(condition, sub_block, add_block) builder.cbranch(condition, sub_block, add_block)
builder.position_at_end(add_block) builder.position_at_end(add_block)
@ -150,7 +147,7 @@ class VFraction(VGeneric):
builder.branch(merge_block) builder.branch(merge_block)
builder.position_at_end(merge_block) builder.position_at_end(merge_block)
a = builder.phi(lc.Type.int(64)) a = builder.phi(ll.IntType(64))
a.add_incoming(a_add, add_block) a.add_incoming(a_add, add_block)
a.add_incoming(a_sub, sub_block) a.add_incoming(a_sub, sub_block)
r.auto_store(builder, builder.sdiv(a, b)) r.auto_store(builder, builder.sdiv(a, b))
@ -165,19 +162,19 @@ class VFraction(VGeneric):
other = other.o_int64(builder) other = other.o_int64(builder)
a, b = self._nd(builder) a, b = self._nd(builder)
ssa_r = builder.and_( ssa_r = builder.and_(
builder.icmp(lc.ICMP_EQ, a, builder.icmp_signed("==", a,
other.auto_load()), other.auto_load()),
builder.icmp(lc.ICMP_EQ, b, builder.icmp_signed("==", b,
lc.Constant.int(lc.Type.int(64), 1))) ll.Constant(ll.IntType(64), 1)))
else: else:
a, b = self._nd(builder) a, b = self._nd(builder)
c, d = other._nd(builder) c, d = other._nd(builder)
ssa_r = builder.and_( ssa_r = builder.and_(
builder.icmp(lc.ICMP_EQ, a, c), builder.icmp_signed("==", a, c),
builder.icmp(lc.ICMP_EQ, b, d)) builder.icmp_signed("==", b, d))
if ne: if ne:
ssa_r = builder.xor(ssa_r, ssa_r = builder.xor(ssa_r,
lc.Constant.int(lc.Type.int(1), 1)) ll.Constant(ll.IntType(1), 1))
r.auto_store(builder, ssa_r) r.auto_store(builder, ssa_r)
return r return r
@ -194,24 +191,23 @@ class VFraction(VGeneric):
r = VBool() r = VBool()
if builder is not None: if builder is not None:
diff = diff.auto_load(builder) diff = diff.auto_load(builder)
a = builder.extract_element( a = builder.extract_value(diff, 0)
diff, lc.Constant.int(lc.Type.int(), 0)) zero = ll.Constant(ll.IntType(64), 0)
zero = lc.Constant.int(lc.Type.int(64), 0)
ssa_r = builder.icmp(icmp, a, zero) ssa_r = builder.icmp(icmp, a, zero)
r.auto_store(builder, ssa_r) r.auto_store(builder, ssa_r)
return r return r
def o_lt(self, other, builder): def o_lt(self, other, builder):
return self._o_cmp(other, lc.ICMP_SLT, builder) return self._o_cmp(other, "<", builder)
def o_le(self, other, builder): def o_le(self, other, builder):
return self._o_cmp(other, lc.ICMP_SLE, builder) return self._o_cmp(other, "<=", builder)
def o_gt(self, other, builder): def o_gt(self, other, builder):
return self._o_cmp(other, lc.ICMP_SGT, builder) return self._o_cmp(other, ">", builder)
def o_ge(self, other, builder): def o_ge(self, other, builder):
return self._o_cmp(other, lc.ICMP_SGE, builder) return self._o_cmp(other, ">=", builder)
def _o_addsub(self, other, builder, sub, invert=False): def _o_addsub(self, other, builder, sub, invert=False):
if isinstance(other, VFloat): if isinstance(other, VFloat):

View File

@ -1,7 +1,5 @@
from llvm import core as lc
from artiq.py2llvm.values import operators from artiq.py2llvm.values import operators
from artiq.py2llvm.base_types import VBool, VInt from artiq.py2llvm.base_types import VInt
class IRange: class IRange:
def __init__(self, builder, args): def __init__(self, builder, args):

View File

@ -1,13 +1,12 @@
from llvm import core as lc import llvmlite.ir as ll
from llvm import passes as lp import llvmlite.binding as llvm
from llvm import ee as le
from artiq.py2llvm import infer_types, ast_body, base_types, fractions, tools from artiq.py2llvm import infer_types, ast_body, base_types, fractions, tools
class Module: class Module:
def __init__(self, env=None): def __init__(self, env=None):
self.llvm_module = lc.Module.new("main") self.llvm_module = ll.Module("main")
self.env = env self.env = env
if self.env is not None: if self.env is not None:
@ -15,17 +14,19 @@ class Module:
fractions.init_module(self) fractions.init_module(self)
def finalize(self): def finalize(self):
pass_manager = lp.PassManager.new() self.llvm_module = llvm.parse_assembly(str(self.llvm_module)) # FIXME
pass_manager.add(lp.PASS_MEM2REG) pmb = llvm.create_pass_manager_builder()
pass_manager.add(lp.PASS_INSTCOMBINE) pmb.opt_level = 2
pass_manager.add(lp.PASS_REASSOCIATE) pm = llvm.create_module_pass_manager()
pass_manager.add(lp.PASS_GVN) pmb.populate(pm)
pass_manager.add(lp.PASS_SIMPLIFYCFG) pm.run(self.llvm_module)
pass_manager.run(self.llvm_module)
def get_ee(self): def get_ee(self):
self.finalize() self.finalize()
return le.ExecutionEngine.new(self.llvm_module) tm = llvm.Target.from_default_triple().create_target_machine()
ee = llvm.create_mcjit_compiler(self.llvm_module, tm)
ee.finalize_object()
return ee
def emit_object(self): def emit_object(self):
self.finalize() self.finalize()
@ -35,11 +36,12 @@ class Module:
ns = infer_types.infer_function_types(self.env, func_def, param_types) ns = infer_types.infer_function_types(self.env, func_def, param_types)
retval = ns["return"] retval = ns["return"]
function_type = lc.Type.function(retval.get_llvm_type(), function_type = ll.FunctionType(retval.get_llvm_type(),
[ns[arg.arg].get_llvm_type() for arg in func_def.args.args]) [ns[arg.arg].get_llvm_type() for arg in func_def.args.args])
function = self.llvm_module.add_function(function_type, func_def.name) function = ll.Function(self.llvm_module, function_type, func_def.name)
bb = function.append_basic_block("entry") bb = function.append_basic_block("entry")
builder = lc.Builder.new(bb) builder = ll.IRBuilder()
builder.position_at_end(bb)
for arg_ast, arg_llvm in zip(func_def.args.args, function.args): for arg_ast, arg_llvm in zip(func_def.args.args, function.args):
arg_llvm.name = arg_ast.arg arg_llvm.name = arg_ast.arg

View File

@ -1,2 +1,5 @@
import llvmlite.ir as ll
def is_terminated(basic_block): def is_terminated(basic_block):
return basic_block.instructions and basic_block.instructions[-1].is_terminator return (basic_block.instructions
and isinstance(basic_block.instructions[-1], ll.Terminator))

View File

@ -1,7 +1,7 @@
from types import SimpleNamespace from types import SimpleNamespace
from copy import copy from copy import copy
from llvm import core as lc import llvmlite.ir as ll
class VGeneric: class VGeneric:
@ -25,7 +25,7 @@ class VGeneric:
.format(repr(self), repr(other))) .format(repr(self), repr(other)))
def auto_load(self, builder): def auto_load(self, builder):
if isinstance(self.llvm_value.type, lc.PointerType): if isinstance(self.llvm_value.type, ll.PointerType):
return builder.load(self.llvm_value) return builder.load(self.llvm_value)
else: else:
return self.llvm_value return self.llvm_value
@ -33,7 +33,7 @@ class VGeneric:
def auto_store(self, builder, llvm_value): def auto_store(self, builder, llvm_value):
if self.llvm_value is None: if self.llvm_value is None:
self.llvm_value = llvm_value self.llvm_value = llvm_value
elif isinstance(self.llvm_value.type, lc.PointerType): elif isinstance(self.llvm_value.type, ll.PointerType):
builder.store(llvm_value, self.llvm_value) builder.store(llvm_value, self.llvm_value)
else: else:
raise RuntimeError( raise RuntimeError(

View File

@ -98,7 +98,9 @@ These steps are required to generate bitstream (``.bit``) files, build the MiSoC
$ cd ~/artiq-dev/misoc $ cd ~/artiq-dev/misoc
$ ./make.py -X ~/artiq/soc -t artiq all $ ./make.py -X ~/artiq/soc -t artiq all
* Then, build and flash the ARTIQ runtime: :: * Then, build and flash the ARTIQ runtime:
::
$ cd ~/artiq-dev $ cd ~/artiq-dev
$ git clone https://github.com/m-labs/artiq $ git clone https://github.com/m-labs/artiq
@ -120,36 +122,30 @@ The communication parameters are 115200 8-N-1.
Installing the host-side software Installing the host-side software
--------------------------------- ---------------------------------
* Install LLVM and its Python bindings: * Install LLVM and the llvmlite Python bindings: ::
The main dependency of ARTIQ is LLVM and its Python bindings (http://llvmpy.org). Currently, this installation is tedious because of the OpenRISC support not being merged upstream LLVM and because of incompatibilities between the versions of LLVM that support OpenRISC and the versions of LLVM that support the Python bindings. ::
$ cd ~/artiq-dev $ cd ~/artiq-dev
$ git clone https://github.com/openrisc/llvm-or1k $ git clone https://github.com/openrisc/llvm-or1k
$ cd ~/artiq-dev/llvm-or1k
$ git checkout b3a48efb2c05ed6cedc5395ae726c6a6573ef3ba
$ cat ~/artiq-dev/artiq/patches/llvm/* | patch -p1
$ cd ~/artiq-dev/llvm-or1k/tools $ cd ~/artiq-dev/llvm-or1k/tools
$ git clone https://github.com/openrisc/clang-or1k clang $ git clone https://github.com/openrisc/clang-or1k clang
$ cd ~/artiq-dev/llvm-or1k/tools/clang $ cd ~/artiq-dev/llvm-or1k/tools/clang
$ git checkout 02d831c7e7dc1517abed9cc96abdfb937af954eb
$ cat ~/artiq-dev/artiq/patches/clang/* | patch -p1
$ cd ~/artiq-dev/llvm-or1k $ cd ~/artiq-dev/llvm-or1k
$ mkdir build $ mkdir build
$ cd ~/artiq-dev/llvm-or1k/build $ cd ~/artiq-dev/llvm-or1k/build
$ ../configure --prefix=/usr/local/llvm-or1k $ ../configure --prefix=/usr/local/llvm-or1k
$ make ENABLE_OPTIMIZED=1 REQUIRES_RTTI=1 -j4 $ make ENABLE_OPTIMIZED=1 -j4
$ sudo -E make install ENABLE_OPTIMIZED=1 REQUIRES_RTTI=1 $ sudo -E make install ENABLE_OPTIMIZED=1
$ cd ~/artiq-dev $ cd ~/artiq-dev
$ git clone https://github.com/llvmpy/llvmpy $ git clone https://github.com/numba/llvmlite
$ cd ~/artiq-dev/llvmpy $ cd ~/artiq-dev/llvmlite
$ git checkout 7af2f7140391d4f708adf2721e84f23c1b89e97a $ cat /path_to/artiq/patches/llvmlite/* | patch -p1
$ cat /path_to/artiq/patches/llvmpy/* | patch -p1
$ LLVM_CONFIG_PATH=/usr/local/llvm-or1k/bin/llvm-config sudo -E python setup.py install $ LLVM_CONFIG_PATH=/usr/local/llvm-or1k/bin/llvm-config sudo -E python setup.py install
.. note::
llvmlite is in development and its API is not stable yet. Commit ID ``11a8303d02e3d6dd2d1e0e9065701795cd8a979f`` is known to work.
.. note:: .. note::
Compilation of LLVM can take more than 30 min on some machines. Compilation of LLVM can take more than 30 min on some machines.

View File

@ -1,32 +0,0 @@
From af106d252693b6af5c94d241fabed1c04cbb2fc6 Mon Sep 17 00:00:00 2001
From: Robert Jordens <jordens@gmail.com>
Date: Tue, 8 Jul 2014 22:35:58 -0600
Subject: [PATCH] exclude some broken aarch64 builtins
---
lib/CodeGen/CGBuiltin.cpp | 2 ++
1 file changed, 2 insertions(+)
diff --git a/lib/CodeGen/CGBuiltin.cpp b/lib/CodeGen/CGBuiltin.cpp
index 52e40db..d089ad3 100644
--- a/lib/CodeGen/CGBuiltin.cpp
+++ b/lib/CodeGen/CGBuiltin.cpp
@@ -1760,6 +1760,7 @@ static Value *EmitAArch64ScalarBuiltinExpr(CodeGenFunction &CGF,
// argument that specifies the vector type, need to handle each case.
switch (BuiltinID) {
default: break;
+#if 0
// Scalar Add
case AArch64::BI__builtin_neon_vaddd_s64:
Int = Intrinsic::aarch64_neon_vaddds;
@@ -1945,6 +1946,7 @@ static Value *EmitAArch64ScalarBuiltinExpr(CodeGenFunction &CGF,
case AArch64::BI__builtin_neon_vminnmvq_f32:
Int = Intrinsic::aarch64_neon_vminnmv;
AcrossVec = true; ExtendEle = false; s = "vminnmv"; break;
+#endif
}
if (!Int)
--
1.9.1

View File

@ -1,24 +0,0 @@
From 4dd12eaf0a14196f45ce4f25ed4a9f23bb3f55d5 Mon Sep 17 00:00:00 2001
From: Robert Jordens <jordens@gmail.com>
Date: Tue, 8 Jul 2014 22:37:03 -0600
Subject: [PATCH] or1k: initAsmInfo()
---
lib/Target/OR1K/OR1KTargetMachine.cpp | 1 +
1 file changed, 1 insertion(+)
diff --git a/lib/Target/OR1K/OR1KTargetMachine.cpp b/lib/Target/OR1K/OR1KTargetMachine.cpp
index 8f260f0..1771bce 100644
--- a/lib/Target/OR1K/OR1KTargetMachine.cpp
+++ b/lib/Target/OR1K/OR1KTargetMachine.cpp
@@ -41,6 +41,7 @@ OR1KTargetMachine(const Target &T, StringRef TT,
"f64:32:32-v64:32:32-v128:32:32-a0:0:32-n32"),
InstrInfo(), TLInfo(*this), TSInfo(*this),
FrameLowering(Subtarget) {
+ initAsmInfo();
}
namespace {
/// OR1K Code Generator Pass Configuration Options.
--
1.9.1

View File

@ -0,0 +1,38 @@
diff --git a/ffi/initfini.cpp b/ffi/initfini.cpp
index 42c8965..067be62 100644
--- a/ffi/initfini.cpp
+++ b/ffi/initfini.cpp
@@ -37,9 +37,10 @@ LLVMPY_Shutdown(){
// NOTE: it is important that we don't export functions which we don't use,
// especially those which may pull in large amounts of additional code or data.
-// INIT(AllTargetInfos)
-// INIT(AllTargets)
-// INIT(AllTargetMCs)
+INIT(AllTargetInfos)
+INIT(AllTargets)
+INIT(AllTargetMCs)
+INIT(AllAsmPrinters)
INIT(NativeTarget)
INIT(NativeAsmParser)
INIT(NativeAsmPrinter)
diff --git a/llvmlite/binding/initfini.py b/llvmlite/binding/initfini.py
index bfaa5b2..7d0df11 100644
--- a/llvmlite/binding/initfini.py
+++ b/llvmlite/binding/initfini.py
@@ -8,6 +8,15 @@ def initialize():
ffi.lib.LLVMPY_InitializeCore()
+def initialize_all_targets():
+ ffi.lib.LLVMPY_InitializeAllTargetInfos()
+ ffi.lib.LLVMPY_InitializeAllTargets()
+ ffi.lib.LLVMPY_InitializeAllTargetMCs()
+
+def initialize_all_asmprinters():
+ ffi.lib.LLVMPY_InitializeAllAsmPrinters()
+
+
def initialize_native_target():
"""
Initialize the native (host) target. Necessary before doing any

View File

@ -1,25 +0,0 @@
From 7f84a57f4a73837e50df7a8c6905773c0de568ab Mon Sep 17 00:00:00 2001
From: Robert Jordens <jordens@gmail.com>
Date: Tue, 8 Jul 2014 22:40:10 -0600
Subject: [PATCH] use 3.3 opcodes
---
llvm/core.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/core.py b/llvm/core.py
index 20ad062..d33860f 100644
--- a/llvm/core.py
+++ b/llvm/core.py
@@ -174,7 +174,7 @@ class OpcodeEnum(Enum):
OPCODE_PTRTOINT = 42
OPCODE_INTTOPTR = 43
OPCODE_BITCAST = 44
- if llvm.version <= (3, 3):
+ if llvm.version <= (3, 3) or True:
OPCODE_ICMP = 45
OPCODE_FCMP = 46
OPCODE_PHI = 47
--
1.9.1

View File

@ -1,12 +0,0 @@
diff --git a/llvm/core.py b/llvm/core.py
index 20ad062..245ac65 100644
--- a/llvm/core.py
+++ b/llvm/core.py
@@ -379,6 +379,7 @@ class AttrEnum(Enum):
ATTR_NAKED = AttrVal.Naked
ATTR_INLINE_HINT = AttrVal.InlineHint
ATTR_STACK_ALIGNMENT = AttrVal.StackAlignment
+ ATTR_RETURNS_TWICE = AttrVal.ReturnsTwice
AttrEnum.declare()

View File

@ -2,8 +2,9 @@ import unittest
import ast import ast
import inspect import inspect
from fractions import Fraction from fractions import Fraction
from ctypes import CFUNCTYPE, c_int, c_int32, c_int64, c_double
from llvm import ee as le import llvmlite.binding as llvm
from artiq.language.core import int64, array from artiq.language.core import int64, array
from artiq.py2llvm.infer_types import infer_function_types from artiq.py2llvm.infer_types import infer_function_types
@ -11,6 +12,11 @@ from artiq.py2llvm import base_types, arrays
from artiq.py2llvm.module import Module from artiq.py2llvm.module import Module
llvm.initialize()
llvm.initialize_native_target()
llvm.initialize_native_asmprinter()
def _base_types(choice): def _base_types(choice):
a = 2 # promoted later to int64 a = 2 # promoted later to int64
b = a + 1 # initially int32, becomes int64 after a is promoted b = a + 1 # initially int32, becomes int64 after a is promoted
@ -81,34 +87,42 @@ class FunctionArrayTypesCase(unittest.TestCase):
self.assertEqual(self.ns["i"].nbits, 32) self.assertEqual(self.ns["i"].nbits, 32)
def _value_to_ctype(v):
if isinstance(v, base_types.VBool):
return c_int
elif isinstance(v, base_types.VInt):
if v.nbits == 32:
return c_int32
elif v.nbits == 64:
return c_int64
else:
raise NotImplementedError(str(v))
elif isinstance(v, base_types.VFloat):
return c_double
else:
raise NotImplementedError(str(v))
class CompiledFunction: class CompiledFunction:
def __init__(self, function, param_types): def __init__(self, function, param_types):
module = Module() module = Module()
func_def = ast.parse(inspect.getsource(function)).body[0] func_def = ast.parse(inspect.getsource(function)).body[0]
self.function, self.retval = module.compile_function( function, retval = module.compile_function(func_def, param_types)
func_def, param_types) argvals = [param_types[arg.arg] for arg in func_def.args.args]
self.argval = [param_types[arg.arg] for arg in func_def.args.args]
self.ee = module.get_ee() ee = module.get_ee()
cfptr = ee.get_pointer_to_global(
module.llvm_module.get_function(function.name))
retval_ctype = _value_to_ctype(retval)
argval_ctypes = [_value_to_ctype(argval) for argval in argvals]
self.cfunc = CFUNCTYPE(retval_ctype, *argval_ctypes)(cfptr)
# HACK: prevent garbage collection of self.cfunc internals
self.ee = ee
def __call__(self, *args): def __call__(self, *args):
args_llvm = [] return self.cfunc(*args)
for av, a in zip(self.argval, args):
if isinstance(av, base_types.VInt):
al = le.GenericValue.int(av.get_llvm_type(), a)
elif isinstance(av, base_types.VFloat):
al = le.GenericValue.real(av.get_llvm_type(), a)
else:
raise NotImplementedError
args_llvm.append(al)
result = self.ee.run_function(self.function, args_llvm)
if isinstance(self.retval, base_types.VBool):
return bool(result.as_int())
elif isinstance(self.retval, base_types.VInt):
return result.as_int_signed()
elif isinstance(self.retval, base_types.VFloat):
return result.as_real(self.retval.get_llvm_type())
else:
raise NotImplementedError
def arith(op, a, b): def arith(op, a, b):