-
Notifications
You must be signed in to change notification settings - Fork 182
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
Draft of dependency graph generation algorithm #1848
Closed
Closed
Changes from all commits
Commits
Show all changes
40 commits
Select commit
Hold shift + click to select a range
a447bd9
Add dependency analysis code
atgeller c465360
Formatting
atgeller 0943b5a
Use lifetimes computed from dependency graph to map to physical qubits.
atgeller 31a7d64
Use lifetimes to determine when it is safe to reuse qubits, and reord…
atgeller 49edf9e
Insert into new block and whack old block after instead of erasing in…
atgeller 7a31f75
Missed an erase
atgeller 615ee75
Forgot to actually erase old block
atgeller 7a752d9
Some cleanup and fixes
atgeller 96fa396
Merge branch 'main' into dependency_analysis
atgeller 3565142
Fix up scheduling to address bugs, includes two test cases for these …
atgeller fc5c485
Merge branch 'dependency_analysis' of github.com:atgeller/cuda-quantu…
atgeller 0212dde
Add filecheck commands to tests
atgeller 07050d7
Add assertions and validation functions, and tests for errors. Also i…
atgeller d959274
More assertions in place
atgeller 2884c07
Add support for classical values
atgeller 4b3136b
Merge branch 'main' into dependency_analysis
atgeller a9d4941
Fixes several bugs (mostly related to classical values) and adds test…
atgeller 0f5f20a
Merge branch 'dependency_analysis' of github.com:atgeller/cuda-quantu…
atgeller 68a056e
Some cleanup, remove unused functions
atgeller 9a9f826
Remove unnecessary TODO
atgeller 9d5d12d
Improve error messages, add missing test files
atgeller 6526b5e
Improve errors a bit
atgeller 24843c1
Fix performance issue with finding nodes at a given cycle
atgeller a61ac20
Ensure that classical operations after quantum values are generated
atgeller 0d7160a
Preliminary addition of qubit management passes to JIT pipeline
atgeller 622b8b2
Update pass descriptions
atgeller f4e93bc
Add qubit management pipeline
atgeller ffc4c4c
Merge remote-tracking branch 'upstream/main' into dependency_analysis
atgeller 32ecc13
Add to yaml configs, add options to disable qubit management and to d…
atgeller 02b45c9
Add targettests for qubit management
atgeller ffad80d
Fix bug counting number of virtual qubits
atgeller da4f915
Update how qubit-management is added to qir-base pipeline
atgeller 6c0ff58
Forgot to remove debug code
atgeller 3de2006
Run qubit management before mapping
atgeller c61600e
Impose ordering on assigning physical qubits
atgeller c11779c
Fix various issues in dependency tests
atgeller 8c8f054
Fix bug with codegen for classical values
atgeller 775239f
Avoid reliance on statistic variables to avoid multithreading issues
atgeller 3f01e51
Missed a test file
atgeller ab3c9c4
Small fix to qubit management pipeline
atgeller File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2022 - 2024 NVIDIA Corporation & Affiliates. * | ||
* All rights reserved. * | ||
* * | ||
* This source code and the accompanying materials are made available under * | ||
* the terms of the Apache License 2.0 which accompanies this distribution. * | ||
******************************************************************************/ | ||
|
||
#include "cudaq/Frontend/nvqpp/AttributeNames.h" | ||
#include "cudaq/Optimizer/Dialect/CC/CCDialect.h" | ||
#include "cudaq/Optimizer/Dialect/Quake/QuakeDialect.h" | ||
#include "cudaq/Optimizer/Dialect/Quake/QuakeOps.h" | ||
#include "cudaq/Optimizer/Transforms/Passes.h" | ||
#include "mlir/IR/PatternMatch.h" | ||
#include "mlir/IR/Threading.h" | ||
#include "mlir/InitAllDialects.h" | ||
#include "mlir/Rewrite/FrozenRewritePatternSet.h" | ||
#include "mlir/Transforms/DialectConversion.h" | ||
|
||
using namespace mlir; | ||
|
||
//===----------------------------------------------------------------------===// | ||
// Generated logic | ||
//===----------------------------------------------------------------------===// | ||
namespace cudaq::opt { | ||
#define GEN_PASS_DEF_ASSIGNIDS | ||
#include "cudaq/Optimizer/Transforms/Passes.h.inc" | ||
} // namespace cudaq::opt | ||
|
||
namespace { | ||
bool isMeasureOp(Operation *op) { | ||
return dyn_cast<quake::MxOp>(*op) || dyn_cast<quake::MyOp>(*op) || | ||
dyn_cast<quake::MzOp>(*op); | ||
} | ||
|
||
int numClassicalInput(Operation *op) { | ||
if (dyn_cast<quake::RxOp>(*op) || dyn_cast<quake::RyOp>(*op) || | ||
dyn_cast<quake::RzOp>(*op)) | ||
return 1; | ||
|
||
if (dyn_cast<quake::PhasedRxOp>(*op)) | ||
return 2; | ||
|
||
return 0; | ||
} | ||
|
||
class NullWirePat : public OpRewritePattern<quake::NullWireOp> { | ||
public: | ||
unsigned *counter; | ||
|
||
NullWirePat(MLIRContext *context, unsigned *c) | ||
: OpRewritePattern<quake::NullWireOp>(context), counter(c) {} | ||
|
||
LogicalResult matchAndRewrite(quake::NullWireOp alloc, | ||
PatternRewriter &rewriter) const override { | ||
if (alloc->hasAttr("qid")) | ||
return failure(); | ||
|
||
auto qid = (*counter)++; | ||
|
||
rewriter.startRootUpdate(alloc); | ||
alloc->setAttr("qid", rewriter.getUI32IntegerAttr(qid)); | ||
rewriter.finalizeRootUpdate(alloc); | ||
|
||
return success(); | ||
} | ||
}; | ||
|
||
std::optional<uint> findQid(Value v) { | ||
auto defop = v.getDefiningOp(); | ||
if (!defop) | ||
return std::nullopt; | ||
|
||
if (defop->getRegions().size() != 0) { | ||
defop->emitOpError( | ||
"AssignIDsPass cannot handle non-function operations with regions." | ||
" Do you have if statements in a Base Profile QIR program?"); | ||
return std::nullopt; | ||
} | ||
|
||
if (!isa<quake::WireType>(v.getType())) | ||
return std::nullopt; | ||
|
||
assert(quake::isLinearValueForm(defop) && | ||
"AssignIDsPass requires operations to be in value form"); | ||
|
||
if (defop->hasAttr("qid")) { | ||
uint qid = defop->getAttr("qid").cast<IntegerAttr>().getUInt(); | ||
return std::optional<uint>(qid); | ||
} | ||
|
||
// Figure out matching operand | ||
size_t i = 0; | ||
for (; i < defop->getNumResults(); i++) | ||
if (defop->getResult(i) == v) | ||
break; | ||
|
||
// Special cases where result # != operand #: | ||
// Wire is second output but sole input | ||
if (isMeasureOp(defop)) | ||
i = 0; | ||
// Classical values preceding wires as input are consumed and not part of the results | ||
i += numClassicalInput(defop); | ||
// Swap op swaps wires | ||
if (dyn_cast<quake::SwapOp>(defop)) | ||
i = (i == 1 ? 0 : 1); | ||
|
||
return findQid(defop->getOperand(i)); | ||
} | ||
|
||
class SinkOpPat : public OpRewritePattern<quake::SinkOp> { | ||
public: | ||
SinkOpPat(MLIRContext *context) : OpRewritePattern<quake::SinkOp>(context) {} | ||
|
||
LogicalResult matchAndRewrite(quake::SinkOp release, | ||
PatternRewriter &rewriter) const override { | ||
auto qid = findQid(release.getOperand()); | ||
|
||
if (!qid.has_value()) | ||
return failure(); | ||
|
||
rewriter.startRootUpdate(release); | ||
release->setAttr("qid", rewriter.getUI32IntegerAttr(qid.value())); | ||
rewriter.finalizeRootUpdate(release); | ||
|
||
return success(); | ||
} | ||
}; | ||
|
||
//===----------------------------------------------------------------------===// | ||
// Pass implementation | ||
//===----------------------------------------------------------------------===// | ||
|
||
struct AssignIDsPass : public cudaq::opt::impl::AssignIDsBase<AssignIDsPass> { | ||
using AssignIDsBase::AssignIDsBase; | ||
|
||
void runOnOperation() override { | ||
auto func = getOperation(); | ||
|
||
if (!func->hasAttr("cudaq-kernel") || func.getBlocks().empty()) | ||
return; | ||
|
||
if (!func.getFunctionBody().hasOneBlock()) { | ||
func.emitError("AssignIDsPass cannot handle multiple blocks. Do " | ||
"you have if statements in a Base Profile QIR program?"); | ||
signalPassFailure(); | ||
return; | ||
} | ||
|
||
assign(); | ||
} | ||
|
||
void assign() { | ||
auto *ctx = &getContext(); | ||
func::FuncOp func = getOperation(); | ||
RewritePatternSet patterns(ctx); | ||
unsigned x = 0; | ||
patterns.insert<NullWirePat>(ctx, &x); | ||
patterns.insert<SinkOpPat>(ctx); | ||
ConversionTarget target(*ctx); | ||
target.addLegalDialect<quake::QuakeDialect>(); | ||
target.addDynamicallyLegalOp<quake::NullWireOp>( | ||
[&](quake::NullWireOp alloc) { return alloc->hasAttr("qid"); }); | ||
target.addDynamicallyLegalOp<quake::SinkOp>( | ||
[&](quake::SinkOp sink) { return sink->hasAttr("qid"); }); | ||
if (failed(applyPartialConversion(func.getOperation(), target, | ||
std::move(patterns)))) { | ||
func.emitOpError("Assigning qids failed"); | ||
signalPassFailure(); | ||
} | ||
} | ||
}; | ||
|
||
} // namespace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
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 attribute approach is brittle as other transformations will not necessarily keep the information. We should really use WireSet, BorrowWire, ReturnWire for explicitly mapping the identity of a qubit from an infinite space (virtual registers) to a finite space (physical registers).
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.
Makes sense, right now Assign IDs and Dependency Analysis are very tangled passes, so they pretty much have to be run one right after another, and Dependency Analysis has to check that the attributes are present.