-
Notifications
You must be signed in to change notification settings - Fork 80
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
backend: (csl) printing for functions, tasks and layout related things #2647
Conversation
Extracted printing logic for functions and tasks into one function. If a task can be immediately bound (i.e. it has an ID attribute), it will be. Also added printing for csl.call
This part operates on the program module and prints `@export_symbol`.
This also provides the second half of the symbol exporting logic (i.e. `@export_name` in the layout file).
Not all of these ops and types are implemented in the current printer, but this tests for everything the old branch implemented.
Also test for control tasks
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## main #2647 +/- ##
==========================================
+ Coverage 89.60% 89.68% +0.07%
==========================================
Files 360 361 +1
Lines 46172 46319 +147
Branches 6974 7012 +38
==========================================
+ Hits 41373 41540 +167
+ Misses 3725 3709 -16
+ Partials 1074 1070 -4 ☔ View full report in Codecov by Sentry. |
xdsl/backend/csl/print_csl.py
Outdated
@contextmanager | ||
def _in_block(self, block_name: str): | ||
self.print(f"{block_name} {{") | ||
old_prefix = self._prefix | ||
self._prefix += self._INDENT | ||
yield | ||
self._prefix = old_prefix | ||
self.print("}") | ||
pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this replace the previous descend
method?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not really, this just wraps a set of prints in <block_name> { ... }
. I could combine it with descend, but it's more for cases where we don't have an MLIR Block
and need to wrap something in braces.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I see it only being used for comptime regions, if that is the case, maybe don't need a form this generic? Just some food for thought.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's also used for layout
, though I can rewrite that as descend
, since layout does have an MLIR Block
, then make _in_block
_in_comptime
instead, since there are no other CSL block types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically, descend can be used to replace all uses of _in_block
, but this way felt cleaner, since it's always the same pattern:
<block-name> {
<statements>
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would your thoughts be on:
with self._in_block("comptime") as in_comptime:
in_comptime.print(f"@export_symbol({export_val}, {q_name});")
Then we can reuse descend
in _in_block
and avoid repetition there?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe we can instead replace descend with this instead then? I also feel that the context manager "feels" nicer, I would just argue that we should focus on one method for now.
xdsl/backend/csl/print_csl.py
Outdated
def _task_or_fn( | ||
self, introducer: str, name: StringAttr, bdy: Region, ftyp: FunctionType | ||
): | ||
args = ", ".join( | ||
f"{self._get_variable_name_for(arg)} : {self.mlir_type_to_csl_type(arg.type)}" | ||
for arg in bdy.block.args | ||
) | ||
ret = ( | ||
"void" | ||
if len(ftyp.outputs) == 0 | ||
else self.mlir_type_to_csl_type(ftyp.outputs.data[0]) | ||
) | ||
self.print(f"\n{introducer} {name.data}({args}) {ret} {{") | ||
self.descend().print_block(bdy.block) | ||
self.print("}") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would really like to have all functions that print prefixed with print_
xdsl/backend/csl/print_csl.py
Outdated
def _bind_task(self, name: str, kind: csl.TaskKind, id: csl.ColorIdAttr | None): | ||
if id is None: | ||
return | ||
with self._in_block("comptime"): | ||
self.print( | ||
f"@bind_{kind.value}_task({name}, @get_{kind.value}_task_id({self._wrapp_task_id(kind, id.value.data)}));" | ||
) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here, something like print_task_bind
xdsl/backend/csl/print_csl.py
Outdated
def _export_sym_constness(self, ty: FunctionType | csl.PtrType): | ||
if isinstance(ty, FunctionType): | ||
return None | ||
match ty.constness.data: | ||
case csl.PtrConst.VAR: | ||
return True | ||
case csl.PtrConst.CONST: | ||
return False | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand what this function does. Type annotations and docstrings would go a long way in making this more reviewable!
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When exporting symbols we have to specify if they are host-writable, except for functions, where it's a compile error to do so.
Will add a docstring and return type
xdsl/backend/csl/print_csl.py
Outdated
def _task_or_fn( | ||
self, introducer: str, name: StringAttr, bdy: Region, ftyp: FunctionType | ||
): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The introducer
could benefit from a rename and better type annotation (e.g. kind: Literal['task', 'fn']
)
xdsl/backend/csl/print_csl.py
Outdated
) | ||
|
||
|
||
def _get_layout_program(ops: BlockOps) -> tuple[csl.CslModuleOp, csl.CslModuleOp]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think it'd be more appropriate to pass the module here instead of the iterable of it's ops?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, docstrings!
@AntonLydike for the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is overall a pretty good first printer PR, although I would really really like to see more docstrings here!
I think they can easily be private as well! |
Not a list of it's ops
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Much better already!
xdsl/backend/csl/print_csl.py
Outdated
To be used in a `with` statement. | ||
Surrounds everything in the `with` with curly braces and . | ||
|
||
This is used instead of descend when |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
premature end of docstring, I think
xdsl/backend/csl/print_csl.py
Outdated
self, introducer: str, name: StringAttr, bdy: Region, ftyp: FunctionType | ||
def _print_task_or_fn( | ||
self, | ||
kind: Literal["fn"] | Literal["task"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can be simplified to Literal["fn", "task"]
xdsl/backend/csl/print_csl.py
Outdated
self.descend().print_block(bdy.block) | ||
self.print("}") | ||
|
||
def _wrapp_task_id(self, kind: csl.TaskKind, id: int) -> str: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: typo - should be wrap_task_id
for mod in prog.body.block.ops: | ||
assert isinstance(mod, csl.CslModuleOp) | ||
ctx.print_block(mod.body.block) | ||
layout, program = _get_layout_program(prog) | ||
ctx.print_block(program.body.block) | ||
ctx.print(ctx.DIVIDER) | ||
ctx.print_block(layout.body.block) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like the previous approach more of iterating over the modules, I feel this provides more flexibility for e.g. multiple programs or multiple layouts. This feels overly restrictive
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We have to print program first as that's when we collect symbols to be exported.
We can allow for multiple programs, but there still needs to be some logic to make sure they all get processed before the one layout.
case anyop: | ||
self.print(f"unknown op {anyop}", prefix="//") | ||
|
||
def descend(self) -> CslPrintContext: | ||
@contextmanager | ||
def descend(self, block_start: str = ""): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: you can add a type annotation here so that we know the type of the context manager:
from typing import ContextManager
# ...
@contextmanager
def descend(self, block_start: str = "") -> ContextManager[CslPrintContext]:
....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm curious whether this will work, I would have expected it to rather be -> Iterator[CslPrintContext]
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
iirc pyright (at least when I tested it) were happy with both, but I find ContextManager
to be the most correct imo
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When I try ContextManager[CslPrintContext]
, pyright produces all sorts of errors. ruff also complains that typing.ContextManager
is deprecated in favor of AbstractContextManager
, AbstractContextManager[CslPrintContext]
causes all the same errors, since it's not compatible with Generator
.
Iterator[CslPrintContext]
works, as does Generator[CslPrintContext, None, None]
, but I think both of these make the function signature more confusing. Personally, I would leave the return type auto-deduced, and rely on the docstring
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, the type annotation is for the function passed into the decorator, so ContextManager
is incorrect
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think this is in a good-to-go state now!
I forgot to remove the old |
Printing for:
csl.call
csl.task
csl.func
csl.task
csl.export
csl.layout
Also introduces a divider between the program and layout, for ease of filechecking and splitting