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

[fix] Output linear return values in order #41

Merged
merged 1 commit into from
Oct 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
9 changes: 5 additions & 4 deletions guppy/cfg/cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@
NestedFunctionDef,
BBStatement,
)
from guppy.compiler_base import VarMap, DFContainer, Variable, Globals
from guppy.compiler_base import VarMap, DFContainer, Variable, Globals, is_return_var
from guppy.error import InternalGuppyError, GuppyError, GuppyTypeError
from guppy.ast_util import AstVisitor, line_col, set_location_from
from guppy.expression import ExpressionCompiler
Expand Down Expand Up @@ -234,15 +234,16 @@ def _compile_bb(
# We put all non-linear variables into the branch predicate and all
# linear variables in the normal output (since they are shared between
# all successors). This is in line with the definition of `<` on
# variables which puts linear variables at the end.
# variables which puts linear variables at the end. The only exception
# are return vars which must be outputted in order.
branch_port = self._choose_vars_for_pred(
graph=graph,
pred=branch_port,
output_vars=[
sorted(
x
for x in self.live_before[succ]
if x in dfg and not dfg[x].ty.linear
if x in dfg and (not dfg[x].ty.linear or is_return_var(x))
)
for succ in bb.successors
],
Expand All @@ -253,7 +254,7 @@ def _compile_bb(
# We can look at `successors[0]` here since all successors must have
# the same `live_before` linear variables
for x in self.live_before[bb.successors[0]]
if x in dfg and dfg[x].ty.linear
if x in dfg and dfg[x].ty.linear and not is_return_var(x)
)

graph.add_output(
Expand Down
10 changes: 9 additions & 1 deletion guppy/compiler_base.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,12 @@ def __lt__(self, other: Any) -> bool:
# We define an ordering on variables that is used to determine in which order
# they are outputted from basic blocks. We need to output linear variables at
# the end, so we do a lexicographic ordering of linearity and name, exploiting
# the fact that `False < True` in Python.
# the fact that `False < True` in Python. The only exception are return vars
# which must be outputted in order.
if not isinstance(other, Variable):
return NotImplemented
if is_return_var(self.name) and is_return_var(other.name):
return self.name < other.name
return (self.ty.linear, self.name) < (other.ty.linear, other.name)


Expand Down Expand Up @@ -241,3 +244,8 @@ def return_var(n: int) -> str:
e1 ; %ret2 = e2`. This way, we can reuse our existing mechanism for passing of live
variables between basic blocks."""
return f"%ret{n}"


def is_return_var(x: str) -> bool:
"""Checks whether the given name is a dummy return variable."""
return x.startswith("%ret")
12 changes: 12 additions & 0 deletions tests/integration/test_linear.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,18 @@ def test(q: Qubit) -> Qubit:
validate(module.compile(True))


def test_linear_return_order(validate):
# See https://github.com/CQCL-DEV/guppy/issues/35
module = GuppyModule("test")
module.load(quantum)

@module
def test(q: Qubit) -> tuple[Qubit, bool]:
return measure(q)

validate(module.compile(True))


def test_interleave(validate):
module = GuppyModule("test")
module.load(quantum)
Expand Down