Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Tracing prototype #727

Draft
wants to merge 28 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
16ea171
feat: Tracing prototype
mark-koch Dec 17, 2024
3908a3c
Merge remote-tracking branch 'origin/main' into mk/tracing
mark-koch Jan 2, 2025
6bc5890
Fix mypy issues
mark-koch Jan 6, 2025
dff8cd8
Don't retrace functions on call
mark-koch Jan 6, 2025
c64823d
Fix demo notebook kernel
mark-koch Jan 6, 2025
34b0444
Fix lint
mark-koch Jan 6, 2025
313c9cf
Rename traced to comptime
mark-koch Jan 6, 2025
b52522e
Add missing dunder methods
mark-koch Jan 15, 2025
f814a79
Also try reverse dunder methods
mark-koch Jan 15, 2025
8810c6f
Remove unnecessary repack
mark-koch Jan 15, 2025
13fa209
Fix dunders and rename
mark-koch Jan 15, 2025
b52a7a9
Support builtins float, int, and len
mark-koch Jan 15, 2025
7896297
Merge remote-tracking branch 'origin/main' into mk/tracing
mark-koch Feb 4, 2025
3dd1bd2
Add basic tests
mark-koch Feb 4, 2025
a99b93b
Add arithmetic tests
mark-koch Feb 4, 2025
f8965c2
Check that called function is available in the current module
mark-koch Feb 4, 2025
9b2d0ea
Support golden tests with tracebacks
mark-koch Feb 4, 2025
0fdb1cf
Add some golden tests
mark-koch Feb 4, 2025
7a7b014
Remove bad test
mark-koch Feb 4, 2025
3701b7e
Add __init__.py
mark-koch Feb 4, 2025
af05e98
Improve dunder checks and errors
mark-koch Feb 4, 2025
674cee1
Turn wrong module test into error test
mark-koch Feb 4, 2025
b053322
Ruff
mark-koch Feb 4, 2025
1390562
Check for callable
mark-koch Feb 4, 2025
a43a138
Make golden tests version sensitive
mark-koch Feb 4, 2025
c3b9d2c
Fix mypy
mark-koch Feb 4, 2025
99b05b9
Allow runtime array construction and mutation
mark-koch Feb 4, 2025
b2bd5a2
Support structs
mark-koch Feb 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
528 changes: 528 additions & 0 deletions examples/tracing.ipynb

Large diffs are not rendered by default.

59 changes: 46 additions & 13 deletions execute_llvm/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ use hugr::llvm::CodegenExtsBuilder;
use hugr::package::Package;
use hugr::Hugr;
use hugr::{self, ops, std_extensions, HugrView};
use inkwell::types::BasicType;
use inkwell::values::BasicMetadataValueEnum;
use inkwell::{context::Context, module::Module, values::GenericValue};
use pyo3::exceptions::PyValueError;
use pyo3::prelude::*;
Expand Down Expand Up @@ -79,9 +81,11 @@ fn compile_module<'a>(
Ok(emitter.finish())
}

fn run_function<T>(
fn run_function<T: Clone>(
hugr_json: &str,
fn_name: &str,
args: &[T],
encode_arg: impl Fn(&Context, T) -> BasicMetadataValueEnum,
parse_result: impl FnOnce(&Context, GenericValue) -> PyResult<T>,
) -> PyResult<T> {
let mut hugr = parse_hugr(hugr_json)?;
Expand All @@ -98,10 +102,29 @@ fn run_function<T>(
.get_function(&mangled_name)
.ok_or(pyerr!("Couldn't find function {} in module", mangled_name))?;

// Build a new function that calls the target function with the provided arguments.
// Calling `ExecutionEngine::run_function` with arguments directly always segfaults for some
// reason...
let main = module.add_function(
"__main__",
fv.get_type().get_return_type().unwrap().fn_type(&[], false),
None,
);
let bb = ctx.append_basic_block(main, "");
let builder = ctx.create_builder();
builder.position_at_end(bb);
let args: Vec<_> = args.iter().map(|a| encode_arg(&ctx, a.clone())).collect();
let res = builder
.build_call(fv, &args, "")
.unwrap()
.try_as_basic_value()
.unwrap_left();
builder.build_return(Some(&res)).unwrap();

let ee = module
.create_execution_engine()
.map_err(|_| pyerr!("Failed to create execution engine"))?;
let llvm_result = unsafe { ee.run_function(fv, &[]) };
let llvm_result = unsafe { ee.run_function(main, &[]) };
parse_result(&ctx, llvm_result)
}

Expand All @@ -124,19 +147,29 @@ mod execute_llvm {
}

#[pyfunction]
fn run_int_function(hugr_json: &str, fn_name: &str) -> PyResult<i64> {
run_function::<i64>(hugr_json, fn_name, |_, llvm_val| {
// GenericVal is 64 bits wide
let int_with_sign = llvm_val.as_int(true);
let signed_int = int_with_sign as i64;
Ok(signed_int)
})
fn run_int_function(hugr_json: &str, fn_name: &str, args: Vec<i64>) -> PyResult<i64> {
run_function::<i64>(
hugr_json,
fn_name,
&args,
|ctx, i| ctx.i64_type().const_int(i as u64, true).into(),
|_, llvm_val| {
// GenericVal is 64 bits wide
let int_with_sign = llvm_val.as_int(true);
let signed_int = int_with_sign as i64;
Ok(signed_int)
},
)
}

#[pyfunction]
fn run_float_function(hugr_json: &str, fn_name: &str) -> PyResult<f64> {
run_function::<f64>(hugr_json, fn_name, |ctx, llvm_val| {
Ok(llvm_val.as_float(&ctx.f64_type()))
})
fn run_float_function(hugr_json: &str, fn_name: &str, args: Vec<f64>) -> PyResult<f64> {
run_function::<f64>(
hugr_json,
fn_name,
&args,
|ctx, f| ctx.f64_type().const_float(f).into(),
|ctx, llvm_val| Ok(llvm_val.as_float(&ctx.f64_type())),
)
}
}
4 changes: 2 additions & 2 deletions guppylang/checker/expr_checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1170,7 +1170,7 @@ def eval_py_expr(node: PyExpr, ctx: Context) -> Any:


def python_value_to_guppy_type(
v: Any, node: ast.expr, globals: Globals, type_hint: Type | None = None
v: Any, node: ast.AST, globals: Globals, type_hint: Type | None = None
) -> Type | None:
"""Turns a primitive Python value into a Guppy type.

Expand Down Expand Up @@ -1213,7 +1213,7 @@ def python_value_to_guppy_type(


def _python_list_to_guppy_type(
vs: list[Any], node: ast.expr, globals: Globals, type_hint: Type | None
vs: list[Any], node: ast.AST, globals: Globals, type_hint: Type | None
) -> OpaqueType | None:
"""Turns a Python list into a Guppy type.

Expand Down
Loading
Loading