forked from M-Labs/artiq
Add LLVM IR generation for function calls.
This commit is contained in:
parent
e299801c0f
commit
ec9d40b04f
|
@ -467,7 +467,7 @@ class TEnvironment(types.TMono):
|
||||||
def is_environment(typ):
|
def is_environment(typ):
|
||||||
return isinstance(typ, TEnvironment)
|
return isinstance(typ, TEnvironment)
|
||||||
|
|
||||||
class EnvironmentArgument(NamedValue):
|
class EnvironmentArgument(Argument):
|
||||||
"""
|
"""
|
||||||
A function argument specifying an outer environment.
|
A function argument specifying an outer environment.
|
||||||
"""
|
"""
|
||||||
|
@ -799,7 +799,7 @@ class Call(Instruction):
|
||||||
def opcode(self):
|
def opcode(self):
|
||||||
return "call"
|
return "call"
|
||||||
|
|
||||||
def function(self):
|
def target_function(self):
|
||||||
return self.operands[0]
|
return self.operands[0]
|
||||||
|
|
||||||
def arguments(self):
|
def arguments(self):
|
||||||
|
|
|
@ -174,7 +174,7 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
|
|
||||||
optargs = []
|
optargs = []
|
||||||
for arg_name in typ.optargs:
|
for arg_name in typ.optargs:
|
||||||
optargs.append(ir.Argument(ir.TSSAOption(typ.optargs[arg_name]), "arg." + arg_name))
|
optargs.append(ir.Argument(ir.TOption(typ.optargs[arg_name]), "arg." + arg_name))
|
||||||
|
|
||||||
func = ir.Function(typ, ".".join(self.name), [env_arg] + args + optargs)
|
func = ir.Function(typ, ".".join(self.name), [env_arg] + args + optargs)
|
||||||
self.functions.append(func)
|
self.functions.append(func)
|
||||||
|
@ -1189,11 +1189,11 @@ class ARTIQIRGenerator(algorithm.Visitor):
|
||||||
optarg_typ = ir.TOption(typ.optargs[optarg_name])
|
optarg_typ = ir.TOption(typ.optargs[optarg_name])
|
||||||
for keyword in node.keywords:
|
for keyword in node.keywords:
|
||||||
if keyword.arg == optarg_name:
|
if keyword.arg == optarg_name:
|
||||||
value = self.append(ir.Alloc(optarg_typ, [self.visit(keyword.value)]))
|
value = self.append(ir.Alloc([self.visit(keyword.value)], optarg_typ))
|
||||||
args.append(value)
|
args.append(value)
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
value = self.append(ir.Alloc(optarg_typ, []))
|
value = self.append(ir.Alloc([], optarg_typ))
|
||||||
args.append(value)
|
args.append(value)
|
||||||
|
|
||||||
if self.unwind_target is None:
|
if self.unwind_target is None:
|
||||||
|
|
|
@ -16,18 +16,21 @@ class LLVMIRGenerator:
|
||||||
self.llmap = {}
|
self.llmap = {}
|
||||||
self.fixups = []
|
self.fixups = []
|
||||||
|
|
||||||
def llty_of_type(self, typ, for_alloc=False, for_return=False):
|
def llty_of_type(self, typ, bare=False, for_return=False):
|
||||||
if types.is_tuple(typ):
|
if types.is_tuple(typ):
|
||||||
return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts])
|
return ll.LiteralStructType([self.llty_of_type(eltty) for eltty in typ.elts])
|
||||||
elif types.is_function(typ):
|
elif types.is_function(typ):
|
||||||
envarg = ll.IntType(8).as_pointer
|
envarg = ll.IntType(8).as_pointer()
|
||||||
llty = ll.FunctionType(args=[envarg] +
|
llty = ll.FunctionType(args=[envarg] +
|
||||||
[self.llty_of_type(typ.args[arg])
|
[self.llty_of_type(typ.args[arg])
|
||||||
for arg in typ.args] +
|
for arg in typ.args] +
|
||||||
[self.llty_of_type(ir.TOption(typ.optargs[arg]))
|
[self.llty_of_type(ir.TOption(typ.optargs[arg]))
|
||||||
for arg in typ.optargs],
|
for arg in typ.optargs],
|
||||||
return_type=self.llty_of_type(typ.ret, for_return=True))
|
return_type=self.llty_of_type(typ.ret, for_return=True))
|
||||||
return llty.as_pointer()
|
if bare:
|
||||||
|
return llty
|
||||||
|
else:
|
||||||
|
return ll.LiteralStructType([envarg, llty.as_pointer()])
|
||||||
elif builtins.is_none(typ):
|
elif builtins.is_none(typ):
|
||||||
if for_return:
|
if for_return:
|
||||||
return ll.VoidType()
|
return ll.VoidType()
|
||||||
|
@ -55,7 +58,7 @@ class LLVMIRGenerator:
|
||||||
elif ir.is_environment(typ):
|
elif ir.is_environment(typ):
|
||||||
llty = ll.LiteralStructType([self.llty_of_type(typ.params[name])
|
llty = ll.LiteralStructType([self.llty_of_type(typ.params[name])
|
||||||
for name in typ.params])
|
for name in typ.params])
|
||||||
if for_alloc:
|
if bare:
|
||||||
return llty
|
return llty
|
||||||
else:
|
else:
|
||||||
return llty.as_pointer()
|
return llty.as_pointer()
|
||||||
|
@ -76,10 +79,17 @@ class LLVMIRGenerator:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
def map(self, value):
|
def map(self, value):
|
||||||
if isinstance(value, (ir.Instruction, ir.BasicBlock)):
|
if isinstance(value, (ir.Argument, ir.Instruction, ir.BasicBlock)):
|
||||||
return self.llmap[value]
|
return self.llmap[value]
|
||||||
elif isinstance(value, ir.Constant):
|
elif isinstance(value, ir.Constant):
|
||||||
return self.llconst_of_const(value)
|
return self.llconst_of_const(value)
|
||||||
|
elif isinstance(value, ir.Function):
|
||||||
|
llfun = self.llmodule.get_global(value.name)
|
||||||
|
if llfun is None:
|
||||||
|
return ll.Function(self.llmodule, self.llty_of_type(value.type, bare=True),
|
||||||
|
value.name)
|
||||||
|
else:
|
||||||
|
return llfun
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
|
@ -88,24 +98,30 @@ class LLVMIRGenerator:
|
||||||
self.process_function(func)
|
self.process_function(func)
|
||||||
|
|
||||||
def process_function(self, func):
|
def process_function(self, func):
|
||||||
llargtys = []
|
|
||||||
for arg in func.arguments:
|
|
||||||
llargtys.append(self.llty_of_type(arg.type))
|
|
||||||
llfunty = ll.FunctionType(args=llargtys,
|
|
||||||
return_type=self.llty_of_type(func.type.ret, for_return=True))
|
|
||||||
|
|
||||||
try:
|
try:
|
||||||
self.llfunction = ll.Function(self.llmodule, llfunty, func.name)
|
self.llfunction = self.llmodule.get_global(func.name)
|
||||||
|
if self.llfunction is None:
|
||||||
|
llargtys = []
|
||||||
|
for arg in func.arguments:
|
||||||
|
llargtys.append(self.llty_of_type(arg.type))
|
||||||
|
llfunty = ll.FunctionType(args=llargtys,
|
||||||
|
return_type=self.llty_of_type(func.type.ret, for_return=True))
|
||||||
|
self.llfunction = ll.Function(self.llmodule, llfunty, func.name)
|
||||||
|
|
||||||
self.llmap = {}
|
self.llmap = {}
|
||||||
self.llbuilder = ll.IRBuilder()
|
self.llbuilder = ll.IRBuilder()
|
||||||
self.fixups = []
|
self.fixups = []
|
||||||
|
|
||||||
# First, create all basic blocks.
|
# First, map arguments.
|
||||||
|
for arg, llarg in zip(func.arguments, self.llfunction.args):
|
||||||
|
self.llmap[arg] = llarg
|
||||||
|
|
||||||
|
# Second, create all basic blocks.
|
||||||
for block in func.basic_blocks:
|
for block in func.basic_blocks:
|
||||||
llblock = self.llfunction.append_basic_block(block.name)
|
llblock = self.llfunction.append_basic_block(block.name)
|
||||||
self.llmap[block] = llblock
|
self.llmap[block] = llblock
|
||||||
|
|
||||||
# Second, translate all instructions.
|
# Third, translate all instructions.
|
||||||
for block in func.basic_blocks:
|
for block in func.basic_blocks:
|
||||||
self.llbuilder.position_at_end(self.llmap[block])
|
self.llbuilder.position_at_end(self.llmap[block])
|
||||||
for insn in block.instructions:
|
for insn in block.instructions:
|
||||||
|
@ -113,7 +129,7 @@ class LLVMIRGenerator:
|
||||||
assert llinsn is not None
|
assert llinsn is not None
|
||||||
self.llmap[insn] = llinsn
|
self.llmap[insn] = llinsn
|
||||||
|
|
||||||
# Third, fixup phis.
|
# Fourth, fixup phis.
|
||||||
for fixup in self.fixups:
|
for fixup in self.fixups:
|
||||||
fixup()
|
fixup()
|
||||||
finally:
|
finally:
|
||||||
|
@ -131,7 +147,7 @@ class LLVMIRGenerator:
|
||||||
|
|
||||||
def process_Alloc(self, insn):
|
def process_Alloc(self, insn):
|
||||||
if ir.is_environment(insn.type):
|
if ir.is_environment(insn.type):
|
||||||
return self.llbuilder.alloca(self.llty_of_type(insn.type, for_alloc=True),
|
return self.llbuilder.alloca(self.llty_of_type(insn.type, bare=True),
|
||||||
name=insn.name)
|
name=insn.name)
|
||||||
elif builtins.is_list(insn.type):
|
elif builtins.is_list(insn.type):
|
||||||
llsize = self.map(insn.operands[0])
|
llsize = self.map(insn.operands[0])
|
||||||
|
@ -171,7 +187,14 @@ class LLVMIRGenerator:
|
||||||
def process_SetLocal(self, insn):
|
def process_SetLocal(self, insn):
|
||||||
env = insn.environment()
|
env = insn.environment()
|
||||||
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name)
|
llptr = self.llptr_to_var(self.map(env), env.type, insn.var_name)
|
||||||
return self.llbuilder.store(self.map(insn.value()), llptr)
|
llvalue = self.map(insn.value())
|
||||||
|
if llptr.type.pointee != llvalue.type:
|
||||||
|
# The environment argument is an i8*, so that all closures can
|
||||||
|
# unify with each other regardless of environment type or size.
|
||||||
|
# We fixup the type on assignment into the ".outer" slot.
|
||||||
|
assert isinstance(insn.value(), ir.EnvironmentArgument)
|
||||||
|
llvalue = self.llbuilder.bitcast(llvalue, llptr.type.pointee)
|
||||||
|
return self.llbuilder.store(llvalue, llptr)
|
||||||
|
|
||||||
def attr_index(self, insn):
|
def attr_index(self, insn):
|
||||||
return list(insn.object().type.attributes.keys()).index(insn.attr)
|
return list(insn.object().type.attributes.keys()).index(insn.attr)
|
||||||
|
@ -362,11 +385,20 @@ class LLVMIRGenerator:
|
||||||
else:
|
else:
|
||||||
assert False
|
assert False
|
||||||
|
|
||||||
# def process_Closure(self, insn):
|
def process_Closure(self, insn):
|
||||||
# pass
|
llvalue = ll.Constant(self.llty_of_type(insn.target_function.type), ll.Undefined)
|
||||||
|
llenv = self.llbuilder.bitcast(self.map(insn.environment()), ll.IntType(8).as_pointer())
|
||||||
|
llvalue = self.llbuilder.insert_value(llvalue, llenv, 0)
|
||||||
|
llvalue = self.llbuilder.insert_value(llvalue, self.map(insn.target_function), 1,
|
||||||
|
name=insn.name)
|
||||||
|
return llvalue
|
||||||
|
|
||||||
# def process_Call(self, insn):
|
def process_Call(self, insn):
|
||||||
# pass
|
llclosure, llargs = self.map(insn.target_function()), map(self.map, insn.arguments())
|
||||||
|
llenv = self.llbuilder.extract_value(llclosure, 0)
|
||||||
|
llfun = self.llbuilder.extract_value(llclosure, 1)
|
||||||
|
return self.llbuilder.call(llfun, [llenv] + list(llargs),
|
||||||
|
name=insn.name)
|
||||||
|
|
||||||
def process_Select(self, insn):
|
def process_Select(self, insn):
|
||||||
return self.llbuilder.select(self.map(insn.cond()),
|
return self.llbuilder.select(self.map(insn.cond()),
|
||||||
|
@ -383,7 +415,7 @@ class LLVMIRGenerator:
|
||||||
# pass
|
# pass
|
||||||
|
|
||||||
def process_Return(self, insn):
|
def process_Return(self, insn):
|
||||||
if builtins.is_none(insn.type):
|
if builtins.is_none(insn.value().type):
|
||||||
return self.llbuilder.ret_void()
|
return self.llbuilder.ret_void()
|
||||||
else:
|
else:
|
||||||
return self.llbuilder.ret(self.llmap[insn.value()])
|
return self.llbuilder.ret(self.llmap[insn.value()])
|
||||||
|
|
Loading…
Reference in New Issue