Skip to content

Commit

Permalink
Merge branch 'main' into fix_nightly_test
Browse files Browse the repository at this point in the history
  • Loading branch information
sacpis authored Nov 16, 2024
2 parents 65bdb70 + d09ad57 commit d07fa84
Show file tree
Hide file tree
Showing 47 changed files with 376 additions and 400 deletions.
5 changes: 3 additions & 2 deletions docs/sphinx/api/default_ops.rst
Original file line number Diff line number Diff line change
Expand Up @@ -631,8 +631,9 @@ operations, each operating on 2 qubits.

.. note::

Custom operations are currently supported only on :doc:`../using/backends/simulators`.
Attempt to use with a hardware backend will result in runtime error.
When a custom operation is used on hardware backends, it is synthesized to a
set of native quantum operations. Currently, only 1-qubit and 2-qubit custom
operations are supported on hardware backends.


Photonic Operations on Qudits
Expand Down
19 changes: 18 additions & 1 deletion include/cudaq/Optimizer/Dialect/CC/CCOps.td
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
#define CUDAQ_OPTIMIZER_DIALECT_CC_OPS

include "mlir/Interfaces/InferTypeOpInterface.td"
include "mlir/IR/SymbolInterfaces.td"
include "cudaq/Optimizer/Dialect/Common/Traits.td"
include "cudaq/Optimizer/Dialect/CC/CCDialect.td"
include "cudaq/Optimizer/Dialect/CC/CCInterfaces.td"
Expand Down Expand Up @@ -911,19 +912,35 @@ def cc_GlobalOp : CCOp<"global", [IsolatedFromAbove, Symbol]> {

let arguments = (ins
TypeAttr:$global_type,
StrAttr:$sym_name,
SymbolNameAttr:$sym_name,
OptionalAttr<AnyAttr>:$value,
OptionalAttr<StrAttr>:$sym_visibility,
UnitAttr:$constant,
UnitAttr:$external
);

let hasCustomAssemblyFormat = 1;

let builders = [
OpBuilder<(ins
"mlir::Type":$type, "mlir::StringRef":$name,
"mlir::Attribute":$value, "bool":$constant, "bool":$external), [{
return build($_builder, $_state, type, name, value,
mlir::StringAttr{}, constant, external);
}]
>];

let extraClassDeclaration = [{
cudaq::cc::PointerType getType() {
auto globalTy = getGlobalType();
return cudaq::cc::PointerType::get(globalTy);
}

//===------------------------------------------------------------------===//
// SymbolOpInterface Methods
//===------------------------------------------------------------------===//

bool isDeclaration() { return getExternal(); }
}];
}

Expand Down
4 changes: 2 additions & 2 deletions include/cudaq/Optimizer/Transforms/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -407,7 +407,7 @@ def GetConcreteMatrix : Pass<"get-concrete-matrix", "mlir::func::FuncOp"> {
return
}

