Add LLVM IR generation for function calls.

This commit is contained in:
whitequark 2015-07-21 13:45:27 +03:00
parent e299801c0f
commit ec9d40b04f
3 changed files with 59 additions and 27 deletions

View File

@ -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):

View File

@ -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:

View File

@ -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):
try:
self.llfunction = self.llmodule.get_global(func.name)
if self.llfunction is None:
llargtys = [] llargtys = []
for arg in func.arguments: for arg in func.arguments:
llargtys.append(self.llty_of_type(arg.type)) llargtys.append(self.llty_of_type(arg.type))
llfunty = ll.FunctionType(args=llargtys, llfunty = ll.FunctionType(args=llargtys,
return_type=self.llty_of_type(func.type.ret, for_return=True)) return_type=self.llty_of_type(func.type.ret, for_return=True))
try:
self.llfunction = ll.Function(self.llmodule, llfunty, func.name) 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()])