Conversation
|
@burgholzer @denialhaag @DRovara I am pretty sure everyone of you has an opinion on how this getting started guide should look - and should not look. Hence, I kindly asked for a review from each one of you. I hope this is okay! |
📝 WalkthroughSummary by CodeRabbit
WalkthroughAdds a new MLIR "Getting Started" guide at Changes
Sequence Diagram(s)(omitted — changes are documentation additions, not new multi-component control flow) Estimated code review effort🎯 2 (Simple) | ⏱️ ~15 minutes Suggested labels
Suggested reviewers
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
📝 Coding Plan
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Thanks a lot for the work, @MatthiasReumann! All in all, it already looks pretty nice. I still tried to give some (maybe controversial) opinions, just to make sure everything is clear. None of them are really set in stone, just suggestions.
That being said though: I believe there is still some room for discussion when it comes to who the target audience should be for this "Getting Started Guide":
- Probably it shouldn't be quantum algorithm engineers who just want to compile their code. They don't care what happens in the background.
- Then, one would assume it's compiler developers. But why would compiler developers care about the
qcdialect (which the majority of this tutorial is about).
All in all, this brings me to the big question: Is it really the "correct" approach to give the getting started guide in terms of the QC dialect? People are never supposed to write MLIR code anyways - we will likely have some other front-end or DSL for that. So the only time when the code will use QC is during the translation process (and for the output, if the user does not compile down to QIR). The only advantage that QC has over QCO is that it is simpler, but it is weird to argue, for a tutorial "we won't explain the important thing because that is too complicated, so instead we explain the less important thing".
What are everyone else's thoughts on that?
docs/mlir/GettingStarted.md
Outdated
| @@ -0,0 +1,196 @@ | |||
| # Getting Started | |||
|
|
|||
| The Multi-Level Intermediate Representation (MLIR) project is an extensive framework to build compilers for heterogeneous hardware. The Munich Quantum Toolkit (MQT) utilizes MLIR for quantum compilation. That is, given an intermediate representation (IR) - a description - of a quantum computation, transform this representation to one that is efficiently executable on a target architecture. | |||
There was a problem hiding this comment.
Something about
That is, given an intermediate representation (IR) - a description - of a quantum computation, transform this representation to one that is efficiently executable on a target architecture.
Feels unclear to me. I wasn't immediately able to determine what exactly is being defined by this phrase, so it kind of kicked me out of the reading flow. Also, I'm not sure what I think about using "a quantum computation" as a technical term. It may not necessarily be wrong, but it feels like such an abstract concept in this context.
There was a problem hiding this comment.
Piggybacking off that comment, I believe the entire guide is still too compact and does not yet provide enough context for the reader to follow the narrative (which is not entirely clear as off now as well).
I'll expand a bit on this in a larger comment.
docs/mlir/GettingStarted.md
Outdated
|
|
||
| The short snippets above contain many fundamental concepts of MLIR. | ||
|
|
||
| - **Dialects**: A dialect groups operations (`alloc`, `dealloc`) and types (`qubit`) under a common namespace (`qc`). The example above combines built-in dialects with custom dialects. The [`builtin`](https://mlir.llvm.org/docs/Dialects/Builtin/) dialect provides the `module` operation (the `builtin.` is usually omitted) and the [`func`](https://mlir.llvm.org/docs/Dialects/Func/) dialect contains operations to define and call functions. The custom [`qc`](./QC.md) (_"quantum circuit"_) dialect is defined in the MQT and extends the built-in ones with the necessary functionality for quantum computing. |
There was a problem hiding this comment.
Not a strong opinion, but I wonder what others think about it:
The custom
qc("quantum circuit") dialect is defined in the MQT
"in the MQT" makes it feel a bit like we have this underlying MQT concept that defines stuff. But the MLIR code is only part of MQT Core and other MQT Repositories don't even use it really.
There was a problem hiding this comment.
The entire section in the docs is currently called "MLIR in the MQT", which is where I would assume this is coming from.
I would be in favor of changing that and, potentially, making this more of a "MQT Compiler Collection" section in the docs. And then explicitly refer to that name throughout the guide here.
docs/mlir/GettingStarted.md
Outdated
| The short snippets above contain many fundamental concepts of MLIR. | ||
|
|
||
| - **Dialects**: A dialect groups operations (`alloc`, `dealloc`) and types (`qubit`) under a common namespace (`qc`). The example above combines built-in dialects with custom dialects. The [`builtin`](https://mlir.llvm.org/docs/Dialects/Builtin/) dialect provides the `module` operation (the `builtin.` is usually omitted) and the [`func`](https://mlir.llvm.org/docs/Dialects/Func/) dialect contains operations to define and call functions. The custom [`qc`](./QC.md) (_"quantum circuit"_) dialect is defined in the MQT and extends the built-in ones with the necessary functionality for quantum computing. | ||
| - **SSA Values**: Operations can consume (_"operands"_) and produce (_"results"_) values. For instance, `qc.alloc` produces the value `q0`, while `qc.dealloc` consumes it. Furthermore, values in MLIR adhere to the static single-assignment (SSA) principle, where each variable is assigned exactly once and never reassigned. |
There was a problem hiding this comment.
It feels a bit weird that this point is named "SSA Values", but the explanation of what that means is just a secondary sentence "Furthermore, ..."
Conceptually, it is also a tiny bit confusing to start with "SSA Values" and then talk about consuming and producing values first. Maybe this can be fixed with simple reformulating?
docs/mlir/GettingStarted.md
Outdated
|
|
||
| - **Dialects**: A dialect groups operations (`alloc`, `dealloc`) and types (`qubit`) under a common namespace (`qc`). The example above combines built-in dialects with custom dialects. The [`builtin`](https://mlir.llvm.org/docs/Dialects/Builtin/) dialect provides the `module` operation (the `builtin.` is usually omitted) and the [`func`](https://mlir.llvm.org/docs/Dialects/Func/) dialect contains operations to define and call functions. The custom [`qc`](./QC.md) (_"quantum circuit"_) dialect is defined in the MQT and extends the built-in ones with the necessary functionality for quantum computing. | ||
| - **SSA Values**: Operations can consume (_"operands"_) and produce (_"results"_) values. For instance, `qc.alloc` produces the value `q0`, while `qc.dealloc` consumes it. Furthermore, values in MLIR adhere to the static single-assignment (SSA) principle, where each variable is assigned exactly once and never reassigned. | ||
| - **Regions and Blocks**: To represent hierarchical structures, operations may contain _"regions"_. A region consists of one to many _"blocks"_ which again contain operations. For instance, the `module` operation contains one region consisting of one block that contains the `func.func` operation. A block optionally requires a _"terminator"_ that defines the end of the current block. The `func.return` operation is such a terminator. The following figure visualizes the connection between operations, regions, and blocks succinctly. |
There was a problem hiding this comment.
I like the figure on Regions and Blocks, but I also don't think it is self-explanatory enough.
The section on Regions and Blocks does not really provide a distinction on what the two are so that a reader would feel confident in distinguishing the concepts. Also, I think we should take advantage of the intuitive "surrounded by curly braces" explanation, so that a reader would think "ah, so it's just like in [their favourite programming language]".
There was a problem hiding this comment.
I agree with Damian here, this could benefit from an updated picture as well as description that makes this a little more tangible.
docs/mlir/GettingStarted.md
Outdated
| :align: center | ||
| ``` | ||
|
|
||
| ### Gates And Measurements |
There was a problem hiding this comment.
This feels a bit abrupt. Maybe we should add a finishing sentence before going back to quantum concepts.
docs/mlir/GettingStarted.md
Outdated
|
|
||
| Internally, the optimizations are performed on the [`qco`](./QCO.md) (_"quantum circuit optimization"_) dialect. While the QC dialect is great for exchanging with other formats (such as OpenQASM), the QCO dialect is specifically designed for optimizations. | ||
|
|
||
| The following IR describes the construction of the first Bell state (and subsequent measurement) in the QCO dialect. Each unitary operation consumes and produces SSA values and each SSA value is used at most once (_"linear typing"_). Semantically, a qubit SSA value in the QCO dialect represents the state of the qubit (_"value semantics"_) whereas in the QC dialect a qubit SSA value references a qubit (_"reference semantics"_). |
There was a problem hiding this comment.
Each unitary operation consumes and produces SSA values
From a story-telling perspective, it feels a bit weird that this concept of consuming and producing SSA values was explained in the MLIR basics and then only came up here, so much later.
I don't know if there's a solution for that, though.
docs/mlir/GettingStarted.md
Outdated
|
|
||
| Internally, the optimizations are performed on the [`qco`](./QCO.md) (_"quantum circuit optimization"_) dialect. While the QC dialect is great for exchanging with other formats (such as OpenQASM), the QCO dialect is specifically designed for optimizations. | ||
|
|
||
| The following IR describes the construction of the first Bell state (and subsequent measurement) in the QCO dialect. Each unitary operation consumes and produces SSA values and each SSA value is used at most once (_"linear typing"_). Semantically, a qubit SSA value in the QCO dialect represents the state of the qubit (_"value semantics"_) whereas in the QC dialect a qubit SSA value references a qubit (_"reference semantics"_). |
There was a problem hiding this comment.
whereas in the QC dialect a qubit SSA value references a qubit ("reference semantics").
Feels a bit awkward. Maybe more like "is a pointer to a qubit" or "is a reference to a qubit", or maybe even a nod towards related things they already know ("just like Qubits in OpenQASM").
| } | ||
| } | ||
| ``` | ||
|
|
There was a problem hiding this comment.
To make it more intuitive, it would be cool to have an explanation of what changed.
- "All
qcogates now return the new state after applying the gate (%q0_1 = qco.h %q0_0)" - "The result of the operation inside the
ctrlmodifier needs to be passed on to the outer block, so we useqco.yield" - "
qco.measurenow returns two values: in addition to the classical measurement outcome, we also return the state after measurement`" - "
qco.deallocdoes not have to return a value, as the corresponding qubit is destroyed."
|
|
||
| The following figure illustrates the data-flow graph of the IR above. Thanks to the QCO dialect, the dependencies between operations become immediately apparent. For example, the controlled-X gate depends on the Hadamard gate because it consumes the `q0_1` qubit SSA value. Moreover, MLIR provides the necessary functionality to efficiently traverse the data-flow graph and thus the circuit. | ||
|
|
||
| ```{image} ../_static/qco-dataflow.svg |
There was a problem hiding this comment.
No strong opinion, just to bring it up: The MLIR code has no CX, just a CTRL(X). Should that be illustrated somehow in the figure?
Great figure, otherwise!
There was a problem hiding this comment.
Also love the figure. Could be even cooler when showing the control modifier, its block arguments, and the nested structure in general.
|
|
||
| Quantum IR in the QCO dialect can be quite complex. Writing it by hand is certainly an error-prone task. Fortunately, you don't have to. The compiler driver's interface accepts and produces quantum IR in the QC dialect. Under the hood, it transforms it to the QCO dialect, performs the optimizations, and transforms it back to the QC dialect. That's also why we refer to the QC dialect as interface dialect. The following figure depicts the interplay between the two dialects illustratively. | ||
|
|
||
| ```{image} ../_static/compilation-pipeline.svg |
There was a problem hiding this comment.
Should we add optional QIR output information here?
Some people may be specifically interested in compiling down to QIR. There should be some source that tells them how to call mqt-cc for that and that even tells them that we can do that to begin with. Might as well be here.
There was a problem hiding this comment.
I believe we should definitely talk about QIR here and also show an example of a QIR program. Then this can also be tied back to the other documentation section on the QIR runner. Best case, whatever is being produced here can be directly fed into the commands being shown there.
There was a problem hiding this comment.
Covered in the Emitting Quantum Intermediate Representation (QIR) subsection.
burgholzer
left a comment
There was a problem hiding this comment.
Thanks @MatthiasReumann for getting this started 😄
Great to see someone push this forward!
I now also gave this a thorough read.
I added some comments inline as well, but much more important than that, I would like to pick up on Damians points below.
That being said though: I believe there is still some room for discussion when it comes to who the target audience should be for this "Getting Started Guide":
Probably it shouldn't be quantum algorithm engineers who just want to compile their code. They don't care what happens in the background.
Then, one would assume it's compiler developers. But why would compiler developers care about the qc dialect (which the majority of this tutorial is about).
All in all, this brings me to the big question: Is it really the "correct" approach to give the getting started guide in terms of the QC dialect? People are never supposed to write MLIR code anyways - we will likely have some other front-end or DSL for that. So the only time when the code will use QC is during the translation process (and for the output, if the user does not compile down to QIR). The only advantage that QC has over QCO is that it is simpler, but it is weird to argue, for a tutorial "we won't explain the important thing because that is too complicated, so instead we explain the less important thing".What are everyone else's thoughts on that?
Currently, the guide feels very compact. It touches on some topics, but mostly briefly, and for the most part probably not exhaustively.
I said in one of the comments that it is "nicht fisch, nicht fleisch", and I think this also is what Damian is highlighting above. At the moment the guide itself isn't sure who it is written for.
I think this could easily be split into three parts:
- For the people knowing quantum that have never heard of MLIR; those should start with an MLIR section that explains the concepts; potentially referring back to concepts that people might know from SDKs like Qiskit or Pennylane, or from languages like OpenQASM. People knowing MLIR may skip this section.
- For the people that know classical compilers (and MLIR), but that don't know quantum too well. Those should start at a section that step by step explains quantum concepts, but tries to refer back to classical compiler and MLIR terminology wherever suitable. People knowing quantum may skip this section.
- For the people familiar with both (or that have read both previous sections). Those people, we should tell what exactly we are doing as part of the project here. This should explain the difference between the two dialects, the compilation flow, etc. This is the meat of the tutorial; the previous sections are kind of the background for the relevant crowd. Within this section, it may again be interesting to provide some anecdotes that people from one of the backgrounds would find helpful ("the program structure in QCO is very similar to DAG structures people may be familiar with from Qiskit" for example)
Overall, this should really have an educational character for people and leave as little up for imagination as possible (Damian already did a great job in the comments highlighting a couple of places where this might not yet be the case).
That's all I got for now. I hope this makes sense and helps to navigate this into the right direction. Despite the flood of comments, this is still a really great start! 🎉
There was a problem hiding this comment.
Love the figure (and the style in general).
One could extend this, by also showing the potential inputs and outputs (or formats) somehow. For now this would mean it can translate qc::QuantumComputation objects (which in turn can be constructed from OpenQASM 3 and Qiskit QuantumCircuits) and it can produce QIR.
Probably a figure that we will be extending in the future.
docs/mlir/GettingStarted.md
Outdated
| @@ -0,0 +1,196 @@ | |||
| # Getting Started | |||
|
|
|||
| The Multi-Level Intermediate Representation (MLIR) project is an extensive framework to build compilers for heterogeneous hardware. The Munich Quantum Toolkit (MQT) utilizes MLIR for quantum compilation. That is, given an intermediate representation (IR) - a description - of a quantum computation, transform this representation to one that is efficiently executable on a target architecture. | |||
There was a problem hiding this comment.
Piggybacking off that comment, I believe the entire guide is still too compact and does not yet provide enough context for the reader to follow the narrative (which is not entirely clear as off now as well).
I'll expand a bit on this in a larger comment.
docs/mlir/GettingStarted.md
Outdated
| module { | ||
| func.func @main() { | ||
| %q0 = qc.alloc : !qc.qubit | ||
| qc.dealloc %q0 : !qc.qubit | ||
|
|
||
| func.return | ||
| } | ||
| } |
There was a problem hiding this comment.
I believe this is not a faithful representation of a QC program that would be generated from the ProgramBuilder. It definitely lacks the entrypoint definition and I am not 100% sure whether the return statement is correct.
docs/mlir/GettingStarted.md
Outdated
| } | ||
| ``` | ||
|
|
||
| ### Interlude: MLIR Concepts |
There was a problem hiding this comment.
This is related to something that Damian brought up elsewhere: The current guide somewhat feels lacking in certain bits and pieces (in German one would say "nicht Fisch, nicht Fleisch"). It starts off with some quantum concepts, but not really to many for someone that wouldn't know much about quantum; then it switches to MLIR concepts, but directly ties these to quantum concepts, which might be confusing to the reader. I think we need to zoom out here a little bit, and find a good, coherent narrative.
docs/mlir/GettingStarted.md
Outdated
|
|
||
| The short snippets above contain many fundamental concepts of MLIR. | ||
|
|
||
| - **Dialects**: A dialect groups operations (`alloc`, `dealloc`) and types (`qubit`) under a common namespace (`qc`). The example above combines built-in dialects with custom dialects. The [`builtin`](https://mlir.llvm.org/docs/Dialects/Builtin/) dialect provides the `module` operation (the `builtin.` is usually omitted) and the [`func`](https://mlir.llvm.org/docs/Dialects/Func/) dialect contains operations to define and call functions. The custom [`qc`](./QC.md) (_"quantum circuit"_) dialect is defined in the MQT and extends the built-in ones with the necessary functionality for quantum computing. |
There was a problem hiding this comment.
The entire section in the docs is currently called "MLIR in the MQT", which is where I would assume this is coming from.
I would be in favor of changing that and, potentially, making this more of a "MQT Compiler Collection" section in the docs. And then explicitly refer to that name throughout the guide here.
docs/mlir/GettingStarted.md
Outdated
|
|
||
| - **Dialects**: A dialect groups operations (`alloc`, `dealloc`) and types (`qubit`) under a common namespace (`qc`). The example above combines built-in dialects with custom dialects. The [`builtin`](https://mlir.llvm.org/docs/Dialects/Builtin/) dialect provides the `module` operation (the `builtin.` is usually omitted) and the [`func`](https://mlir.llvm.org/docs/Dialects/Func/) dialect contains operations to define and call functions. The custom [`qc`](./QC.md) (_"quantum circuit"_) dialect is defined in the MQT and extends the built-in ones with the necessary functionality for quantum computing. | ||
| - **SSA Values**: Operations can consume (_"operands"_) and produce (_"results"_) values. For instance, `qc.alloc` produces the value `q0`, while `qc.dealloc` consumes it. Furthermore, values in MLIR adhere to the static single-assignment (SSA) principle, where each variable is assigned exactly once and never reassigned. | ||
| - **Regions and Blocks**: To represent hierarchical structures, operations may contain _"regions"_. A region consists of one to many _"blocks"_ which again contain operations. For instance, the `module` operation contains one region consisting of one block that contains the `func.func` operation. A block optionally requires a _"terminator"_ that defines the end of the current block. The `func.return` operation is such a terminator. The following figure visualizes the connection between operations, regions, and blocks succinctly. |
There was a problem hiding this comment.
I agree with Damian here, this could benefit from an updated picture as well as description that makes this a little more tangible.
docs/mlir/GettingStarted.md
Outdated
|
|
||
| Internally, the optimizations are performed on the [`qco`](./QCO.md) (_"quantum circuit optimization"_) dialect. While the QC dialect is great for exchanging with other formats (such as OpenQASM), the QCO dialect is specifically designed for optimizations. | ||
|
|
||
| The following IR describes the construction of the first Bell state (and subsequent measurement) in the QCO dialect. Each unitary operation consumes and produces SSA values and each SSA value is used at most once (_"linear typing"_). Semantically, a qubit SSA value in the QCO dialect represents the state of the qubit (_"value semantics"_) whereas in the QC dialect a qubit SSA value references a qubit (_"reference semantics"_). |
There was a problem hiding this comment.
| The following IR describes the construction of the first Bell state (and subsequent measurement) in the QCO dialect. Each unitary operation consumes and produces SSA values and each SSA value is used at most once (_"linear typing"_). Semantically, a qubit SSA value in the QCO dialect represents the state of the qubit (_"value semantics"_) whereas in the QC dialect a qubit SSA value references a qubit (_"reference semantics"_). | |
| The following IR describes the construction of the first Bell state (and subsequent measurement) in the QCO dialect. Each unitary operation consumes and produces SSA values and each SSA value is used exactly once (_"linear typing"_). Semantically, a qubit SSA value in the QCO dialect represents the state of the qubit (_"value semantics"_) whereas in the QC dialect a qubit SSA value references a qubit (_"reference semantics"_). |
Subtle, but important. Linear typing dictates that values are used exactly once.
|
|
||
| The following figure illustrates the data-flow graph of the IR above. Thanks to the QCO dialect, the dependencies between operations become immediately apparent. For example, the controlled-X gate depends on the Hadamard gate because it consumes the `q0_1` qubit SSA value. Moreover, MLIR provides the necessary functionality to efficiently traverse the data-flow graph and thus the circuit. | ||
|
|
||
| ```{image} ../_static/qco-dataflow.svg |
There was a problem hiding this comment.
Also love the figure. Could be even cooler when showing the control modifier, its block arguments, and the nested structure in general.
|
|
||
| Quantum IR in the QCO dialect can be quite complex. Writing it by hand is certainly an error-prone task. Fortunately, you don't have to. The compiler driver's interface accepts and produces quantum IR in the QC dialect. Under the hood, it transforms it to the QCO dialect, performs the optimizations, and transforms it back to the QC dialect. That's also why we refer to the QC dialect as interface dialect. The following figure depicts the interplay between the two dialects illustratively. | ||
|
|
||
| ```{image} ../_static/compilation-pipeline.svg |
There was a problem hiding this comment.
I believe we should definitely talk about QIR here and also show an example of a QIR program. Then this can also be tied back to the other documentation section on the QIR runner. Best case, whatever is being produced here can be directly fed into the commands being shown there.
docs/mlir/index.md
Outdated
| QC | ||
| QCO | ||
| Conversions | ||
| GettingStarted |
There was a problem hiding this comment.
I feel like this should be the first section in this chapter of the docs. In the end, it is about getting started, which should happen first I suppose.
Also, we may want to nest the other sections one level deeper under an "API" heading or similar.
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (1)
docs/mlir/GettingStarted.md (1)
83-89:⚠️ Potential issue | 🟠 MajorFill in the core tutorial sections before merge.
The two key subsections are empty (
The QC and QCO Dialects,Compilation Flow), so the guide currently misses the main learning path (QC vs QCO semantics and QC→QCO flow) promised by this PR and linked issue.✍️ Minimal structure to add now
### The QC and QCO Dialects +QC uses reference semantics and models qubits as references to allocated resources. +QCO uses value semantics with linear types, where each qubit SSA value is consumed exactly once. +Show one small side-by-side snippet (QC and QCO) for the same Bell-state step to make this concrete. ### Compilation Flow +The typical flow is: OpenQASM -> QC -> QCO -> (optional) QIR. +Add one command sequence with `mqt-cc` and briefly explain where optimizations happen. +Include one short note about current limitations (e.g., unsupported patterns), if applicable.Based on learnings from issue
#1452objectives, this guide is expected to explain QC vs QCO in detail and illustrate the QC → QCO transformation with a running example.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 83 - 89, The two subsections "The QC and QCO Dialects" and "Compilation Flow" in GettingStarted.md are empty; fill them with content that (1) defines QC and QCO semantics (key differences, example ops/constructs and when to use each) under the "The QC and QCO Dialects" header and (2) describes the QC→QCO transformation pipeline with a small running example showing input QC IR, the transformation steps (pass names or functions) and resulting QCO IR under "Compilation Flow"; reference the section titles "The QC and QCO Dialects" and "Compilation Flow" when adding content so the guide explains QC vs QCO and demonstrates the QC→QCO flow end-to-end as requested by the linked issue.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/mlir/GettingStarted.md`:
- Line 164: The "## Conclusion" heading in the GettingStarted.md document is
empty; either remove the heading or add a brief concluding paragraph summarizing
the guide. Locate the heading text "## Conclusion" and either delete that line
(and any trailing blank lines) or append 2–4 sentences that wrap up the
document’s key takeaways and next steps so the section is not left blank.
- Around line 30-33: Fix the wording in the MLIR intro: change "The core concept
in MLIR are _dialects_" to "The core concepts in MLIR are _dialects_"; change
"floating point" to "floating-point" (e.g., "integer and floating-point
operations"); and replace "which let's us define and call functions" with "which
lets us define and call functions" (remove the apostrophe). Keep references to
SCF, arith, and Func dialects intact.
---
Duplicate comments:
In `@docs/mlir/GettingStarted.md`:
- Around line 83-89: The two subsections "The QC and QCO Dialects" and
"Compilation Flow" in GettingStarted.md are empty; fill them with content that
(1) defines QC and QCO semantics (key differences, example ops/constructs and
when to use each) under the "The QC and QCO Dialects" header and (2) describes
the QC→QCO transformation pipeline with a small running example showing input QC
IR, the transformation steps (pass names or functions) and resulting QCO IR
under "Compilation Flow"; reference the section titles "The QC and QCO Dialects"
and "Compilation Flow" when adding content so the guide explains QC vs QCO and
demonstrates the QC→QCO flow end-to-end as requested by the linked issue.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 5455081e-a4a9-4d40-a96e-60c3468ccfde
⛔ Files ignored due to path filters (1)
docs/_static/mlir-regions-blocks-ops.svgis excluded by!**/*.svg
📒 Files selected for processing (2)
docs/mlir/GettingStarted.mddocs/mlir/index.md
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/mlir/GettingStarted.md`:
- Line 26: The headings "Quantum Computing" and "Compilation Flow" in
GettingStarted.md are empty placeholders; either remove these headings or add
brief, complete content under each (e.g., a short overview and links/examples)
to avoid interrupting the tutorial flow; update both occurrences (the heading at
line showing "Quantum Computing" and the other empty "Compilation Flow" heading
referenced at the other location) and ensure the added content matches the
surrounding style and links/refs elsewhere in the document.
- Around line 94-95: Several `{code-block}` directives contain a non-breaking
space between "}" and "mlir" (the sequence `{code-block} mlir`) which breaks
MyST/Sphinx parsing; locate each occurrence of the string `{code-block} mlir` in
GettingStarted.md (the blocks around the QC examples) and replace the
non-breaking space with a normal ASCII space so the directives read
`{code-block} mlir`; ensure you update all occurrences mentioned (the four
directive instances around the QC examples) and preserve the surrounding
backticks/Markdown fencing and code content.
- Around line 199-203: Add a short "Current limitations" subsection before the
"Examples Using the MQT Compiler Collection Tool" examples under the
"Compilation Flow" heading that clearly lists the QC→QCO and
multi-function/control-flow boundaries: mention limited support for multiple
functions in a single conversion, constraints around function-like and scf
regions, and known issues with container-typed qubit flows (e.g., lists/arrays
of qubits not fully supported); keep it concise, use the terms "QC→QCO",
"function-like", and "scf" so readers can correlate with code examples, and
place it immediately above the examples section.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 86caa472-2736-4f43-99b3-c860a750e36d
📒 Files selected for processing (1)
docs/mlir/GettingStarted.md
There was a problem hiding this comment.
Actionable comments posted: 1
♻️ Duplicate comments (5)
docs/mlir/GettingStarted.md (5)
274-274:⚠️ Potential issue | 🟠 MajorFill or remove the empty "Compilation Flow" subsection.
This subsection heading at line 274 is empty. It should either explain the compilation workflow (QC→QCO conversion, optimization passes, lowering to QIR) or be removed. Given that the Examples section immediately follows, a brief 2-3 paragraph overview of the compilation pipeline would provide valuable context before showing tool usage.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` at line 274, The "Compilation Flow" subsection heading is empty — either remove the heading or populate it with a brief 2–3 paragraph overview describing the pipeline: explain the QC → QCO conversion step, enumerate key optimization passes (e.g., simplification, gate fusion, resource/ancilla allocation), and describe the lowering stage to QIR including any backend/codegen considerations; update the subsection under the "Compilation Flow" heading so it sits before the Examples section and uses clear, concise sentences referencing the QC→QCO conversion, optimization passes, and lowering to QIR.
26-26:⚠️ Potential issue | 🟠 MajorFill or remove the empty "Quantum Computing" subsection.
The Fundamentals section (line 24) promises coverage for readers unfamiliar with quantum computing, but the "Quantum Computing" subsection at line 26 is empty. This leaves beginners without necessary context. Either add a brief (3-4 paragraph) introduction covering qubits, gates, superposition, entanglement, and measurement, or remove the heading and adjust the intro text to clarify that quantum computing background is assumed.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` at line 26, The "Quantum Computing" subsection heading is empty; either populate the "Quantum Computing" subsection with a brief 3–4 paragraph primer covering qubits, quantum gates, superposition, entanglement, and measurement (so readers unfamiliar with quantum concepts can follow the "Fundamentals" section), or remove the "Quantum Computing" heading and update the "Fundamentals" intro to clearly state that quantum computing background is assumed. Locate the heading "Quantum Computing" in GettingStarted.md and implement one of these two fixes, ensuring the added text is concise and aligns with surrounding tone and structure.
276-278:⚠️ Potential issue | 🟠 MajorDocument known multi-function and control-flow limitations.
The PR description notes that "attempts to implement multiple functions and function calling fail when converting QC → QCO." However, the guide does not document this or other known limitations. Add a "Current Limitations" subsection before the examples that clearly states:
- Multi-function modules with qubit-typed helper functions are not yet supported in QC→QCO conversion
- Function operations assume all-qubit or all-classical types (no mixed quantum/classical signatures)
scf.forcan handle qubit containers (memref/tensor), butscf.ifandscf.whileare restricted to scalar qubit types onlyThis will prevent confusion when readers attempt workflows beyond the single-function examples shown.
Based on learnings: QCToQCO conversion passes enforce specific constraints on func and scf operations that limit multi-function and container-typed qubit flows.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 276 - 278, Add a new "Current Limitations" subsection immediately before the "Examples Using the MQT Compiler Collection Tool" section that explicitly lists the known QC→QCO conversion constraints: state that multi-function modules with qubit-typed helper functions are not supported in QC→QCO conversion, that func operations assume homogeneous argument/result types (all-qubit or all-classical — no mixed quantum/classical signatures), and that scf.for supports qubit containers (memref/tensor) while scf.if and scf.while are limited to scalar qubit types only; reference these symbols (QC→QCO, func, scf.for, scf.if, scf.while) in the prose so readers can map limitations to the conversion checks mentioned in the PR.
32-32:⚠️ Potential issue | 🟡 MinorFix grammar and style issues in dialect introduction.
Three issues on this line:
- Subject-verb disagreement: "core concept...are" should be "core concepts...are"
- Missing hyphen in compound adjective: "floating point operations" should be "floating-point operations"
- Incorrect apostrophe: "which let's us" should be "which lets us"
📝 Proposed fix
-The core concept in MLIR are _dialects_. A dialect groups operations, types, and attributes under a common namespace. A single program may combine multiple dialects, which facilitates code reuse. For example, the structured control flow (SCF) dialect provides functionality for control flow constructs, while the arith dialect defines integer and floating point operations. Another essential dialect is the Func dialect, which let's us define and call functions. +The core concepts in MLIR are _dialects_. A dialect groups operations, types, and attributes under a common namespace. A single program may combine multiple dialects, which facilitates code reuse. For example, the structured control flow (SCF) dialect provides functionality for control-flow constructs, while the arith dialect defines integer and floating-point operations. Another essential dialect is the Func dialect, which lets us define and call functions.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` at line 32, Fix the sentence describing MLIR dialects: change "The core concept in MLIR are" to either "The core concepts in MLIR are" or "A core concept in MLIR is" for correct subject-verb agreement; add a hyphen to "floating point operations" -> "floating-point operations"; and replace the incorrect contraction "which let's us" with "which lets us". Update the line referencing MLIR dialects and examples (SCF, arith, Func) accordingly.
94-95:⚠️ Potential issue | 🔴 CriticalFix non-breaking spaces in
{code-block}directives.Lines 94, 118, 142, 170, and 204 contain non-breaking space characters (U+00A0) between
}andmlirin the code-block directives, which break MyST/Sphinx parsing. Replace these with regular ASCII spaces.Affected lines
- Line 94:
{code-block}(beforemlir)- Line 118:
{code-block}(beforemlir)- Line 142:
{code-block}(beforemlir)- Line 170:
{code-block}(beforemlir)- Line 204:
{code-block}(beforemlir)🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 94 - 95, Replace the non-breaking space (U+00A0) between the `{code-block}` token and the language specifier `mlir` with a normal ASCII space in the `{code-block}` directives; locate occurrences of the sequence "{code-block} mlir" (note the NBSP) and change them to "{code-block} mlir" so MyST/Sphinx parsing is restored.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/mlir/GettingStarted.md`:
- Line 351: The "## Conclusion" heading in GettingStarted.md is empty; either
remove the heading or add a 2–3 sentence summary that wraps up the guide (for
example mention foundation for using the MQT Compiler Collection, differences
between QC and QCO dialects, and emitting QIR for execution) so the document has
a proper closing; edit the "## Conclusion" section accordingly in
docs/mlir/GettingStarted.md.
---
Duplicate comments:
In `@docs/mlir/GettingStarted.md`:
- Line 274: The "Compilation Flow" subsection heading is empty — either remove
the heading or populate it with a brief 2–3 paragraph overview describing the
pipeline: explain the QC → QCO conversion step, enumerate key optimization
passes (e.g., simplification, gate fusion, resource/ancilla allocation), and
describe the lowering stage to QIR including any backend/codegen considerations;
update the subsection under the "Compilation Flow" heading so it sits before the
Examples section and uses clear, concise sentences referencing the QC→QCO
conversion, optimization passes, and lowering to QIR.
- Line 26: The "Quantum Computing" subsection heading is empty; either populate
the "Quantum Computing" subsection with a brief 3–4 paragraph primer covering
qubits, quantum gates, superposition, entanglement, and measurement (so readers
unfamiliar with quantum concepts can follow the "Fundamentals" section), or
remove the "Quantum Computing" heading and update the "Fundamentals" intro to
clearly state that quantum computing background is assumed. Locate the heading
"Quantum Computing" in GettingStarted.md and implement one of these two fixes,
ensuring the added text is concise and aligns with surrounding tone and
structure.
- Around line 276-278: Add a new "Current Limitations" subsection immediately
before the "Examples Using the MQT Compiler Collection Tool" section that
explicitly lists the known QC→QCO conversion constraints: state that
multi-function modules with qubit-typed helper functions are not supported in
QC→QCO conversion, that func operations assume homogeneous argument/result types
(all-qubit or all-classical — no mixed quantum/classical signatures), and that
scf.for supports qubit containers (memref/tensor) while scf.if and scf.while are
limited to scalar qubit types only; reference these symbols (QC→QCO, func,
scf.for, scf.if, scf.while) in the prose so readers can map limitations to the
conversion checks mentioned in the PR.
- Line 32: Fix the sentence describing MLIR dialects: change "The core concept
in MLIR are" to either "The core concepts in MLIR are" or "A core concept in
MLIR is" for correct subject-verb agreement; add a hyphen to "floating point
operations" -> "floating-point operations"; and replace the incorrect
contraction "which let's us" with "which lets us". Update the line referencing
MLIR dialects and examples (SCF, arith, Func) accordingly.
- Around line 94-95: Replace the non-breaking space (U+00A0) between the
`{code-block}` token and the language specifier `mlir` with a normal ASCII space
in the `{code-block}` directives; locate occurrences of the sequence
"{code-block} mlir" (note the NBSP) and change them to "{code-block} mlir" so
MyST/Sphinx parsing is restored.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: ae0ea925-ed00-426f-9add-7e1cd6ded496
📒 Files selected for processing (1)
docs/mlir/GettingStarted.md
There was a problem hiding this comment.
Actionable comments posted: 2
♻️ Duplicate comments (3)
docs/mlir/GettingStarted.md (3)
89-140: 🧹 Nitpick | 🔵 TrivialOptional: Consider adding brief explanations for type syntax and operands vs. attributes.
The MLIR fundamentals section introduces SSA values, types, operations, blocks, and regions effectively. However, as noted in past reviews, readers encountering quantum MLIR examples later may benefit from:
- A brief note on the
!dialect.typenametype syntax convention (e.g.,!qc.qubit,!qco.qubit)- A short distinction between operands (runtime values) and attributes (compile-time constants)
These could be added as 1-2 sentence clarifications in this section or deferred to the Quantum Dialects section where they first appear.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 89 - 140, Add a concise 1–2 sentence clarification in the MLIR fundamentals section (near the explanations of types and SSA values) that explains the MLIR custom type syntax using the form !dialect.typename (give examples like !qc.qubit and !qco.qubit) and briefly distinguish operands (runtime SSA values like %a, %b) from attributes (compile-time constants attached to ops); insert this either inline after the bullet about ": index and : i32" or as a short note before the quantum dialect examples so readers see the convention before encountering !qc.qubit and the use of operands vs. attributes.
440-440:⚠️ Potential issue | 🟡 MinorFill or remove the empty Conclusion heading.
The "## Conclusion" heading at line 440 has no content. This was flagged in a previous review and remains unresolved. Either:
Add a brief 2–3 sentence closing summary that wraps up the key takeaways (e.g., "You now have a foundation for using the MQT Compiler Collection to write, optimize, and transpile quantum programs using the QC and QCO dialects. The value semantics and linear typing in QCO enable powerful optimization passes, while the QC dialect provides a familiar interface for quantum circuit representation. For more details on specific dialect operations and advanced features, refer to the QC and QCO dialect documentation pages.")
Remove the heading entirely if the examples section serves as a natural conclusion
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` at line 440, The "## Conclusion" heading is empty; either add a brief 2–3 sentence closing summary under the "## Conclusion" heading that wraps up the key takeaways (suggested text: two sentences about having a foundation for using the MQT Compiler Collection, value of QCO semantics and QC dialect, and a pointer to the QC and QCO dialect pages) or delete the "## Conclusion" heading entirely if the examples already serve as the natural end; if you add the summary, include links to the QC and QCO docs (referenced as QC and QCO) to guide readers to more detail.
350-363: 🧹 Nitpick | 🔵 TrivialConsider documenting current compiler limitations for advanced use cases.
The Compilation Flow section provides a good high-level overview. However, as noted in a previous review comment, users attempting more complex workflows should be aware of current limitations. Consider adding a brief "Current Limitations" note or subsection that mentions:
- Function signatures: Multi-function programs with qubit-typed parameters have limited support in some conversion passes
- Control-flow constraints: While
scf.forsupports qubit containers (memref/tensor),scf.ifandscf.whileare currently restricted to scalar qubit types only in certain conversion contexts- QIR emission: The QIR conversion path currently assumes a single entry-point function with specific signature constraints
These caveats would help users understand the boundaries of the current implementation and avoid frustration when exploring beyond the documented examples. Based on learnings, the MLIR functionality is still under active development, so explicitly noting these as temporary limitations is appropriate.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 350 - 363, Add a brief "Current Limitations" subsection under the "Compilation Flow" heading that explicitly lists the known MLIR/compilation constraints so advanced users are aware: mention limited support for multi-function programs with qubit-typed parameters (function signature constraints), the control-flow restrictions where scf.for can handle qubit containers (memref/tensor) but scf.if and scf.while are currently limited to scalar qubit types in some conversion passes, and the QIR emission path assumption of a single entry-point with specific signature constraints; mark these as temporary/under-development and keep the note concise and linked to the Compilation Flow description.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@docs/mlir/GettingStarted.md`:
- Around line 7-19: Replace the `%` shell prompt tokens with `$` in the console
code blocks in GettingStarted.md so they match project documentation style:
change occurrences in the cmake/build example (the lines showing "cmake -Bbuild
\", "cd build && cmake --build . --target mqt-cc") and the verification command
("./mlir/tools/mqt-cc/mqt-cc --help") from `%` to `$`, and apply the same
`%`→`$` replacement to the other console blocks elsewhere in the file that
follow the same pattern.
- Around line 142-349: Add a new subsection after the Quantum Dialects section
that provides (1) an scf.for example showing loop-carried SSA qubit values with
qco.alloc/qco.yield to demonstrate linear typing across iterations (reference
scf.for, qco.yield, loop-carried entry-arguments), (2) an scf.if example that
conditionally applies gates based on a measurement result showing separate SSA
branches and how to merge results without re-using values (reference scf.if,
qco.measure, qco.yield), and (3) a multi-function example that defines a helper
function taking and returning qubits and shows a call site to illustrate
function parameter/return semantics under linear typing (reference the function
declaration/call symbols used in the doc); briefly annotate each example with
one sentence explaining how linear typing is preserved (use scf.yield and
explicit entry-arguments to avoid variable re-use).
---
Duplicate comments:
In `@docs/mlir/GettingStarted.md`:
- Around line 89-140: Add a concise 1–2 sentence clarification in the MLIR
fundamentals section (near the explanations of types and SSA values) that
explains the MLIR custom type syntax using the form !dialect.typename (give
examples like !qc.qubit and !qco.qubit) and briefly distinguish operands
(runtime SSA values like %a, %b) from attributes (compile-time constants
attached to ops); insert this either inline after the bullet about ": index and
: i32" or as a short note before the quantum dialect examples so readers see the
convention before encountering !qc.qubit and the use of operands vs. attributes.
- Line 440: The "## Conclusion" heading is empty; either add a brief 2–3
sentence closing summary under the "## Conclusion" heading that wraps up the key
takeaways (suggested text: two sentences about having a foundation for using the
MQT Compiler Collection, value of QCO semantics and QC dialect, and a pointer to
the QC and QCO dialect pages) or delete the "## Conclusion" heading entirely if
the examples already serve as the natural end; if you add the summary, include
links to the QC and QCO docs (referenced as QC and QCO) to guide readers to more
detail.
- Around line 350-363: Add a brief "Current Limitations" subsection under the
"Compilation Flow" heading that explicitly lists the known MLIR/compilation
constraints so advanced users are aware: mention limited support for
multi-function programs with qubit-typed parameters (function signature
constraints), the control-flow restrictions where scf.for can handle qubit
containers (memref/tensor) but scf.if and scf.while are currently limited to
scalar qubit types in some conversion passes, and the QIR emission path
assumption of a single entry-point with specific signature constraints; mark
these as temporary/under-development and keep the note concise and linked to the
Compilation Flow description.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: b13701dc-8795-46ac-a613-5b08981fc759
⛔ Files ignored due to path filters (2)
docs/_static/bell-circuit.svgis excluded by!**/*.svgdocs/_static/qco-dataflow.svgis excluded by!**/*.svg
📒 Files selected for processing (1)
docs/mlir/GettingStarted.md
| ```console | ||
| % cmake -Bbuild \ | ||
| -DMLIR_DIR=<path to MLIR> \ | ||
| -DLLVM_DIR=<path to LLVM> \ | ||
| -DCMAKE_BUILD_TYPE:STRING=Release \ | ||
| -DBUILD_MQT_CORE_MLIR=ON | ||
| % cd build && cmake --build . --target mqt-cc | ||
| ``` | ||
|
|
||
| You can verify your build by running the following command. If everything worked correctly, it should print an usage message. | ||
|
|
||
| ```console | ||
| % ./mlir/tools/mqt-cc/mqt-cc --help |
There was a problem hiding this comment.
🧹 Nitpick | 🔵 Trivial
Consider using $ prompt for consistency with project documentation style.
The console code blocks use % as the shell prompt. Based on learnings, MQT Core documentation conventionally uses $ prompt symbols in console code blocks (e.g., $ uv pip install ...). Consider updating to $ for consistency, unless % is intentionally used to indicate a different shell context.
📝 Suggested prompt update
```console
-% cmake -Bbuild \
+$ cmake -Bbuild \
-DMLIR_DIR=<path to MLIR> \
-DLLVM_DIR=<path to LLVM> \
-DCMAKE_BUILD_TYPE:STRING=Release \
-DBUILD_MQT_CORE_MLIR=ON
-% cd build && cmake --build . --target mqt-cc
+$ cd build && cmake --build . --target mqt-ccYou can verify your build by running the following command. If everything worked correctly, it should print an usage message.
-% ./mlir/tools/mqt-cc/mqt-cc --help
+$ ./mlir/tools/mqt-cc/mqt-cc --help
Apply the same replacement at lines 391, 429, and 435.
</details>
<details>
<summary>🤖 Prompt for AI Agents</summary>
Verify each finding against the current code and only fix it if needed.
In @docs/mlir/GettingStarted.md around lines 7 - 19, Replace the % shell
prompt tokens with $ in the console code blocks in GettingStarted.md so they
match project documentation style: change occurrences in the cmake/build example
(the lines showing "cmake -Bbuild ", "cd build && cmake --build . --target
mqt-cc") and the verification command ("./mlir/tools/mqt-cc/mqt-cc --help") from
% to $, and apply the same %→$ replacement to the other console blocks
elsewhere in the file that follow the same pattern.
</details>
<!-- fingerprinting:phantom:triton:puma -->
<!-- This is an auto-generated comment by CodeRabbit -->
| ## The MQT Compiler Collection | ||
|
|
||
| The MQT Compiler Collection provides tools to optimize and transpile quantum programs. This section outlines how we utilize the MLIR framework as well as its compilation infrastructure to implement these tasks. | ||
|
|
||
| ### Quantum Dialects | ||
|
|
||
| The MQT Compiler Collection defines two dialects in MLIR, each with a distinctive purpose. While the Quantum Circuit (QC) dialect is great for exchanging with other formats (such as OpenQASM), the Quantum Circuit Optimization (QCO) dialect is - as the name suggests - specifically designed for optimizations. Let's explore their differences. | ||
|
|
||
| The following snippet allocates and subsequently deallocates one qubit using the `alloc` and `dealloc` operations, respectively. | ||
|
|
||
| ::::{grid} 2 | ||
| :::{grid-item} | ||
|
|
||
| ```{code-block} mlir | ||
| // QC | ||
| %q0 = qc.alloc : !qc.qubit | ||
| qc.dealloc %q0 : !qc.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::{grid-item} | ||
|
|
||
| ```mlir | ||
| // QCO | ||
| %q0_0 = qco.alloc : !qco.qubit | ||
| qco.dealloc %q0_0 : !qco.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
| :::: | ||
|
|
||
| Alternatively, we can target specific hardware qubits by using the `static` operation. In the QC dialect, static qubits don't require a deallocation. | ||
|
|
||
| ::::{grid} 2 | ||
| :::{grid-item} | ||
|
|
||
| ```{code-block} mlir | ||
| // QC | ||
| %q0 = qc.static 1 : !qc.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::{grid-item} | ||
|
|
||
| ```mlir | ||
| // QCO | ||
| %q0_0 = qco.static 1 : !qco.qubit | ||
| qco.dealloc %q0_0 : !qco.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
| :::: | ||
|
|
||
| So far so good. No visible differences. Next, we want to apply the single-qubit Hadamard gate. | ||
|
|
||
| ::::{grid} 2 | ||
| :::{grid-item} | ||
|
|
||
| ```{code-block} mlir | ||
| // QC | ||
| %q0 = qc.alloc : !qc.qubit | ||
| qc.h %q0 : !qc.qubit | ||
| qc.dealloc %q0 : !qc.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::{grid-item} | ||
|
|
||
| ```mlir | ||
| // QCO | ||
| %q0_0 = qco.alloc : !qco.qubit | ||
| %q0_1 = qco.h %q0_0 : !qco.qubit -> !qco.qubit | ||
| qco.dealloc %q0_1 : !qco.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
| :::: | ||
|
|
||
| Notice how the Hadamard operation in the QCO dialect consumes and produces SSA values, while the operation in the QC dialect simply references the targeted qubit. We say that the QC dialect uses _reference semantics_ whereas the QCO dialect uses _value semantics_. Semantically, the unitary operations in the QCO dialect return the new state after modifying it. Furthermore, the QCO dialect imposes _linear typing_: each SSA value is used _exactly_ once. | ||
|
|
||
| Instead of using the Hadamard directly, we can also apply the transformation in terms of X and Y rotations with parameterized gates. | ||
|
|
||
| ::::{grid} 2 | ||
| :::{grid-item} | ||
|
|
||
| ```{code-block} mlir | ||
| // QC | ||
| %theta = arith.constant 1.570796 : f64 | ||
| %phi = arith.constant 3.141593 : f64 | ||
|
|
||
| %q0 = qc.alloc : !qc.qubit | ||
| qc.ry(%theta) %q0 : !qc.qubit | ||
| qc.rx(%phi) %q0 : !qc.qubit | ||
| qc.dealloc %q0 : !qc.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::{grid-item} | ||
|
|
||
| ```mlir | ||
| // QCO | ||
| %theta = arith.constant 1.570796 : f64 | ||
| %phi = arith.constant 3.141593 : f64 | ||
|
|
||
| %q0_0 = qco.alloc : !qco.qubit | ||
| %q0_1 = qco.ry(%theta) %q0_0 : !qco.qubit -> !qco.qubit | ||
| %q0_2 = qco.rx(%phi) %q0_1 : !qco.qubit -> !qco.qubit | ||
| qco.dealloc %q0_2 : !qco.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
| :::: | ||
|
|
||
| To measure qubits, use the `measure` operation. In the QCO dialect, the measurement operation returns not only the classical measurement outcome but also the state after measurement. | ||
|
|
||
| ::::{grid} 2 | ||
| :::{grid-item} | ||
|
|
||
| ```{code-block} mlir | ||
| // QC | ||
| %q0 = qc.alloc : !qc.qubit | ||
| qc.h %q0 : !qc.qubit | ||
| %c0 = qc.measure %q0 : !qc.qubit -> i1 | ||
| qc.dealloc %q0 : !qc.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::{grid-item} | ||
|
|
||
| ```mlir | ||
| // QCO | ||
| %q0_0 = qco.alloc : !qco.qubit | ||
| %q0_1 = qco.h %q0_0 : !qco.qubit -> !qco.qubit | ||
| %q0_2, %c0 = qco.measure %q0_1 : !qco.qubit | ||
| qco.dealloc %q0_2 : !qco.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
| :::: | ||
|
|
||
| Moving on from one-qubit gates, let us apply a controlled-X operation. Towards that end, we allocate another qubit and subsequently use the `ctrl` _modifier_ operation of the respective dialect to implement the controlled-X. Thanks to modifiers, we can represent arbitrary (multi-)controlled gates without having to explicitly define them. | ||
|
|
||
| ::::{grid} 2 | ||
| :::{grid-item} | ||
|
|
||
| ```{code-block} mlir | ||
| // QC | ||
| %q0 = qc.alloc : !qc.qubit | ||
| %q1 = qc.alloc : !qc.qubit | ||
|
|
||
| qc.h %q0 : !qc.qubit | ||
| qc.ctrl(%q0) { | ||
| qc.x %q1 : !qc.qubit | ||
|
|
||
| } : !qc.qubit | ||
|
|
||
| %c0 = qc.measure %q0 : !qc.qubit -> i1 | ||
| %c1 = qc.measure %q1 : !qc.qubit -> i1 | ||
|
|
||
| qc.dealloc %q0 : !qc.qubit | ||
| qc.dealloc %q1 : !qc.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| :::{grid-item} | ||
|
|
||
| ```mlir | ||
| // QCO | ||
| %q0_0 = qco.alloc : !qco.qubit | ||
| %q1_0 = qco.alloc : !qco.qubit | ||
|
|
||
| %q0_1 = qco.h %q0_0 : !qco.qubit -> !qco.qubit | ||
| %q0_2, %q1_1 = qco.ctrl(%q0_1) targets (%arg0 = %q1_0) { | ||
| %q0_2 = qco.x %arg0 : !qco.qubit -> !qco.qubit | ||
| qco.yield %q0_2 | ||
| } : ({!qco.qubit}, {!qco.qubit}) -> ({!qco.qubit}, {!qco.qubit}) | ||
|
|
||
| %q0_3, %c0 = qco.measure %q0_2 : !qco.qubit | ||
| %q1_2, %c1 = qco.measure %q1_1 : !qco.qubit | ||
|
|
||
| qco.dealloc %q0_3 : !qco.qubit | ||
| qco.dealloc %q1_2 : !qco.qubit | ||
| ``` | ||
|
|
||
| ::: | ||
| :::: | ||
|
|
||
| The `qco.ctrl` operation adds a bit of complexity: | ||
|
|
||
| - The input target qubit must be explicitly specified and is aliased to the block argument `%arg0`. | ||
| - The result of the `qco.x` operation needs to be passed to the outer block. Thus, similarly to the operations in the SCF dialect, we use `qco.yield`. | ||
| - Analogously to the other unitary operations in the QCO dialect, the `qco.ctrl` modifier returns the modified state of the input qubits. | ||
|
|
||
| The following figure describes the dataflow graph of the above quantum program in the QCO dialect. | ||
|
|
||
| ```{image} ../_static/qco-dataflow.svg | ||
| :width: 85% | ||
| :align: center | ||
| ``` | ||
|
|
||
| Because of the QCO dialect's value semantics, the dependencies between operations are naturally expressed in the dataflow graph. For instance, in the figure above, the controlled-X operation depends on the application of the Hadamard operation. This is, for example, very useful for gate cancellation: The dependency of one gate is the inverse of it? Cancel the two! Consequently, the expressive dataflow representation is what makes the QCO dialect so powerful for optimization and algorithms more generally. | ||
|
|
There was a problem hiding this comment.
Address missing advanced constructs required by PR objectives.
The Quantum Dialects section provides excellent QC vs. QCO comparisons and explains value/reference semantics well. However, the PR objectives explicitly require:
"Cover advanced constructs: demonstrate multiple functions and discuss control-flow interactions (scf.for, scf.if) with quantum blocks, highlighting SSA and linear-type considerations in QCO (use scf.yield and entry-arguments to avoid variable re-use)."
Current gaps:
- No examples demonstrating
scf.fororscf.ifwith quantum operations - No multi-function examples (function definitions with qubit parameters, function calls)
- No discussion of how linear typing interacts with control-flow constructs
Suggested additions (consider adding a new subsection after line 349):
- Control Flow with Quantum Operations: Show an
scf.forexample that iterates over quantum operations (e.g., applying a gate N times), demonstrating how loop-carried variables work with linear types andqco.yield - Conditional Quantum Operations: Show an
scf.ifexample that conditionally applies operations based on measurement outcomes or parameters - Multi-Function Programs: Show a simple example of a helper function that takes and returns qubits, demonstrating function calls in quantum programs
These examples would complete the tutorial's coverage of the dialect's capabilities and directly address the stated PR objectives.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@docs/mlir/GettingStarted.md` around lines 142 - 349, Add a new subsection
after the Quantum Dialects section that provides (1) an scf.for example showing
loop-carried SSA qubit values with qco.alloc/qco.yield to demonstrate linear
typing across iterations (reference scf.for, qco.yield, loop-carried
entry-arguments), (2) an scf.if example that conditionally applies gates based
on a measurement result showing separate SSA branches and how to merge results
without re-using values (reference scf.if, qco.measure, qco.yield), and (3) a
multi-function example that defines a helper function taking and returning
qubits and shows a call site to illustrate function parameter/return semantics
under linear typing (reference the function declaration/call symbols used in the
doc); briefly annotate each example with one sentence explaining how linear
typing is preserved (use scf.yield and explicit entry-arguments to avoid
variable re-use).
There was a problem hiding this comment.
♻️ Duplicate comments (4)
docs/mlir/GettingStarted.md (4)
442-442:⚠️ Potential issue | 🟡 MinorAdd closing content or remove the empty "Conclusion" heading.
The "Conclusion" heading has no content, leaving the guide without proper closure. Either add a brief 2-3 sentence summary (e.g., recap the key takeaways: understanding QC vs QCO dialects, using
mqt-ccfor optimization, emitting QIR for execution) or remove the heading entirely.✍️ Suggested conclusion text
## Conclusion You now have a foundation for working with the MQT Compiler Collection. You've learned the differences between the QC and QCO dialects, explored how value semantics and linear typing enable powerful optimizations, and seen how to use `mqt-cc` to optimize quantum programs and emit QIR for execution. For more details on the dialects and available passes, refer to the [QC](./QC.md) and [QCO](./QCO.md) documentation.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` at line 442, The "## Conclusion" heading is empty; either remove that heading or add a brief 2–3 sentence closing paragraph under "## Conclusion" that recaps key takeaways (differences between the QC and QCO dialects, value semantics/linear typing enabling optimizations, using `mqt-cc` to optimize and emit QIR) and adds links to the QC and QCO docs (e.g., reference ./QC.md and ./QCO.md); update the GettingStarted.md by replacing the empty heading with this short summary or deleting the heading entirely.
352-365: 🧹 Nitpick | 🔵 TrivialConsider adding a brief "Current Limitations" note.
The compilation flow description is clear and the diagram is helpful. However, based on learnings, the QC↔QCO conversions currently have specific constraints (e.g., limited multi-function support patterns, container-typed qubit flow restrictions, scf operation constraints). Consider adding a brief "Current Limitations" note or a link to more detailed documentation so readers attempting complex multi-function or control-flow programs understand the current boundaries.
📋 Suggested limitation note
Add a note before or after the diagram:
**Note:** The current QC↔QCO conversion has some limitations. For example, multi-function programs with qubit parameters and complex control-flow patterns (mixing `scf` operations with container-typed qubits) may require specific patterns. Refer to the [QC](./QC.md) and [QCO](./QCO.md) dialect documentation for details on supported constructs.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 352 - 365, Add a short "Current Limitations" note adjacent to the compilation flow diagram in GettingStarted.md explaining that QC↔QCO conversions have constraints (e.g., limited multi-function patterns with qubit parameters, container-typed qubit flow restrictions, and scf operation interop limits) and point readers to the QC and QCO dialect docs for details (suggested phrasing: a one-paragraph note referencing ./QC.md and ./QCO.md); place this note immediately before or after the embedded compilation-pipeline.svg block so readers see the limitation caveat when viewing the flow.
148-351:⚠️ Potential issue | 🟠 MajorAdd required advanced constructs to complete PR objectives.
The Quantum Dialects section provides excellent QC vs. QCO comparisons and clearly explains value/reference semantics and linear typing. However, the PR objectives explicitly require coverage of advanced constructs that are currently missing:
"Cover advanced constructs beyond simple gates: demonstrate multiple functions and discuss interaction of control-flow (scf.for, scf.if) with quantum blocks, emphasizing SSA and linear-type considerations in QCO (use scf.yield and entry-arguments to avoid variable reuse)."
Missing content:
scf.forwith quantum operations: Show loop-carried SSA qubit values demonstrating how linear typing works across iterationsscf.ifwith quantum operations: Show conditional quantum operations with separate SSA branches and how to merge results without reusing values- Multi-function examples: Show helper functions with qubit parameters/returns to illustrate function call semantics under linear typing
These examples are essential for readers to understand how the QCO dialect handles real-world quantum programs with control flow and modularity.
Suggested additions (consider adding a new subsection "Advanced Constructs" after line 349):
📚 Recommended structure for advanced constructs subsection
Add a new subsection covering:
Control Flow with Quantum Operations (
scf.for):
- Example: applying a gate N times in a loop
- Show how loop-carried variables work with
qco.alloc,qco.yield, and entry-arguments- Annotate how linear typing is preserved across iterations
Conditional Quantum Operations (
scf.if):
- Example: conditionally applying gates based on measurement outcomes
- Show separate SSA branches and merging results with
qco.yield- Explain how to avoid variable reuse in branches
Multi-Function Programs:
- Example: helper function that takes and returns qubits
- Show function declaration with qubit parameters
- Show call site demonstrating function call/return under linear typing
Each example should include 1-2 sentences explaining how linear typing constraints are satisfied.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 148 - 351, The Advanced Constructs requirement is missing: add a new "Advanced Constructs" subsection after the Quantum Dialects examples that demonstrates scf.for, scf.if, and multi-function examples with QCO to show SSA/linear-typing across control flow and calls. Concretely, include (1) an scf.for example that uses a loop-carried qubit value (use qco.alloc at entry, thread the qubit through loop iterations via scf.for region arguments and qco.yield to show linear typing across iterations), (2) an scf.if example that measures and conditionally applies gates with separate SSA branches and merges results via qco.yield/entry-arguments (avoid reusing SSA values), and (3) a small helper function example (declare a function taking and returning !qco.qubit, call it and thread the returned SSA qubit) to illustrate function-call semantics under linear typing; annotate each snippet with one or two sentences explaining how qco.yield, entry-arguments, and SSA ensure linear usage.
7-20: 🧹 Nitpick | 🔵 TrivialConsole prompt symbols don't match project documentation style.
The console code blocks use
%as the shell prompt. Based on learnings, MQT Core documentation conventionally uses$prompt symbols in console code blocks (e.g.,$ uv pip install ...or$ cmake -Bbuild ...). Consider updating to$for consistency across the documentation.📝 Suggested prompt update
```console -% cmake -Bbuild \ +$ cmake -Bbuild \ -DMLIR_DIR=<path to MLIR> \ -DLLVM_DIR=<path to LLVM> \ -DCMAKE_BUILD_TYPE:STRING=Release \ -DBUILD_MQT_CORE_MLIR=ON -% cd build && cmake --build . --target mqt-cc +$ cd build && cmake --build . --target mqt-ccYou can verify your build by running the following command. If everything worked correctly, it should print an usage message.
-% ./mlir/tools/mqt-cc/mqt-cc --help +$ ./mlir/tools/mqt-cc/mqt-cc --helpApply the same replacement at lines 393, 431, and 437. </details> <details> <summary>🤖 Prompt for AI Agents</summary>Verify each finding against the current code and only fix it if needed.
In
@docs/mlir/GettingStarted.mdaround lines 7 - 20, Replace the nonstandard
percent shell prompt (%) with the project's conventional dollar prompt ($)
inside the console code blocks: update the prompt for the cmake invocation
("cmake -Bbuild ... -DBUILD_MQT_CORE_MLIR=ON"), the build command ("cd build &&
cmake --build . --target mqt-cc"), and the verification command
("./mlir/tools/mqt-cc/mqt-cc --help"); then apply the same %→$ replacement to
the other console blocks containing those commands (the additional occurrences
mentioned in the review).</details> </blockquote></details> </blockquote></details> <details> <summary>🤖 Prompt for all review comments with AI agents</summary>Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In@docs/mlir/GettingStarted.md:
- Line 442: The "## Conclusion" heading is empty; either remove that heading or
add a brief 2–3 sentence closing paragraph under "## Conclusion" that recaps key
takeaways (differences between the QC and QCO dialects, value semantics/linear
typing enabling optimizations, usingmqt-ccto optimize and emit QIR) and adds
links to the QC and QCO docs (e.g., reference ./QC.md and ./QCO.md); update the
GettingStarted.md by replacing the empty heading with this short summary or
deleting the heading entirely.- Around line 352-365: Add a short "Current Limitations" note adjacent to the
compilation flow diagram in GettingStarted.md explaining that QC↔QCO conversions
have constraints (e.g., limited multi-function patterns with qubit parameters,
container-typed qubit flow restrictions, and scf operation interop limits) and
point readers to the QC and QCO dialect docs for details (suggested phrasing: a
one-paragraph note referencing ./QC.md and ./QCO.md); place this note
immediately before or after the embedded compilation-pipeline.svg block so
readers see the limitation caveat when viewing the flow.- Around line 148-351: The Advanced Constructs requirement is missing: add a new
"Advanced Constructs" subsection after the Quantum Dialects examples that
demonstrates scf.for, scf.if, and multi-function examples with QCO to show
SSA/linear-typing across control flow and calls. Concretely, include (1) an
scf.for example that uses a loop-carried qubit value (use qco.alloc at entry,
thread the qubit through loop iterations via scf.for region arguments and
qco.yield to show linear typing across iterations), (2) an scf.if example that
measures and conditionally applies gates with separate SSA branches and merges
results via qco.yield/entry-arguments (avoid reusing SSA values), and (3) a
small helper function example (declare a function taking and returning
!qco.qubit, call it and thread the returned SSA qubit) to illustrate
function-call semantics under linear typing; annotate each snippet with one or
two sentences explaining how qco.yield, entry-arguments, and SSA ensure linear
usage.- Around line 7-20: Replace the nonstandard percent shell prompt (%) with the
project's conventional dollar prompt ($) inside the console code blocks: update
the prompt for the cmake invocation ("cmake -Bbuild ...
-DBUILD_MQT_CORE_MLIR=ON"), the build command ("cd build && cmake --build .
--target mqt-cc"), and the verification command ("./mlir/tools/mqt-cc/mqt-cc
--help"); then apply the same %→$ replacement to the other console blocks
containing those commands (the additional occurrences mentioned in the review).</details> --- <details> <summary>ℹ️ Review info</summary> <details> <summary>⚙️ Run configuration</summary> **Configuration used**: Organization UI **Review profile**: ASSERTIVE **Plan**: Pro **Run ID**: `a0e03394-5f02-488e-9483-b8722bd852bd` </details> <details> <summary>📥 Commits</summary> Reviewing files that changed from the base of the PR and between 0b25cef4c2eac8ff8638dcd2d2990af47022c3bf and 6caf32718c0929680980b552d0695a9c7b6fb62d. </details> <details> <summary>⛔ Files ignored due to path filters (1)</summary> * `docs/_static/compilation-pipeline.svg` is excluded by `!**/*.svg` </details> <details> <summary>📒 Files selected for processing (1)</summary> * `docs/mlir/GettingStarted.md` </details> </details> <!-- This is an auto-generated comment by CodeRabbit for review status -->
There was a problem hiding this comment.
♻️ Duplicate comments (4)
docs/mlir/GettingStarted.md (4)
294-294:⚠️ Potential issue | 🔴 CriticalFix non-breaking space in the MyST
{code-block}directive.At Line 294,
{code-block} mlircontains a non-ASCII NBSP between}andmlir, which can break directive parsing in some doc toolchains. Replace it with a normal ASCII space.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` at line 294, The `{code-block}` MyST directive contains a non-breaking space between the closing brace and the language token (the snippet appears as "```{code-block} mlir"); locate that directive and replace the NBSP with a normal ASCII space so it reads "```{code-block} mlir" to avoid parsing issues in doc toolchains.
470-470:⚠️ Potential issue | 🟡 MinorComplete or remove the empty Conclusion section.
At Line 470,
## Conclusionis empty, leaving the guide without a closeout. Add a short summary paragraph or remove the heading.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` at line 470, The "## Conclusion" heading in GettingStarted.md is empty; either remove the "## Conclusion" line entirely or add a brief closing paragraph under the "## Conclusion" heading that summarizes the guide and next steps; update the section titled "## Conclusion" accordingly so the document no longer contains an empty heading.
176-379:⚠️ Potential issue | 🟠 MajorPR objective gap: advanced quantum control-flow and multi-function examples are still missing.
This section still lacks dedicated examples for quantum
scf.for, quantumscf.if, and a multi-function qubit flow with explicit linear-typing handling (scf.yield/ entry arguments), which are required by the linked objective.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 176 - 379, The docs section is missing examples for quantum control-flow and multi-function linear-typed flows; add compact MLIR snippets demonstrating scf.for, scf.if, and a multi-function example that uses scf.yield and function entry arguments to show explicit linear typing and qubit SSA flow (reference the QCO dialect operations like qco.alloc, qco.dealloc, qco.ctrl, qco.h, qco.measure plus scf.for/scf.if/scf.yield and function signatures) so readers can see how control flow and inter-function qubit passing respect value semantics and linear usage; place them near the existing QCO examples and ensure each snippet highlights the linear-typing rules (each SSA qubit used exactly once) and use of scf.yield to return updated qubit values.
395-397:⚠️ Potential issue | 🟠 MajorAdd a short “Current limitations” note before the tool examples.
Before Line 395, add a concise limitations block for current QC→QCO, function-like, and scf boundaries so readers do not overgeneralize support from the examples.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@docs/mlir/GettingStarted.md` around lines 395 - 397, Add a short "Current limitations" note immediately before the "## Examples Using the MQT Compiler Collection Tool" header that briefly calls out the known limitations for QC→QCO translation, function-like constructs, and scf region boundaries so readers don't overgeneralize from the examples; keep it concise (1–3 sentences or a 3-line bullet list) and mention: QC→QCO mappings are partial, function-like entities may not be fully preserved/Lowered, and scf regions/loops have limited handling/edge-case support.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Duplicate comments:
In `@docs/mlir/GettingStarted.md`:
- Line 294: The `{code-block}` MyST directive contains a non-breaking space
between the closing brace and the language token (the snippet appears as
"```{code-block} mlir"); locate that directive and replace the NBSP with a
normal ASCII space so it reads "```{code-block} mlir" to avoid parsing issues in
doc toolchains.
- Line 470: The "## Conclusion" heading in GettingStarted.md is empty; either
remove the "## Conclusion" line entirely or add a brief closing paragraph under
the "## Conclusion" heading that summarizes the guide and next steps; update the
section titled "## Conclusion" accordingly so the document no longer contains an
empty heading.
- Around line 176-379: The docs section is missing examples for quantum
control-flow and multi-function linear-typed flows; add compact MLIR snippets
demonstrating scf.for, scf.if, and a multi-function example that uses scf.yield
and function entry arguments to show explicit linear typing and qubit SSA flow
(reference the QCO dialect operations like qco.alloc, qco.dealloc, qco.ctrl,
qco.h, qco.measure plus scf.for/scf.if/scf.yield and function signatures) so
readers can see how control flow and inter-function qubit passing respect value
semantics and linear usage; place them near the existing QCO examples and ensure
each snippet highlights the linear-typing rules (each SSA qubit used exactly
once) and use of scf.yield to return updated qubit values.
- Around line 395-397: Add a short "Current limitations" note immediately before
the "## Examples Using the MQT Compiler Collection Tool" header that briefly
calls out the known limitations for QC→QCO translation, function-like
constructs, and scf region boundaries so readers don't overgeneralize from the
examples; keep it concise (1–3 sentences or a 3-line bullet list) and mention:
QC→QCO mappings are partial, function-like entities may not be fully
preserved/Lowered, and scf regions/loops have limited handling/edge-case
support.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: ASSERTIVE
Plan: Pro
Run ID: 75a98cd7-106b-4785-a6a4-3d120be55e05
📒 Files selected for processing (1)
docs/mlir/GettingStarted.md
Description
This pull request adds a "Getting Started with MLIR" tutorial to the ReadTheDocs documentation. Thus, resolves #1452.
Checklist: