forked from NVIDIA/cuda-quantum
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathPasses.td
More file actions
275 lines (228 loc) · 10.5 KB
/
Passes.td
File metadata and controls
275 lines (228 loc) · 10.5 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
/********************************************************** -*- tablegen -*- ***
* Copyright (c) 2022 - 2025 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. *
******************************************************************************/
#ifndef CUDAQ_OPT_OPTIMIZER_CODEGEN_PASSES
#define CUDAQ_OPT_OPTIMIZER_CODEGEN_PASSES
include "mlir/Pass/PassBase.td"
def QuakeToCC : Pass<"quake-to-cc", "mlir::ModuleOp"> {
let summary = "Lower Quake to CC.";
let description = [{
Converts Quake to CC. The `add-dealloc` pass should be run before this pass
in order to properly generate deallocations for allocated qubits.
This is the second of 2 passes to lower quake code to cc code. The
`quake-to-cc-prep` pass must be run first. After these passes the code will
be in the CC dialect, with calls back to the runtime, specifically the
execution manager.
}];
let dependentDialects = ["cudaq::cc::CCDialect", "mlir::LLVM::LLVMDialect"];
}
def QuakeToCCPrep : Pass<"quake-to-cc-prep", "mlir::ModuleOp"> {
let summary = "Prepare for lowering Quake to CC.";
let description = [{
Do the preparation work on the module. This pass must be run before the
`quake-to-cc` pass is run.
}];
let dependentDialects = ["cudaq::cc::CCDialect"];
}
def CCToLLVM : Pass<"cc-to-llvm", "mlir::ModuleOp"> {
let summary = "Convert CC dialect (and others) to LLVM-IR.";
let description = [{
Complete the conversion of modules from 'CC dialect' to LLVM-IR dialect.
This is the final step before generating LLVM code. It would typically be
used after `-quake-to-cc` when a simulator is the target.
}];
let dependentDialects = [
"cudaq::codegen::CodeGenDialect", "mlir::LLVM::LLVMDialect"
];
}
def ConvertToQIR : Pass<"quake-to-qir", "mlir::ModuleOp"> {
let summary = "Lower Quake to QIR.";
let description = [{
Converts Quake to QIR (as LLVM-IR). The add-dealloc pass should be run
before this pass in order to properly generate deallocations for allocated
QIR qubits.
}];
let dependentDialects = [
"cudaq::codegen::CodeGenDialect", "mlir::LLVM::LLVMDialect"
];
}
def LowerToCG : Pass<"lower-to-cg", "mlir::ModuleOp"> {
let summary = "Lower Quake to CG dialect.";
let description = [{
Lower the Quake IR to the codegen dialect. The codegen dialect is used to
fuse small DAGs of IR into larger macro operations just prior to the final
codegen. This allows conversions to take place on the macro operations and
avoid some of the limitations of an MLIR conversion pass.
}];
let dependentDialects = [ "cudaq::codegen::CodeGenDialect" ];
}
def QIRToQIRProfilePrep : Pass<"qir-profile-prep", "mlir::ModuleOp"> {
let summary =
"Prepare the IR for rewriting to the base profile or adaptive profile";
let description = [{
This is a (module) subpass of the pipeline to convert to a specific QIR
Profile.
Before we can convert the functions to the specific profile, we have to do
a bit of bookkeeping on the module itself. That preparation is done in
this pass. Specifically, we create all the function declarations that we
may need and add them to the ModuleOp a priori. This avoids multi-threading
conflicts when rewriting matching DAGs independently.
}];
let constructor = "cudaq::opt::createQIRProfilePreparationPass()";
}
def QIRToQIRProfileFunc : Pass<"quake-to-qir-func",
"mlir::LLVM::LLVMFuncOp"> {
let summary = "Analyze kernels and add attributes and record calls.";
let description = [{
This is a (function) subpass of the pipeline to convert to specific QIR
Profile.
Each function with a body is analyzed for qubit allocations and qubit
measurements. Attributes for the total count of qubits are added to the
LLVMFuncOp. Additionally, measurements are collected and recording marker
functions are added to the final block in the function.
}];
let options = [
Option<"convertTo", "convert-to", "std::string", /*default=*/"\"qir-base\"",
"Which QIR profile to convert to (default is 'qir-base')">
];
let constructor = "cudaq::opt::createConvertToQIRFuncPass(\"qir-base\")";
}
def QIRToQIRProfile : Pass<"convert-to-qir-profile"> {
let summary =
"Lower full QIR further to the specific QIR Profile.";
let description = [{
This is run after lowering a Quake kernel to full QIR.
This is a subpass of the pipeline to convert to the specific QIR Profile.
This pass lowers various QIR DAGs to the specific QIR Profile. See
https://github.com/qir-alliance/qir-spec/blob/main/specification/v0.1/7_Profiles.md
}];
let options = [
Option<"convertTo", "convert-to", "std::string", "\"qir-base\"",
"Which QIR profile to convert to (default is 'qir-base')">
];
let constructor = "cudaq::opt::createQIRToQIRProfilePass(\"qir-base\")";
}
def RemoveMeasurements : Pass<"remove-measurements"> {
let summary =
"Remove measurements and output recording calls from a QIR program";
let description = [{
Some backends perform implicit measurements on all qubits at the end of the
kernel, which is a distinct problem for compiler-generated qubits (as is
done in the multicontrol-decomposition pass) because the user cannot tell
the difference between measurement results for their qubits and measurement
results for compiler-generated qubits. This pass enables the compiler to
strip out the measurements and output recording calls from a QIR program to
prevent that problem. This pass MUST be run after normal measurements and
output recording calls have been generated because that metadata must be
extracted from the program to allow reconstruction of the outputs from the
backend.
}];
}
def VerifyNVQIRCallOps :
Pass<"verify-nvqir-call-ops", "mlir::LLVM::LLVMFuncOp"> {
let summary =
"Verify that all LLVM CallOps' callees are NVQIR compliant";
let description = [{
This is a function pass to verify that all function calls within the
function body are referring to pre-defined allowed functions or QIR
functions, i.e., starting with a __quantum prefix, or NVQIR runtime
functions.
}];
let options = [
ListOption<"allowedFuncs", "allowed-funcs", "llvm::StringRef",
"Allowed list of functions in addition to NVQIR-defined function.">
];
let constructor = "cudaq::opt::createVerifyNVQIRCallOpsPass({})";
}
def VerifyQIRProfile : Pass<"verify-qir-profile", "mlir::LLVM::LLVMFuncOp"> {
let summary = "Verify that the output conforms to the specific profile";
let description = [{
This pass scans over functions in the LLVM-IR dialect to make sure they
conform to the QIR specific profile.
}];
let options = [
Option<"convertTo", "convert-to", "std::string", "\"qir-base\"",
"Which QIR profile to convert to (default is 'qir-base')">
];
}
def WireSetToProfileQIR : Pass<"wireset-to-profile-qir", "mlir::func::FuncOp"> {
let summary = "Convert quake using wire sets to a profile of QIR";
let description = [{
This pass takes quake in "value semantics" form and after it has been
converted to use wire sets (qubit management, mapping, etc.) and converts
the code to CC dialect with QIR calls, etc.
}];
let dependentDialects = ["cudaq::cc::CCDialect", "mlir::LLVM::LLVMDialect"];
let options = [
Option<"convertTo", "convert-to", "std::string", /*default=*/"\"qir-base\"",
"Select the profile to convert wire sets to.">
];
}
def WireSetToProfileQIRPost :
Pass<"wireset-to-profile-qir-post", "mlir::ModuleOp"> {
let summary = "Post processing for lowering wire sets to a profile of QIR";
let description = [{
This pass should be run immediately after wireset-to-profile-qir.
}];
let dependentDialects = ["cudaq::cc::CCDialect", "mlir::func::FuncDialect"];
}
def WireSetToProfileQIRPrep :
Pass<"wireset-to-profile-qir-prep", "mlir::ModuleOp"> {
let summary = "Prepare for lowering wire sets to a profile of QIR";
let description = [{
This pass should be run immediately before wireset-to-profile-qir.
}];
let dependentDialects = ["cudaq::cc::CCDialect", "mlir::func::FuncDialect"];
}
def QuakeToQIRAPI : Pass<"quake-to-qir-api"> {
let summary = "Convert the Quake dialect to the QIR API.";
let description = [{
This pass converts Quake operations to the QIR API as expressed in terms
of function calls to QIR functions.
Which QIR functions are to be used is parameterized on the `api` option.
This pass can lower to either use the obsolete opaque structure types (per
the QIR spec) or to use LLVM's currently supported opaque pointers. In the
latter case, type information is fully understood from the function names
themselves.
}];
let dependentDialects = ["cudaq::cc::CCDialect", "mlir::arith::ArithDialect",
"mlir::cf::ControlFlowDialect", "mlir::func::FuncDialect",
"mlir::LLVM::LLVMDialect"];
let options = [
Option<"api", "api", "std::string", /*default=*/"\"full\"",
"Select the QIR API to use.">,
Option<"opaquePtr", "opaque-pointer", "bool", /*default=*/"false",
"Use opaque pointers.">
];
}
def QuakeToQIRAPIFinal : Pass<"quake-to-qir-api-final", "mlir::ModuleOp"> {
let summary = "Convert the Quake dialect to the QIR API finalization.";
let description = [{
}];
let dependentDialects = ["cudaq::cc::CCDialect", "mlir::arith::ArithDialect",
"mlir::cf::ControlFlowDialect", "mlir::func::FuncDialect",
"mlir::LLVM::LLVMDialect"];
let options = [
Option<"api", "api", "std::string", /*default=*/"\"full\"",
"Select the QIR API to use.">
];
}
def QuakeToQIRAPIPrep : Pass<"quake-to-qir-api-prep", "mlir::ModuleOp"> {
let summary = "Convert the Quake dialect to the QIR API preparation.";
let description = [{
}];
let dependentDialects = ["cudaq::cc::CCDialect", "mlir::arith::ArithDialect",
"mlir::cf::ControlFlowDialect", "mlir::func::FuncDialect",
"mlir::LLVM::LLVMDialect", "cudaq::codegen::CodeGenDialect"];
let options = [
Option<"api", "api", "std::string", /*default=*/"\"full\"",
"Select the QIR API to use.">,
Option<"opaquePtr", "opaque-pointer", "bool", /*default=*/"false",
"Use opaque pointers.">
];
}
#endif // CUDAQ_OPT_OPTIMIZER_CODEGEN_PASSES