|
@@ -52,23 +52,13 @@ def map_and_simplify_generator(function, instruction):
|
|
|
# First handle the children by mapping on them and then simplifying them.
|
|
|
new_children = []
|
|
|
for inst in instruction.get_children():
|
|
|
- try:
|
|
|
- gen = map_and_simplify_generator(function, inst)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- new_children.append(ex.result)
|
|
|
+ new_inst, = yield [("CALL_ARGS", [map_and_simplify_generator, (function, inst)])]
|
|
|
+ new_children.append(new_inst)
|
|
|
|
|
|
# Then apply the function to the top-level node.
|
|
|
- try:
|
|
|
- gen = function(instruction.create(new_children))
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- # Finally, simplify the transformed top-level node.
|
|
|
- raise primitive_functions.PrimitiveFinished(ex.result.simplify_node())
|
|
|
+ transformed, = yield [("CALL_ARGS", [function, (instruction.create(new_children),)])]
|
|
|
+ # Finally, simplify the transformed top-level node.
|
|
|
+ raise primitive_functions.PrimitiveFinished(transformed.simplify_node())
|
|
|
|
|
|
def expand_constant_read(instruction):
|
|
|
"""Tries to replace a read of a constant node by a literal."""
|
|
@@ -253,36 +243,33 @@ class ModelverseJit(object):
|
|
|
self.jitted_entry_points[body_id] = function_name
|
|
|
self.jit_globals[function_name] = None
|
|
|
|
|
|
- try:
|
|
|
- gen = self.jit_parameters(body_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- parameter_ids, parameter_list = ex.result
|
|
|
+ (parameter_ids, parameter_list), = yield [("CALL_ARGS", [self.jit_parameters, (body_id,)])]
|
|
|
|
|
|
param_dict = dict(zip(parameter_ids, parameter_list))
|
|
|
body_param_dict = dict(zip(parameter_ids, [p + "_ptr" for p in parameter_list]))
|
|
|
dependencies = set([body_id])
|
|
|
self.compilation_dependencies[body_id] = dependencies
|
|
|
- try:
|
|
|
- gen = AnalysisState(
|
|
|
- self, body_id, user_root, body_param_dict,
|
|
|
- self.max_instructions).analyze(body_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- del self.compilation_dependencies[body_id]
|
|
|
- constructed_body = ex.result
|
|
|
- except JitCompilationFailedException as ex:
|
|
|
+
|
|
|
+ def handle_jit_exception(exception):
|
|
|
+ # If analysis fails, then a JitCompilationFailedException will be thrown.
|
|
|
del self.compilation_dependencies[body_id]
|
|
|
for dep in dependencies:
|
|
|
self.mark_no_jit(dep)
|
|
|
if dep in self.jitted_entry_points:
|
|
|
del self.jitted_entry_points[dep]
|
|
|
+
|
|
|
raise JitCompilationFailedException(
|
|
|
- "%s (function '%s' at %d)" % (ex.message, function_name, body_id))
|
|
|
+ "%s (function '%s' at %d)" % (exception.message, function_name, body_id))
|
|
|
+
|
|
|
+ # Try to analyze the function's body.
|
|
|
+ yield [("TRY", [])]
|
|
|
+ yield [("CATCH", [JitCompilationFailedException, handle_jit_exception])]
|
|
|
+ state = AnalysisState(
|
|
|
+ self, body_id, user_root, body_param_dict,
|
|
|
+ self.max_instructions)
|
|
|
+ constructed_body, = yield [("CALL_ARGS", [state.analyze, (body_id,)])]
|
|
|
+ yield [("END_TRY", [])]
|
|
|
+ del self.compilation_dependencies[body_id]
|
|
|
|
|
|
# Write a prologue and prepend it to the generated function body.
|
|
|
prologue_statements = []
|
|
@@ -300,13 +287,8 @@ class ModelverseJit(object):
|
|
|
constructed_body = tree_ir.create_block(
|
|
|
*(prologue_statements + [constructed_body]))
|
|
|
|
|
|
- try:
|
|
|
- gen = optimize_tree_ir(constructed_body)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- constructed_body = ex.result
|
|
|
+ # Optimize the function's body.
|
|
|
+ constructed_body, = yield [("CALL_ARGS", [optimize_tree_ir, (constructed_body,)])]
|
|
|
|
|
|
# Wrap the IR in a function definition, give it a unique name.
|
|
|
constructed_function = tree_ir.DefineFunctionInstruction(
|
|
@@ -391,37 +373,19 @@ class AnalysisState(object):
|
|
|
if debug_info is not None:
|
|
|
debug_info, = yield [("RV", [debug_info])]
|
|
|
|
|
|
- try:
|
|
|
- gen = self.instruction_analyzers[instruction_val](self, instruction_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except StopIteration:
|
|
|
- raise Exception(
|
|
|
- "Instruction analyzer (for '%s') finished without returning a value!" %
|
|
|
- (instruction_val))
|
|
|
- except primitive_functions.PrimitiveFinished as outer_e:
|
|
|
- # Check if the instruction has a 'next' instruction.
|
|
|
- next_instr, = yield [("RD", [instruction_id, "next"])]
|
|
|
- if self.jit.tracing_enabled:
|
|
|
- outer_result = tree_ir.with_debug_info_trace(
|
|
|
- outer_e.result, debug_info, self.function_name)
|
|
|
- else:
|
|
|
- outer_result = outer_e.result
|
|
|
-
|
|
|
- if next_instr is None:
|
|
|
- raise primitive_functions.PrimitiveFinished(outer_result)
|
|
|
- else:
|
|
|
- gen = self.analyze(next_instr)
|
|
|
- try:
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as inner_e:
|
|
|
- raise primitive_functions.PrimitiveFinished(
|
|
|
- tree_ir.CompoundInstruction(
|
|
|
- outer_result,
|
|
|
- inner_e.result))
|
|
|
+ # Analyze the instruction itself.
|
|
|
+ outer_result, = yield [
|
|
|
+ ("CALL_ARGS", [self.instruction_analyzers[instruction_val], (self, instruction_id)])]
|
|
|
+ # Check if the instruction has a 'next' instruction.
|
|
|
+ next_instr, = yield [("RD", [instruction_id, "next"])]
|
|
|
+ if next_instr is None:
|
|
|
+ raise primitive_functions.PrimitiveFinished(outer_result)
|
|
|
+ else:
|
|
|
+ next_result, = yield [("CALL_ARGS", [self.analyze, (next_instr,)])]
|
|
|
+ raise primitive_functions.PrimitiveFinished(
|
|
|
+ tree_ir.CompoundInstruction(
|
|
|
+ outer_result,
|
|
|
+ next_result))
|
|
|
else:
|
|
|
raise JitCompilationFailedException(
|
|
|
"Unknown instruction type: '%s'" % (instruction_val))
|
|
@@ -430,13 +394,8 @@ class AnalysisState(object):
|
|
|
"""Tries to compile a list of IR trees from the given list of instruction ids."""
|
|
|
results = []
|
|
|
for inst in instruction_ids:
|
|
|
- try:
|
|
|
- gen = self.analyze(inst)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- results.append(ex.result)
|
|
|
+ analyzed_inst, = yield [("CALL_ARGS", [self.analyze, (inst,)])]
|
|
|
+ results.append(analyzed_inst)
|
|
|
|
|
|
raise primitive_functions.PrimitiveFinished(results)
|
|
|
|
|
@@ -448,14 +407,9 @@ class AnalysisState(object):
|
|
|
tree_ir.ReturnInstruction(
|
|
|
tree_ir.EmptyInstruction()))
|
|
|
else:
|
|
|
- try:
|
|
|
- gen = self.analyze(retval_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- raise primitive_functions.PrimitiveFinished(
|
|
|
- tree_ir.ReturnInstruction(ex.result))
|
|
|
+ retval, = yield [("CALL_ARGS", [self.analyze, (retval_id,)])]
|
|
|
+ raise primitive_functions.PrimitiveFinished(
|
|
|
+ tree_ir.ReturnInstruction(retval))
|
|
|
|
|
|
def analyze_if(self, instruction_id):
|
|
|
"""Tries to analyze the given 'if' instruction."""
|
|
@@ -464,25 +418,22 @@ class AnalysisState(object):
|
|
|
("RD", [instruction_id, "then"]),
|
|
|
("RD", [instruction_id, "else"])]
|
|
|
|
|
|
- try:
|
|
|
- gen = self.analyze_all(
|
|
|
- [cond, true]
|
|
|
- if false is None
|
|
|
- else [cond, true, false])
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- if false is None:
|
|
|
- cond_r, true_r = ex.result
|
|
|
- false_r = tree_ir.EmptyInstruction()
|
|
|
- else:
|
|
|
- cond_r, true_r, false_r = ex.result
|
|
|
- raise primitive_functions.PrimitiveFinished(
|
|
|
- tree_ir.SelectInstruction(
|
|
|
- tree_ir.ReadValueInstruction(cond_r),
|
|
|
- true_r,
|
|
|
- false_r))
|
|
|
+ analysis_results, = yield [("CALL_ARGS", [self.analyze_all, (
|
|
|
+ [cond, true]
|
|
|
+ if false is None
|
|
|
+ else [cond, true, false],)])]
|
|
|
+
|
|
|
+ if false is None:
|
|
|
+ cond_r, true_r = analysis_results
|
|
|
+ false_r = tree_ir.EmptyInstruction()
|
|
|
+ else:
|
|
|
+ cond_r, true_r, false_r = analysis_results
|
|
|
+
|
|
|
+ raise primitive_functions.PrimitiveFinished(
|
|
|
+ tree_ir.SelectInstruction(
|
|
|
+ tree_ir.ReadValueInstruction(cond_r),
|
|
|
+ true_r,
|
|
|
+ false_r))
|
|
|
|
|
|
def analyze_while(self, instruction_id):
|
|
|
"""Tries to analyze the given 'while' instruction."""
|
|
@@ -490,21 +441,15 @@ class AnalysisState(object):
|
|
|
("RD", [instruction_id, "cond"]),
|
|
|
("RD", [instruction_id, "body"])]
|
|
|
|
|
|
- try:
|
|
|
- gen = self.analyze_all([cond, body])
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- cond_r, body_r = ex.result
|
|
|
- raise primitive_functions.PrimitiveFinished(
|
|
|
- tree_ir.LoopInstruction(
|
|
|
- tree_ir.CompoundInstruction(
|
|
|
- tree_ir.SelectInstruction(
|
|
|
- tree_ir.ReadValueInstruction(cond_r),
|
|
|
- tree_ir.EmptyInstruction(),
|
|
|
- tree_ir.BreakInstruction()),
|
|
|
- body_r)))
|
|
|
+ (cond_r, body_r), = yield [("CALL_ARGS", [self.analyze_all, ([cond, body],)])]
|
|
|
+ raise primitive_functions.PrimitiveFinished(
|
|
|
+ tree_ir.LoopInstruction(
|
|
|
+ tree_ir.CompoundInstruction(
|
|
|
+ tree_ir.SelectInstruction(
|
|
|
+ tree_ir.ReadValueInstruction(cond_r),
|
|
|
+ tree_ir.EmptyInstruction(),
|
|
|
+ tree_ir.BreakInstruction()),
|
|
|
+ body_r)))
|
|
|
|
|
|
def analyze_constant(self, instruction_id):
|
|
|
"""Tries to analyze the given 'constant' (literal) instruction."""
|
|
@@ -531,13 +476,8 @@ class AnalysisState(object):
|
|
|
# yield None
|
|
|
|
|
|
value_id, = yield [("RD", [instruction_id, "value"])]
|
|
|
- try:
|
|
|
- gen = self.analyze(value_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- value_local = tree_ir.StoreLocalInstruction('value', ex.result)
|
|
|
+ value_val, = yield [("CALL_ARGS", [self.analyze, (value_id,)])]
|
|
|
+ value_local = tree_ir.StoreLocalInstruction('value', value_val)
|
|
|
|
|
|
store_user_root = self.retrieve_user_root()
|
|
|
last_output = tree_ir.StoreLocalInstruction(
|
|
@@ -785,13 +725,7 @@ class AnalysisState(object):
|
|
|
var_id, value_id = yield [("RD", [instruction_id, "var"]),
|
|
|
("RD", [instruction_id, "value"])]
|
|
|
|
|
|
- try:
|
|
|
- gen = self.analyze_all([var_id, value_id])
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- var_r, value_r = ex.result
|
|
|
+ (var_r, value_r), = yield [("CALL_ARGS", [self.analyze_all, ([var_id, value_id],)])]
|
|
|
|
|
|
# Assignments work like this:
|
|
|
#
|
|
@@ -822,14 +756,7 @@ class AnalysisState(object):
|
|
|
def analyze_access(self, instruction_id):
|
|
|
"""Tries to analyze the given 'access' instruction."""
|
|
|
var_id, = yield [("RD", [instruction_id, "var"])]
|
|
|
-
|
|
|
- try:
|
|
|
- gen = self.analyze(var_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- var_r = ex.result
|
|
|
+ var_r, = yield [("CALL_ARGS", [self.analyze, (var_id,)])]
|
|
|
|
|
|
# Accessing a variable is pretty easy. It really just boils
|
|
|
# down to reading the value corresponding to the 'value' key
|
|
@@ -859,13 +786,7 @@ class AnalysisState(object):
|
|
|
compiled_func = self.jit.lookup_compiled_function(callee_name)
|
|
|
if compiled_func is None:
|
|
|
# Compile the callee.
|
|
|
- try:
|
|
|
- gen = self.jit.jit_compile(self.user_root, body_id, callee_name)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- pass
|
|
|
+ yield [("CALL_ARGS", [self.jit.jit_compile, (self.user_root, body_id, callee_name)])]
|
|
|
else:
|
|
|
self.jit.register_compiled(body_id, compiled_func, callee_name)
|
|
|
|
|
@@ -880,13 +801,7 @@ class AnalysisState(object):
|
|
|
intrinsic = self.jit.get_intrinsic(compiled_func_name)
|
|
|
|
|
|
# Analyze the argument dictionary.
|
|
|
- try:
|
|
|
- gen = self.analyze_arguments(first_parameter_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- named_args = ex.result
|
|
|
+ named_args, = yield [("CALL_ARGS", [self.analyze_arguments, (first_parameter_id,)])]
|
|
|
|
|
|
if intrinsic is not None:
|
|
|
raise primitive_functions.PrimitiveFinished(
|
|
@@ -907,13 +822,8 @@ class AnalysisState(object):
|
|
|
param_name_id, = yield [("RD", [next_param, "name"])]
|
|
|
param_name, = yield [("RV", [param_name_id])]
|
|
|
param_val_id, = yield [("RD", [next_param, "value"])]
|
|
|
- try:
|
|
|
- gen = self.analyze(param_val_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- named_args.append((param_name, ex.result))
|
|
|
+ param_val, = yield [("CALL_ARGS", [self.analyze, (param_val_id,)])]
|
|
|
+ named_args.append((param_name, param_val))
|
|
|
|
|
|
next_param, = yield [("RD", [next_param, "next_param"])]
|
|
|
|
|
@@ -923,21 +833,8 @@ class AnalysisState(object):
|
|
|
"""Analyzes a call to an unknown function."""
|
|
|
|
|
|
# First off, let's analyze the callee and the argument list.
|
|
|
- try:
|
|
|
- gen = self.analyze(func_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- func_val = ex.result
|
|
|
-
|
|
|
- try:
|
|
|
- gen = self.analyze_arguments(first_arg_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- except primitive_functions.PrimitiveFinished as ex:
|
|
|
- named_args = ex.result
|
|
|
+ func_val, = yield [("CALL_ARGS", [self.analyze, (func_id,)])]
|
|
|
+ named_args, = yield [("CALL_ARGS", [self.analyze_arguments, (first_arg_id,)])]
|
|
|
|
|
|
# Call the __call_function function to run the interpreter, like so:
|
|
|
#
|
|
@@ -972,20 +869,15 @@ class AnalysisState(object):
|
|
|
global_val, = yield [("RD", [global_var, "value"])]
|
|
|
|
|
|
if global_val is not None:
|
|
|
- gen = self.analyze_direct_call(
|
|
|
- global_val, resolved_var_name, first_param_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- # PrimitiveFinished exception will bubble up from here.
|
|
|
+ result, = yield [("CALL_ARGS", [self.analyze_direct_call, (
|
|
|
+ global_val, resolved_var_name, first_param_id)])]
|
|
|
+ raise primitive_functions.PrimitiveFinished(result)
|
|
|
elif func_instruction_op['value'] == 'constant':
|
|
|
# 'const(func_id)' instructions are also translated to direct calls.
|
|
|
function_val_id, = yield [("RD", [func_id, "node"])]
|
|
|
- gen = self.analyze_direct_call(
|
|
|
- function_val_id, None, first_param_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
+ result, = yield [("CALL_ARGS", [self.analyze_direct_call, (
|
|
|
+ function_val_id, None, first_param_id)])]
|
|
|
+ raise primitive_functions.PrimitiveFinished(result)
|
|
|
|
|
|
raise JitCompilationFailedException(
|
|
|
"Cannot JIT function calls that target an unknown value as direct calls.")
|
|
@@ -995,20 +887,18 @@ class AnalysisState(object):
|
|
|
func_id, first_param_id, = yield [("RD", [instruction_id, "func"]),
|
|
|
("RD", [instruction_id, "params"])]
|
|
|
|
|
|
- try:
|
|
|
- # Try to analyze the call as a direct call.
|
|
|
- gen = self.try_analyze_direct_call(func_id, first_param_id)
|
|
|
- inp = None
|
|
|
- while 1:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- # PrimitiveFinished exception will bubble up from here.
|
|
|
- except JitCompilationFailedException:
|
|
|
+ def handle_exception(exception):
|
|
|
# Looks like we'll have to compile it as an indirect call.
|
|
|
gen = self.analyze_indirect_call(func_id, first_param_id)
|
|
|
- inp = None
|
|
|
- while True:
|
|
|
- inp = yield gen.send(inp)
|
|
|
- # PrimitiveFinished exception will bubble up from here.
|
|
|
+ result, = yield [("CALL", [gen])]
|
|
|
+ raise primitive_functions.PrimitiveFinished(result)
|
|
|
+
|
|
|
+ # Try to analyze the call as a direct call.
|
|
|
+ yield [("TRY", [])]
|
|
|
+ yield [("CATCH", [JitCompilationFailedException, handle_exception])]
|
|
|
+ result, = yield [("CALL_ARGS", [self.try_analyze_direct_call, (func_id, first_param_id)])]
|
|
|
+ yield [("END_TRY", [])]
|
|
|
+ raise primitive_functions.PrimitiveFinished(result)
|
|
|
|
|
|
instruction_analyzers = {
|
|
|
'if' : analyze_if,
|