This document give a high-level overview of the CUDA-Q codebase. If you want to familiarize yourself with the code on this repository, this is the document for you.
CUDA-Q is first-and-foremost a heterogeneous quantum-classical programming model in modern C++. The model enables programmers to define typed-callables (implicit or explicit) that encodes some action to be executed on an available quantum coprocessor.
To implement this model, this repository provides an MLIR-based compiler. The compiler maps the C++ abstract syntax tree (AST) generated by Clang to internal MLIR dialects for quantum and classical computing. These dialects are further lowered to LLVM adherent to the Quantum Intermediate Representation (QIR) specification which can be readily lowered to object code.
The quantum-specific dialect put forward by this repository is the Quantum Kernel Execution (Quake). Quake sits closer to the source language and provides a memory-semantics model of qubits and operations on those qubits. Quake can encode runtime-known information, and is therefore a generator of concrete quantum circuits. Quake also supports a value-semantics model of quantum computing whereby quantum operations consume qubit values and produce a new qubit value. Quake is therefore well suited for optimizations and can encode fully-known, concrete quantum circuits.
We also provide a dialect for classical computing abstractions, specifically modeling types and operations in C++ required to build Quake functions. This is the CC dialect.
The dialects for Quake and CC are defined in
We have designed the compiler to be modular, and the compiler workflow itself is composed of a set of tools (executables) that achieve a specific task.
This folder contains the header files for the AST Bridge. The AST Bridge is
responsible for mapping C++ to Quake MLIR via the Clang abstract syntax tree.
Specifically, ASTBridge.h
contains a subtype of the
clang::RecursiveASTVisitor<T>
that enables one to visit the various nodes of
the AST and perform custom actions based on the data in the node. We keep track
of a RecursiveASTVisitor
which contains an mlir::ModuleOp
member, which we
build up with Quake and classical MLIR operations.
This folder contains the header files defining the MLIR dialects and
transformations used by CUDA-Q. The Dialect
folder contains the tablegen
definitions for Quake and CC. The CodeGen
folder declares the tablegen
required to define MLIR Passes that lower Quake to code, specifically LLVM IR.
The Transforms
folder contains the tablegen necessary for transformations on
Quake and CC (e.g. things like lambda lifting, generating extra kernel glue
code, etc.).
This folder contains the headers for taking Quake to other quantum programming languages like OpenQASM.
This folder contains the implementation code for the RecursiveASTVisitor
that
maps C++ to Quake. Separate implementation files are defined for translating
Clang Expr
, Stmt
, and Decl
types.
This folder contains the implementation code for the MLIR dialects and
transformations used by the compiler. The structure here is pretty
self-explanatory. The dialect implementation is in the Dialect
folder (for
Quake and CC). All transformations on the IR are provided in the Transforms
folder. Conversions between dialects are in the Conversion
folder. The passes
that lower MLIR to LLVM IR code are provided in the CodeGen
folder.
This folder contains the implementation code for mapping Quake to other quantum programming languages.
This folder contains the code for the cudaq-common
library. This library is
used by the other runtime libraries and provides the MeasureCounts
,
ObserveResult
, ExecutionContext
, and logging utility types.
This folder contains the code for a library that implements the QIR
specification. libnvqir
implements the specified QIR QIS and runtime functions
and delegates to an extensible CircuitSimulator
API. This API is implemented
for CPU-only simulation (OpenMP multi-threaded) and GPU-based simulation via
cuQuantum. Switching the backend simulation capability is a link-time task that
is handled implicitly by nvq++
.
This folder contains the CUDA-Q runtime library. The headers in this folder
directly implement the CUDA-Q specification, and in doing so, enables the
nvq++
compiler to generate a full, valid Clang AST that can be processed and
lowered the the MLIR. Moreover, by implementing the specification types and
functions, we are able to use this library to enforce aspects of the
specification at compile time. For example, the specification says that qubits
can not be copied, therefore this runtime library defines the qubit type with a
deleted copy constructor. Any violations of this aspect of the specification
will trigger a standard compiler error. We therefore pick-up existing compiler
diagnostics infrastructures for free.
Specifically, this library provides the qudit
, qubit
, qreg
, and qspan
types, the intrinsic quantum operations, and the algorithmic primitives like
cudaq::sample
and cudaq::observe
.
This library defines the cudaq::spin_op
for defining general Pauli tensor
product terms.
This library defines the quantum_platform
architecture, enabling CUDA-Q to
target both simulated and physical quantum computing architectures.
This folder contains the implementation of the cudaq-quake
tool. This tool
orchestrates the creation of the RecursiveASTVisitor
that walks the Clang AST
representation of input source file and outputs a Quake file for all CUDA-Q
kernels in the code. It will also output the classical LLVM IR representation of
the code (with the CUDA-Q runtime headers) with the specification of the
--emit-llvm-file
flag.
This folder contains the implementation of the cudaq-opt
tool. This tool takes
as input a Quake file, an apply MLIR passes specified by the user as another
command line option (the --pass-pipeline
flag).
This folder contains the implementation of the cudaq-translate
tool. This tool
takes as input a Quake file and lowers that representation to QIR or Base
Profile QIR.
This folder contains the nvq++
compiler tool. This tool is a bash script that
orchestrates the workflow necessary to map CUDA-Q C++ to MLIR and ultimately
down to executable code.
The script does the following:
- Map CUDA-Q C++ kernels to Quake MLIR code via a Clang
ASTConsumer
- Register all Quake kernel code with the runtime for quantum IR introspection
- Rewrite the original CUDA-Q C++ kernel entry-point function to invoke an
internal runtime kernel launch function which targets the specified
quantum_platform
- Lower to QIR and link, producing an executable or object code