/parakeet/frontend/run_function.py

https://gitlab.com/tlevine/parakeet · Python · 135 lines · 93 code · 4 blank · 38 comment · 8 complexity · 02d4e1ea5a919d1d1cef4616a70e618a MD5 · raw file

  1. from .. import config, type_inference
  2. from ..analysis import contains_loops
  3. from ..ndtypes import type_conv, Type
  4. from ..syntax import UntypedFn, TypedFn, ActualArgs
  5. from ..transforms import pipeline
  6. def prepare_args(fn, args, kwargs):
  7. """
  8. Fetch the function's nonlocals and return an ActualArgs object of both the arg
  9. values and their types
  10. """
  11. assert not isinstance(fn, TypedFn), "[prepare_args] Only works for untyped functions"
  12. if not isinstance(fn, UntypedFn):
  13. import ast_conversion
  14. fn = ast_conversion.translate_function_value(fn)
  15. nonlocals = list(fn.python_nonlocals())
  16. arg_values = ActualArgs(nonlocals + list(args), kwargs)
  17. # get types of all inputs
  18. def _typeof(arg):
  19. if hasattr(arg, 'type') and isinstance(arg.type, Type):
  20. return arg.type
  21. else:
  22. return type_conv.typeof(arg)
  23. arg_types = arg_values.transform(_typeof)
  24. return arg_values, arg_types
  25. def specialize(untyped, args, kwargs = {}, optimize = True):
  26. """
  27. Translate, specialize and begin to optimize the given function for the types
  28. of the supplies arguments.
  29. Return the untyped and typed representations, along with all the
  30. arguments in a linear order.
  31. """
  32. if not isinstance(untyped, UntypedFn):
  33. import ast_conversion
  34. untyped = ast_conversion.translate_function_value(untyped)
  35. arg_values, arg_types = prepare_args(untyped, args, kwargs)
  36. # convert the awkward mix of positional, named, and starargs
  37. # into a positional sequence of arguments
  38. linear_args = untyped.args.linearize_without_defaults(arg_values)
  39. # propagate types through function representation and all
  40. # other functions it calls
  41. typed_fn = type_inference.specialize(untyped, arg_types)
  42. if optimize:
  43. from .. transforms.pipeline import normalize
  44. # apply high level optimizations
  45. typed_fn = normalize.apply(typed_fn)
  46. return typed_fn, linear_args
  47. def run_typed_fn(fn, args, backend = None):
  48. assert isinstance(fn, TypedFn)
  49. actual_types = tuple(type_conv.typeof(arg) for arg in args)
  50. expected_types = fn.input_types
  51. assert actual_types == expected_types, \
  52. "Arg type mismatch, expected %s but got %s" % \
  53. (expected_types, actual_types)
  54. if backend is None:
  55. backend = config.backend
  56. if backend == 'c':
  57. from .. import c_backend
  58. return c_backend.run(fn, args)
  59. elif backend == 'openmp':
  60. from .. import openmp_backend
  61. return openmp_backend.run(fn, args)
  62. elif backend == 'cuda':
  63. from .. import cuda_backend
  64. return cuda_backend.run(fn, args)
  65. elif backend == 'llvm':
  66. from ..llvm_backend.llvm_context import global_context
  67. from ..llvm_backend import generic_value_to_python
  68. from ..llvm_backend import ctypes_to_generic_value, compile_fn
  69. lowered_fn = pipeline.lowering.apply(fn)
  70. llvm_fn = compile_fn(lowered_fn).llvm_fn
  71. ctypes_inputs = [t.from_python(v)
  72. for (v,t)
  73. in zip(args, expected_types)]
  74. gv_inputs = [ctypes_to_generic_value(cv, t)
  75. for (cv,t)
  76. in zip(ctypes_inputs, expected_types)]
  77. exec_engine = global_context.exec_engine
  78. gv_return = exec_engine.run_function(llvm_fn, gv_inputs)
  79. return generic_value_to_python(gv_return, fn.return_type)
  80. elif backend == "interp":
  81. from .. import interp
  82. fn = pipeline.loopify(fn)
  83. return interp.eval_fn(fn, args)
  84. else:
  85. assert False, "Unknown backend %s" % backend
  86. def run_untyped_fn(fn, args, kwargs = None, backend = None):
  87. assert isinstance(fn, UntypedFn)
  88. if kwargs is None:
  89. kwargs = {}
  90. typed_fn, linear_args = specialize(fn, args, kwargs)
  91. return run_typed_fn(typed_fn, linear_args, backend)
  92. def run_python_ast(fn_name, fn_args, fn_body, globals_dict,
  93. arg_values, kwarg_values = None, backend = None):
  94. """
  95. Instead of giving Parakeet a function to parse, you can construct a Python
  96. AST yourself and then have that converted into a Typed Parakeet function
  97. """
  98. import ast_conversion
  99. untyped = ast_conversion.translate_function_ast(fn_name, fn_args, fn_body, globals_dict)
  100. return run_untyped_fn(untyped, arg_values, kwarg_values, backend)
  101. def run_python_fn(fn, args, kwargs = None, backend = None):
  102. """
  103. Given a python function, run it in Parakeet on the supplied args
  104. """
  105. import ast_conversion
  106. # translate from the Python AST to Parakeet's untyped format
  107. untyped = ast_conversion.translate_function_value(fn)
  108. return run_untyped_fn(untyped, args, kwargs, backend)