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: Only lower definitions to Hugr if they are used #496

Merged
merged 35 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 34 commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
3c3f157
feat!: Support implicit modules for all decorators and turn builtins …
mark-koch Sep 11, 2024
fcf6984
Lints
mark-koch Sep 11, 2024
359c1fc
Fix test
mark-koch Sep 11, 2024
2b21a44
Fix more tests
mark-koch Sep 11, 2024
d25dab1
Fix test
mark-koch Sep 12, 2024
6f6a564
Merge remote-tracking branch 'origin/main' into feat/implicit-decorators
mark-koch Sep 12, 2024
faa5b64
feat!: Add functions to quantum module and make quantum_functional in…
mark-koch Sep 13, 2024
d99d694
Fix tket tests
mark-koch Sep 13, 2024
f5cff19
Merge remote-tracking branch 'origin/main' into feat/quantum-module
mark-koch Sep 13, 2024
6d869e4
Merge remote-tracking branch 'origin/feat/quantum-module' into feat/i…
mark-koch Sep 13, 2024
37162f9
Fix tests
mark-koch Sep 13, 2024
9287b39
Fmt
mark-koch Sep 13, 2024
f24183d
Fix test
mark-koch Sep 13, 2024
f9aaaa9
fix: Fix implicit imports in notebooks
mark-koch Sep 13, 2024
b65f837
feat: Only lower definitions to Hugr if they are used
mark-koch Sep 13, 2024
133888f
tweak comment
acl-cqc Sep 16, 2024
3f04c01
quantum.py import only no_type_check from typing
acl-cqc Sep 16, 2024
fc29e84
fix: Fix implicit imports in notebooks (#495)
mark-koch Sep 16, 2024
2f70db7
Merge remote-tracking branch 'origin/main' into HEAD
acl-cqc Sep 16, 2024
17b5647
Merge 'origin/main' including 'feat/quantum-module' into HEAD
acl-cqc Sep 16, 2024
d4532ac
Add @overloads to help document _with_optional_module; use Decorator …
acl-cqc Sep 16, 2024
e3c4453
fix overloads, oops, and type-ignore, heh
acl-cqc Sep 16, 2024
15e5c48
Pull stuff out of loop in _get_python_caller
acl-cqc Sep 16, 2024
bafadfe
assert discarded buffer is empty
acl-cqc Sep 16, 2024
8f75828
make assert mypy-ok
acl-cqc Sep 16, 2024
6265442
Merge commit 'fc29e84070c2b6e01d76eada14bd41f581dae483' into fix/note…
acl-cqc Sep 16, 2024
a2579a2
Merge remote-tracking branch 'origin/feat/implicit-decorators' into f…
acl-cqc Sep 16, 2024
9944f07
Merge commit 'cc8a424ad9a8b8c3c5a3b5cc700ccdb7a5ff8fa9' into fix/note…
acl-cqc Sep 16, 2024
51e7f9b
Merge branch 'fix/notebook-imports' into feat/lower-used
acl-cqc Sep 16, 2024
c2b7489
Remove required by requesting compilation
acl-cqc Sep 16, 2024
860c552
comment re. adding to worklist
acl-cqc Sep 16, 2024
a0ce98c
fmt
acl-cqc Sep 16, 2024
d18b805
rm _compile_defs
acl-cqc Sep 16, 2024
a9ca64e
remove unused Definition.compile
doug-q Sep 17, 2024
232571c
lint
doug-q Sep 17, 2024
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
41 changes: 38 additions & 3 deletions guppylang/compiler/core.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,52 @@
from typing import cast

from hugr import Wire, ops
from hugr.build.dfg import DP, DfBase
from hugr.build.dfg import DP, DefinitionBuilder, DfBase

from guppylang.checker.core import FieldAccess, Place, PlaceId, Variable
from guppylang.definition.common import CompiledDef, DefId
from guppylang.definition.common import CheckedDef, CompilableDef, CompiledDef, DefId
from guppylang.error import InternalGuppyError
from guppylang.tys.ty import StructType

CompiledGlobals = dict[DefId, CompiledDef]
CompiledLocals = dict[PlaceId, Wire]


class CompiledGlobals:
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should probably rename this, considering the class does way more than just holding the globals. See #497

"""Compilation context containing all available definitions.

Maintains a `worklist` of definitions which have been used by other compiled code
(i.e. `compile_outer` has been called) but have not yet been compiled/lowered
themselves (i.e. `compile_inner` has not yet been called).
"""

module: DefinitionBuilder[ops.Module]
checked: dict[DefId, CheckedDef]
compiled: dict[DefId, CompiledDef]
worklist: set[DefId]

def __init__(
self,
checked: dict[DefId, CheckedDef],
module: DefinitionBuilder[ops.Module],
) -> None:
self.module = module
self.checked = checked
self.worklist = set()
self.compiled = {}

def __getitem__(self, def_id: DefId) -> CompiledDef:
if def_id not in self.compiled:
defn = self.checked[def_id]
self.compiled[def_id] = self._compile(defn)
self.worklist.add(def_id)
return self.compiled[def_id]

def _compile(self, defn: CheckedDef) -> CompiledDef:
if isinstance(defn, CompilableDef):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For another PR, I reckon we could probably get rid of CompilableDef by giving CheckedDefs an implementation of compile_outer that just returns self

return defn.compile_outer(self.module)
return defn


@dataclass
class DFContainer:
"""A dataflow graph under construction.
Expand Down
31 changes: 15 additions & 16 deletions guppylang/compiler/func_compiler.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,26 +62,25 @@ def compile_local_func_def(

call_args.append(partial)
func.cfg.input_tys.append(func.ty)

# Compile the CFG
cfg = compile_cfg(func.cfg, func_builder, call_args, globals)
func_builder.set_outputs(*cfg)
else:
# Otherwise, we treat the function like a normal global variable
from guppylang.definition.function import CompiledFunctionDef

globals = globals | {
func.def_id: CompiledFunctionDef(
func.def_id,
func.name,
func,
func.ty,
{},
None,
func.cfg,
func_builder,
)
}

# Compile the CFG
cfg = compile_cfg(func.cfg, func_builder, call_args, globals)
func_builder.set_outputs(*cfg)
globals.compiled[func.def_id] = CompiledFunctionDef(
func.def_id,
func.name,
func,
func.ty,
{},
None,
func.cfg,
func_builder,
)
globals.worklist.add(func.def_id) # will compile the CFG later

# Finally, load the function into the local data-flow graph
loaded = dfg.builder.load_function(func_builder, closure_ty)
Expand Down
1 change: 1 addition & 0 deletions guppylang/definition/common.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
from typing import TYPE_CHECKING, ClassVar, TypeAlias

from hugr.build.dfg import DefinitionBuilder, OpVar
from hugr.ext import Package

if TYPE_CHECKING:
from guppylang.checker.core import Globals
Expand Down
32 changes: 10 additions & 22 deletions guppylang/module.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,11 +11,10 @@

import guppylang.compiler.hugr_extension
from guppylang.checker.core import Globals, PyScope
from guppylang.compiler.core import CompiledGlobals
from guppylang.definition.common import (
CheckableDef,
CheckedDef,
CompilableDef,
CompiledDef,
DefId,
Definition,
ParsableDef,
Expand Down Expand Up @@ -264,18 +263,6 @@ def _check_defs(
for def_id, defn in parsed.items()
}

@staticmethod
def _compile_defs(
checked_defs: Mapping[DefId, CheckedDef], hugr_module: Module
) -> dict[DefId, CompiledDef]:
"""Helper method to compile checked definitions to Hugr."""
return {
def_id: defn.compile_outer(hugr_module)
if isinstance(defn, CompilableDef)
else defn
for def_id, defn in checked_defs.items()
}

def check(self) -> None:
"""Type-checks the module."""
if self.checked:
Expand Down Expand Up @@ -325,19 +312,20 @@ def compile(self) -> Package:
return self._compiled_hugr

self.check()
checked_defs = self._imported_checked_defs | self._checked_defs
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed def _compile_defs as the old code (removed here) was the only place calling it


# Prepare Hugr for this module
graph = Module()
graph.metadata["name"] = self.name

# Compile definitions to Hugr
compiled_defs = self._compile_defs(self._imported_checked_defs, graph)
compiled_defs |= self._compile_defs(self._checked_defs, graph)

# Finally, compile the definition contents to Hugr. For example, this compiles
# the bodies of functions.
for defn in compiled_defs.values():
defn.compile_inner(compiled_defs)
# Lower definitions to Hugr
required = set(self._checked_defs.keys())
ctx = CompiledGlobals(checked_defs, graph)
_request_compilation = [ctx[def_id] for def_id in required]
while ctx.worklist:
next_id = ctx.worklist.pop()
next_def = ctx[next_id]
next_def.compile_inner(ctx)

hugr = graph.hugr

Expand Down
6 changes: 1 addition & 5 deletions tests/integration/test_array.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import pytest
from hugr import ops
from hugr.std.int import IntVal

Expand All @@ -22,10 +21,7 @@ def main(xs: array[float, 42]) -> int:
validate(package)

hg = package.modules[0]
vals = [data.op for node, data in hg.nodes() if isinstance(data.op, ops.Const)]
if len(vals) > 1:
pytest.xfail(reason="hugr-includes-whole-stdlib")
[val] = vals
[val] = [data.op for node, data in hg.nodes() if isinstance(data.op, ops.Const)]
assert isinstance(val, ops.Const)
assert isinstance(val.val, IntVal)
assert val.val.v == 42
Expand Down
6 changes: 1 addition & 5 deletions tests/integration/test_basic.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import pytest
from hugr import ops

from guppylang.decorator import guppy
Expand Down Expand Up @@ -69,14 +68,11 @@ def test_func_def_name():
def func_name() -> None:
return

defs = [
[def_op] = [
data.op
for n, data in func_name.modules[0].nodes()
if isinstance(data.op, ops.FuncDefn)
]
if len(defs) > 1:
pytest.xfail(reason="hugr-includes-whole-stdlib")
[def_op] = defs
assert isinstance(def_op, ops.FuncDefn)
assert def_op.f_name == "func_name"

Expand Down
10 changes: 2 additions & 8 deletions tests/integration/test_extern.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,7 @@ def main() -> float:
validate(package)

hg = package.modules[0]
consts = [data.op for n, data in hg.nodes() if isinstance(data.op, ops.Const)]
if len(consts) > 1:
pytest.xfail(reason="hugr-includes-whole-stdlib")
[c] = consts
[c] = [data.op for n, data in hg.nodes() if isinstance(data.op, ops.Const)]
assert isinstance(c.val, val.Extension)
assert c.val.val["symbol"] == "ext"

Expand All @@ -39,10 +36,7 @@ def main() -> int:
validate(package)

hg = package.modules[0]
consts = [data.op for n, data in hg.nodes() if isinstance(data.op, ops.Const)]
if len(consts) > 1:
pytest.xfail(reason="hugr-includes-whole-stdlib")
[c] = consts
[c] = [data.op for n, data in hg.nodes() if isinstance(data.op, ops.Const)]
assert isinstance(c.val, val.Extension)
assert c.val.val["symbol"] == "foo"

Expand Down
Loading