cc.global constant @__nvqpp__mlirgen__function_foo_generator_1.bar.rodata_0 ((dense<[(0.000000e+00,0.000000e+00), (1.000000e+00,0.000000e+00), (1.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
cc.global constant private @__nvqpp__mlirgen__function_foo_generator_1.bar.rodata_0 ((dense<[(0.000000e+00,0.000000e+00), (1.000000e+00,0.000000e+00), (1.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
}
```

Expand Down Expand Up @@ -816,7 +816,7 @@ def StatePreparation : Pass<"state-prep", "mlir::ModuleOp"> {
%2 = quake.init_state %1, %0 : (!quake.veq<2>, !cc.ptr<!cc.array<complex<f32> x 4>>) -> !quake.veq<2>
return
}
cc.global constant @foo.rodata_0 (dense<[(0.707106769,0.000000e+00), (0.707106769,0.000000e+00), (0.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00)]> : tensor<4xcomplex<f32>>) : !cc.array<complex<f32> x 4>
cc.global constant private @foo.rodata_0 (dense<[(0.707106769,0.000000e+00), (0.707106769,0.000000e+00), (0.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00)]> : tensor<4xcomplex<f32>>) : !cc.array<complex<f32> x 4>
}
```
Will be rewritten to:
Expand Down
6 changes: 4 additions & 2 deletions lib/Frontend/nvqpp/ConvertExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2498,8 +2498,10 @@ bool QuakeBridgeVisitor::VisitInitListExpr(clang::InitListExpr *x) {
{
OpBuilder::InsertionGuard guard(builder);
builder.setInsertionPointToEnd(module.getBody());
builder.create<cc::GlobalOp>(loc, globalTy, name, f64Attr,
/*constant=*/true);
builder
.create<cc::GlobalOp>(loc, globalTy, name, f64Attr,
/*constant=*/true, /*external=*/false)
.setPrivate();
}
auto ptrTy = cc::PointerType::get(globalTy);
auto globalInit = builder.create<cc::AddressOfOp>(loc, ptrTy, name);
Expand Down
9 changes: 6 additions & 3 deletions lib/Optimizer/Builder/Intrinsics.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -481,9 +481,12 @@ static cc::GlobalOp buildVectorOfConstantElements(Location loc, ModuleOp module,
OpBuilder::InsertionGuard guard(builder);
builder.setInsertionPointToEnd(module.getBody());
auto globalTy = cc::ArrayType::get(ctx, eleTy, arrayAttr.size());
return builder.create<cudaq::cc::GlobalOp>(loc, globalTy, name, arrayAttr,
/*constant=*/true,
/*external=*/false);
auto global =
builder.create<cudaq::cc::GlobalOp>(loc, globalTy, name, arrayAttr,
/*constant=*/true,
/*external=*/false);
global.setPrivate();
return global;
}

template <typename A>
Expand Down
9 changes: 9 additions & 0 deletions lib/Optimizer/CodeGen/Pipelines.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,15 @@ void cudaq::opt::addPipelineTranslateToOpenQASM(PassManager &pm) {
pm.addNestedPass<func::FuncOp>(createLiftArrayAlloc());
pm.addPass(createGlobalizeArrayValues());
pm.addPass(createStatePreparation());
pm.addNestedPass<func::FuncOp>(createGetConcreteMatrix());
pm.addPass(createUnitarySynthesis());
pm.addPass(createSymbolDCEPass());
pm.addPass(createCanonicalizerPass());
pm.addPass(createCSEPass());
pm.addNestedPass<func::FuncOp>(createMultiControlDecompositionPass());
pm.addPass(createDecompositionPass(
{.enabledPatterns = {"CCZToCX", "RxAdjToRx", "RyAdjToRy", "RzAdjToRz"}}));
pm.addPass(createCanonicalizerPass());
}

void cudaq::opt::addPipelineTranslateToIQMJson(PassManager &pm) {
Expand Down
22 changes: 18 additions & 4 deletions lib/Optimizer/Dialect/CC/CCOps.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1003,6 +1003,14 @@ ParseResult cudaq::cc::GlobalOp::parse(OpAsmParser &parser,
result.addAttribute(getConstantAttrName(result.name),
parser.getBuilder().getUnitAttr());

// Check for the visibility optional keyword third.
StringRef visibility;
if (parser.parseOptionalKeyword(&visibility, {"public", "private", "nested"}))
return failure();

StringAttr visibilityAttr = parser.getBuilder().getStringAttr(visibility);
result.addAttribute(SymbolTable::getVisibilityAttrName(), visibilityAttr);

// Parse the rest of the global.
// @<symbol> ( <initializer-attr> ) : <result-type>
StringAttr name;
Expand Down Expand Up @@ -1033,17 +1041,23 @@ void cudaq::cc::GlobalOp::print(OpAsmPrinter &p) {
p << "extern ";
if (getConstant())
p << "constant ";

if (auto visibility = getSymVisibility())
if (visibility.has_value())
p << visibility.value().str() << ' ';

p.printSymbolName(getSymName());
if (auto value = getValue()) {
p << " (";
p.printAttribute(*value);
p << ")";
}
p << " : " << getGlobalType();
p.printOptionalAttrDictWithKeyword(
(*this)->getAttrs(),
{getSymNameAttrName(), getValueAttrName(), getGlobalTypeAttrName(),
getConstantAttrName(), getExternalAttrName()});

p.printOptionalAttrDict((*this)->getAttrs(),
{getSymNameAttrName(), getValueAttrName(),
getGlobalTypeAttrName(), getConstantAttrName(),
getExternalAttrName(), getSymVisibilityAttrName()});
}

//===----------------------------------------------------------------------===//
Expand Down
108 changes: 108 additions & 0 deletions lib/Optimizer/Transforms/DecompositionPatterns.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1181,6 +1181,41 @@ struct RxToPhasedRx : public OpRewritePattern<quake::RxOp> {
}
};

// quake.rx<adj> (θ) target
// ─────────────────────────────────
// quake.rx(-θ) target
struct RxAdjToRx : public OpRewritePattern<quake::RxOp> {
using OpRewritePattern<quake::RxOp>::OpRewritePattern;

void initialize() { setDebugName("RxAdjToRx"); }

LogicalResult matchAndRewrite(quake::RxOp op,
PatternRewriter &rewriter) const override {
if (!op.getControls().empty())
return failure();

if (!op.isAdj())
return failure();

// Op info
Location loc = op->getLoc();
Value target = op.getTarget();
Value angle = op.getParameter();
angle = rewriter.create<arith::NegFOp>(loc, angle);

// Necessary/Helpful constants
SmallVector<Value> noControls;
SmallVector<Value> parameters = {angle};

QuakeOperatorCreator qRewriter(rewriter);
qRewriter.create<quake::RxOp>(loc, parameters, noControls, target);

qRewriter.selectWiresAndReplaceUses(op, target);
rewriter.eraseOp(op);
return success();
}
};

//===----------------------------------------------------------------------===//
// RyOp decompositions
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1267,6 +1302,41 @@ struct RyToPhasedRx : public OpRewritePattern<quake::RyOp> {
}
};

// quake.ry<adj> (θ) target
// ─────────────────────────────────
// quake.ry(-θ) target
struct RyAdjToRy : public OpRewritePattern<quake::RyOp> {
using OpRewritePattern<quake::RyOp>::OpRewritePattern;

void initialize() { setDebugName("RyAdjToRy"); }

LogicalResult matchAndRewrite(quake::RyOp op,
PatternRewriter &rewriter) const override {
if (!op.getControls().empty())
return failure();

if (!op.isAdj())
return failure();

// Op info
Location loc = op->getLoc();
Value target = op.getTarget();
Value angle = op.getParameter();
angle = rewriter.create<arith::NegFOp>(loc, angle);

// Necessary/Helpful constants
SmallVector<Value> noControls;
SmallVector<Value> parameters = {angle};

QuakeOperatorCreator qRewriter(rewriter);
qRewriter.create<quake::RyOp>(loc, parameters, noControls, target);

qRewriter.selectWiresAndReplaceUses(op, target);
rewriter.eraseOp(op);
return success();
}
};

//===----------------------------------------------------------------------===//
// RzOp decompositions
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1364,6 +1434,41 @@ struct RzToPhasedRx : public OpRewritePattern<quake::RzOp> {
}
};

// quake.rz<adj> (θ) target
// ─────────────────────────────────
// quake.rz(-θ) target
struct RzAdjToRz : public OpRewritePattern<quake::RzOp> {
using OpRewritePattern<quake::RzOp>::OpRewritePattern;

void initialize() { setDebugName("RzAdjToRz"); }

LogicalResult matchAndRewrite(quake::RzOp op,
PatternRewriter &rewriter) const override {
if (!op.getControls().empty())
return failure();

if (!op.isAdj())
return failure();

// Op info
Location loc = op->getLoc();
Value target = op.getTarget();
Value angle = op.getParameter();
angle = rewriter.create<arith::NegFOp>(loc, angle);

// Necessary/Helpful constants
SmallVector<Value> noControls;
SmallVector<Value> parameters = {angle};

QuakeOperatorCreator qRewriter(rewriter);
qRewriter.create<quake::RzOp>(loc, parameters, noControls, target);

qRewriter.selectWiresAndReplaceUses(op, target);
rewriter.eraseOp(op);
return success();
}
};

//===----------------------------------------------------------------------===//
// U3Op decompositions
//===----------------------------------------------------------------------===//
Expand Down Expand Up @@ -1449,12 +1554,15 @@ void cudaq::populateWithAllDecompositionPatterns(RewritePatternSet &patterns) {
// RxOp patterns
CRxToCX,
RxToPhasedRx,
RxAdjToRx,
// RyOp patterns
CRyToCX,
RyToPhasedRx,
RyAdjToRy,
// RzOp patterns
CRzToCX,
RzToPhasedRx,
RzAdjToRz,
// Swap
SwapToCX,
// U3Op
Expand Down
2 changes: 2 additions & 0 deletions lib/Optimizer/Transforms/GetConcreteMatrix.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,8 @@ class CustomUnitaryPattern
if (!funcOp)
return failure();

funcOp.setPrivate();

// The generator function returns a concrete matrix. If prior passes have
// run to constant fold and lift array values, the generator function will
// have address of the global variable which holds the concrete matrix.
Expand Down
3 changes: 2 additions & 1 deletion lib/Optimizer/Transforms/StatePreparation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,8 @@ class StateDecomposer {
/// !cc.ptr<!cc.array<complex<f32> x 4>>) -> !quake.veq<2>
/// return
/// }
/// cc.global constant @foo.rodata_0 (dense<[(0.707106769,0.000000e+00),
/// cc.global constant private @foo.rodata_0
/// (dense<[(0.707106769,0.000000e+00),
/// (0.707106769,0.000000e+00), (0.000000e+00,0.000000e+00),
/// (0.000000e+00,0.000000e+00)]> : tensor<4xcomplex<f32>>) :
/// !cc.array<complex<f32> x 4>
Expand Down
10 changes: 8 additions & 2 deletions python/cudaq/kernel/captured_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,10 @@ def storeCudaqState(self, value: cudaq_runtime.State):
globalName = f'nvqpp.cudaq.state.{stateID}'
setStateName = f'nvqpp.set.cudaq.state.{stateID}'
with InsertionPoint.at_block_begin(self.module.body):
cc.GlobalOp(TypeAttr.get(globalTy), globalName, external=True)
cc.GlobalOp(TypeAttr.get(globalTy),
globalName,
sym_visibility=StringAttr.get("private"),
external=True)
setStateFunc = func.FuncOp(setStateName,
FunctionType.get(inputs=[statePtrTy],
results=[]),
Expand Down Expand Up @@ -133,7 +136,10 @@ def storeArray(self, array: np.ndarray):
globalName = f'nvqpp.state.{arrayId}'
setStateName = f'nvqpp.set.state.{arrayId}'
with InsertionPoint.at_block_begin(self.module.body):
cc.GlobalOp(TypeAttr.get(globalTy), globalName, external=True)
cc.GlobalOp(TypeAttr.get(globalTy),
globalName,
sym_visibility=StringAttr.get("private"),
external=True)
setStateFunc = func.FuncOp(setStateName,
FunctionType.get(inputs=[ptrComplex],
results=[]),
Expand Down
6 changes: 3 additions & 3 deletions python/tests/mlir/custom_op_builder.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,6 @@ def register_custom_operations(matrix):
# CHECK: quake.custom_op @__nvqpp__mlirgen__foo_2_generator_1.rodata {{\[}}%[[VAL_4]]] %[[VAL_3]] : (!quake.veq<2>, !quake.veq<1>) -> ()
# CHECK: return
# CHECK: }
# CHECK-DAG: cc.global constant @__nvqpp__mlirgen__foo_0_generator_1.rodata (dense<[{{.*}}]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK-DAG: cc.global constant @__nvqpp__mlirgen__foo_1_generator_1.rodata (dense<[{{.*}}]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK-DAG: cc.global constant @__nvqpp__mlirgen__foo_2_generator_1.rodata (dense<[{{.*}}]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK-DAG: cc.global constant private @__nvqpp__mlirgen__foo_0_generator_1.rodata (dense<[{{.*}}]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK-DAG: cc.global constant private @__nvqpp__mlirgen__foo_1_generator_1.rodata (dense<[{{.*}}]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK-DAG: cc.global constant private @__nvqpp__mlirgen__foo_2_generator_1.rodata (dense<[{{.*}}]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
8 changes: 4 additions & 4 deletions python/tests/mlir/custom_operation.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,8 @@ def bell():
# CHECK: quake.custom_op @__nvqpp__mlirgen__custom_x_generator_1.rodata {{\[}}%[[VAL_1]]] %[[VAL_2]] : (!quake.ref, !quake.ref) -> ()
# CHECK: return
# CHECK: }
# CHECK: cc.global constant @__nvqpp__mlirgen__custom_h_generator_1.rodata (dense<[(0.70710678118654746,0.000000e+00), (0.70710678118654746,0.000000e+00), (0.70710678118654746,0.000000e+00), (-0.70710678118654746,0.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK: cc.global constant @__nvqpp__mlirgen__custom_x_generator_1.rodata (dense<[(0.000000e+00,0.000000e+00), (1.000000e+00,0.000000e+00), (1.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK: cc.global constant private @__nvqpp__mlirgen__custom_h_generator_1.rodata (dense<[(0.70710678118654746,0.000000e+00), (0.70710678118654746,0.000000e+00), (0.70710678118654746,0.000000e+00), (-0.70710678118654746,0.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK: cc.global constant private @__nvqpp__mlirgen__custom_x_generator_1.rodata (dense<[(0.000000e+00,0.000000e+00), (1.000000e+00,0.000000e+00), (1.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>


def test_custom_adjoint():
Expand Down Expand Up @@ -64,5 +64,5 @@ def kernel():
# CHECK: quake.h %[[VAL_0]] : (!quake.ref) -> ()
# CHECK: return
# CHECK: }
# CHECK: cc.global constant @__nvqpp__mlirgen__custom_s_generator_1.rodata (dense<[(1.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00), (0.000000e+00,1.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK: cc.global constant @__nvqpp__mlirgen__custom_s_adj_generator_1.rodata (dense<[(1.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00), (-0.000000e+00,-1.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK: cc.global constant private @__nvqpp__mlirgen__custom_s_generator_1.rodata (dense<[(1.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00), (0.000000e+00,1.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4>
# CHECK: cc.global constant private @__nvqpp__mlirgen__custom_s_adj_generator_1.rodata (dense<[(1.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00), (0.000000e+00,0.000000e+00), (-0.000000e+00,-1.000000e+00)]> : tensor<4xcomplex<f64>>) : !cc.array<complex<f64> x 4
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ config:
# Tell NVQ++ to generate glue code to set the target backend name
gen-target-backend: true
# Define the lowering pipeline
platform-lowering-config: "func.func(const-prop-complex,canonicalize,cse,lift-array-alloc),globalize-array-values,state-prep,unitary-synthesis,canonicalize,apply-op-specialization,aggressive-early-inlining,unrolling-pipeline,func.func(lower-to-cfg),canonicalize,func.func(multicontrol-decomposition),func.func(memtoreg{quantum=0}),symbol-dce"
platform-lowering-config: "func.func(const-prop-complex,canonicalize,cse,lift-array-alloc),globalize-array-values,state-prep,unitary-synthesis,canonicalize,apply-op-specialization,aggressive-early-inlining,unrolling-pipeline,func.func(lower-to-cfg),canonicalize,func.func(multicontrol-decomposition),decomposition{enable-patterns=CCZToCX,RxAdjToRx,RyAdjToRy,RzAdjToRz},func.func(memtoreg{quantum=0}),symbol-dce"
# Tell the rest-qpu that we are generating OpenQASM 2.0.
codegen-emission: qasm2
# Library mode is only for simulators, physical backends must turn this off
Expand Down
Loading

0 comments on commit d07fa84

Please sign in to comment.