-
Notifications
You must be signed in to change notification settings - Fork 174
Profile adoption tool #1110
Profile adoption tool #1110
Conversation
|
@troelsfr I'm about halfway through the review, and I should be able to finish it before Monday morning your time so you have the chance to respond and we can get this ready to merge by EOD! |
swernli
left a comment
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 changes mostly look good, just a few questions before I'm ready to sign off! There are also some suggestions about minor updates (file renames or comments) that you can either address here or in a follow up PR that we work on Monday to get the feature branch ready for sharing.
src/Passes/examples/QubitAllocationAnalysis/ConstSizeArray/ConstSizeArray.qs
Show resolved
Hide resolved
Co-authored-by: Stefan J. Wernli <[email protected]>
swernli
left a comment
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.
Thanks for addressing my questions! We should be ready to merge this once the builds pass.
| /// are matched in order and by size. | ||
| void addChild(Child const& child); | ||
|
|
||
| /// Flags that this operand should be captured. This function ensures |
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 comment alone here is not sufficient to understand what the purpose is of this flag; what operands can and should be captured? What happens with captured operands? A see also reference to the piece of code that uses this information might help to clarify as well.
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 what you possible need is some high level description of the OperandPrototype, its relation to creating rules and in that context. what captures are?
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.
Yes.
Co-authored-by: bettinaheim <[email protected]>
bettinaheim
left a comment
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 went over the code relatively quick, and I am sure there are places where I didn't look carefully enough. I did a quick read through everything, though.
src/Passes/Source/Passes/QirAllocationAnalysis/QirAllocationAnalysis.hpp
Outdated
Show resolved
Hide resolved
src/Passes/Source/Passes/ExpandStaticAllocation/ExpandStaticAllocation.cpp
Show resolved
Hide resolved
| @@ -1,156 +1,157 @@ | |||
| # QIR Passes for LLVM | |||
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 was the reason for removing the general intro and links to the docs? Also the link in ## Out-of-source Pass might be useful to keep.
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.
As such we can keep it as training material, but it does not belong at the top-level README as this file should contain the "user" documentation such as "What does the tool do", "How to build the tool", "How to run the tool" and "How do I create new profiles". Passes and the usage of passes is an implementation detail that only has relevance for those contributing to the implementation of the library.
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'd keep the info in the same place as any instructions for contributing to the passes.
Profile adoption tool
Note PR is WiP.
Goal
The overall goal of this PR is to create a first version of a tool that allows transformation of a general QIR to a base profile.
Quick start
Once the project is built (see next sections), you can generate a new QIR as follows:
Likewise, you can validate that a QIR follows a specification by running:
Example
In this example, we start with a QIR generated by the Q# frontend. Rather than giving the full 3445 lines of QIR, we instead give the frontend code:
Once compiled and the initial QIR is generated and save in the file
analysis-example.ll, we execute the commandThe QAT tool will now attempt to map the QIR in
analysis-example.llinto a QIR which is compatible with the base format. Removing type and function declarations, the correspoding code reads:We note the absence of loops, and that quantum registers are "allocated" at compile time meaning that each qubit instance is assigned a unique ID. As some code may be dead and optimised away, the qubit allocation is not garantueed to be sequential at this point in time. Future work will include writing a qubit ID remapper which will allow qubits.
We also note that the function
TeleportChain__TeleportQubitUsingPresharedEntanglement__bodywas cloned twice. This is due to the allocation of qubits and the function being called twice. At present, the analyser does not take qubit release into account and just assumes that it will never be released due to the complicated nature for dealing with nested functions at compile time.Current TODOs include getting LLVM to remove dead code, do better constant folding and function inlining. Once this is performed correctly, next steps is the remapper and finally a better analysis on what call paths potentially create problems in terms of qubit allocation.
Dependencies
This library is written in C++ and depends on:
Additional development dependencies include:
Building the passes
To build the passes, create a new build directory and switch to that directory:
mkdir Debug cd Debug/To build the library, first configure CMake from the build directory
and then make your target
The default target is
all. Other valid targets are the name of the folders inlibs/found in the passes root.Profile adoption tool
Building QAT
First
cd Debug make qatthen
Implementing a profile pass
As an example of how one can implement a new profile pass, we here show the implementational details of our example pass which allows mapping the teleportation code to the base profile:
pb.registerPipelineParsingCallback([](StringRef name, FunctionPassManager &fpm, ArrayRef<PassBuilder::PipelineElement> /*unused*/) { // Base profile if (name == "restrict-qir<base-profile>") { RuleSet rule_set; // Defining the mapping auto factory = RuleFactory(rule_set); factory.useStaticQuantumArrayAllocation(); factory.useStaticQuantumAllocation(); factory.useStaticResultAllocation(); factory.optimiseBranchQuatumOne(); // factory.optimiseBranchQuatumZero(); factory.disableReferenceCounting(); factory.disableAliasCounting(); factory.disableStringSupport(); fpm.addPass(TransformationRulePass(std::move(rule_set))); return true; } return false; }); }};Transformations of the IR will happen on the basis of what rules are added to the rule set. The purpose of the factory is to make easy to add rules that serve a single purpose as well as making a basis for making rules unit testable.
Implementing new rules
Implementing new rules consists of two steps: Defining a pattern that one wish to replace and implementing the corresponding replacement logic. Inside a factory member function, this look as follows:
where
addRuleadds the rule to the current rule set.Capturing patterns
The pattern defined in this snippet matches IR like:
In the above rule, the first and a second argument of
__quantum__rt__array_get_element_ptr_1dis captured asarrayNameandindex, respectively. Likewise, the bitcast instruction is captured ascast. Each of these captures will be available inside the replacement functionaccess_replacer.Implementing replacement logic
After a positive match is found, the lead instruction alongside a IRBuilder, a capture table and a replacement table is passed to the replacement function. Here is an example on how one can access the captured variables to perform a transformation of the IR: