Skip to content

Commit 65754dc

Browse files
committed
✨ Add GateTable header and implement gate conversion utilities
This commit introduces a new header file `GateTable.h` that serves as a central registry for supported gates in MLIR conversions. It defines enums for Jeff and QIR lowering kinds, a structure for Pauli gate encoding, and a macro-based central gate table for conversions. Additionally, it updates various conversion files to include this new header, facilitating the use of the gate table in conversion patterns. New unit tests are added to ensure the functionality of the gate table and its integration into the conversion processes. - Introduced `GateTable.h` for gate registry and encoding. - Updated conversion files to utilize the new gate table. - Added unit tests for gate table functionality. Fixes #1604.
1 parent e209bda commit 65754dc

9 files changed

Lines changed: 1541 additions & 1753 deletions

File tree

Lines changed: 207 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
/*
2+
* Copyright (c) 2023 - 2026 Chair for Design Automation, TUM
3+
* Copyright (c) 2025 - 2026 Munich Quantum Software Company GmbH
4+
* All rights reserved.
5+
*
6+
* SPDX-License-Identifier: MIT
7+
*
8+
* Licensed under the MIT License
9+
*/
10+
11+
#pragma once
12+
13+
/**
14+
* @file GateTable.h
15+
* @brief Central gate registry for MLIR conversions.
16+
*
17+
* @details
18+
* This header defines a single source of truth for the set of supported gates
19+
* across the conversion passes in `mlir/lib/Conversion/`.
20+
*
21+
* The registry is provided as an X-macro table so it can be consumed in
22+
* multiple translation units without introducing ODR issues.
23+
*
24+
* Each entry specifies:
25+
* - a canonical gate key (identifier),
26+
* - number of targets,
27+
* - number of parameters,
28+
* - the corresponding QCO/QC op types,
29+
* - Jeff lowering kind,
30+
* - QIR function-name selector.
31+
*
32+
* Conversions can consume this table to automatically derive target/parameter
33+
* counts and stay consistent across backends.
34+
*/
35+
36+
#include <cstddef>
37+
#include <cstdint>
38+
39+
namespace mlir::mqt::gates {
40+
41+
/** @brief Jeff lowering kind for a gate entry. */
42+
enum class JeffKind : std::uint8_t {
43+
Native, //!< Dedicated Jeff op exists.
44+
Custom, //!< Lower to jeff.custom with a name string.
45+
PPR, //!< Lower to jeff.ppr with Pauli-gate encoding.
46+
SpecialU2ToU, //!< Lower qco.u2 via jeff.u with injected theta=pi/2.
47+
};
48+
49+
/** @brief QIR lowering kind for a gate entry. */
50+
enum class QIRKind : std::uint8_t {
51+
Unitary, //!< Lower to a QIR runtime call (name depends on num ctrls).
52+
Unsupported, //!< Not supported in QC-to-QIR lowering.
53+
};
54+
55+
/**
56+
* @brief Pauli gate encoding used for jeff.ppr.
57+
*
58+
* @details
59+
* Encoding matches existing QCO<->Jeff conversion logic:
60+
* 1=X, 2=Y, 3=Z.
61+
*/
62+
struct PPRPaulis {
63+
std::int32_t p0 = 0;
64+
std::int32_t p1 = 0;
65+
};
66+
67+
// Helper macros to keep `MQT_GATE_TABLE` macro-friendly.
68+
#define MQT_PPR(P0, P1) \
69+
::mlir::mqt::gates::PPRPaulis { (P0), (P1) }
70+
#define MQT_PPR_NONE MQT_PPR(0, 0)
71+
72+
/**
73+
* @brief Central gate table.
74+
*
75+
* @details
76+
* The table is intentionally limited to the gates currently supported by all
77+
* relevant conversions in this repository.
78+
*
79+
* Columns:
80+
* - KEY: canonical identifier
81+
* - TARGETS: number of target qubits
82+
* - PARAMS: number of floating parameters
83+
* - QCO_OP: QCO op type
84+
* - QC_OP: QC op type
85+
* - JEFF_KIND: JeffKind
86+
* - JEFF_OP: Jeff op type (only for Native/SpecialU2ToU; otherwise void)
87+
* - JEFF_BASE_ADJOINT: whether the base gate is adjoint (e.g. Sdg, Tdg, SXdg)
88+
* - JEFF_CUSTOM_NAME: identifier token for custom op name (only for Custom)
89+
* - JEFF_PPR: PPRPaulis (only for PPR; otherwise {0,0})
90+
* - QIR_KIND: QIRKind
91+
* - QIR_FN: function-name selector for the QC-to-QIR lowering (unitary only)
92+
*
93+
* @details Jeff adjoint encoding for custom gates
94+
* Some gates are represented in Jeff as `jeff.custom "<name>"` and the
95+
* adjointness is carried in the Jeff op attribute `is_adjoint`. For such gates,
96+
* `JEFF_BASE_ADJOINT` indicates whether the *unmodified* QCO/QC gate already
97+
* corresponds to the adjoint of the canonical Jeff base gate. A prominent
98+
* example is `SXdg`, which shares the Jeff custom name `"sx"` but is inherently
99+
* adjoint compared to `SX`. Conversions must avoid double-encoding adjointness
100+
* (i.e., they must not flip `is_adjoint` twice).
101+
*/
102+
#define MQT_GATE_TABLE(ENTRY) \
103+
ENTRY(Id, 1, 0, ::mlir::qco::IdOp, ::mlir::qc::IdOp, \
104+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::IOp, false, _, \
105+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
106+
::mlir::qir::getFnNameI) \
107+
ENTRY(X, 1, 0, ::mlir::qco::XOp, ::mlir::qc::XOp, \
108+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::XOp, false, _, \
109+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
110+
::mlir::qir::getFnNameX) \
111+
ENTRY(Y, 1, 0, ::mlir::qco::YOp, ::mlir::qc::YOp, \
112+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::YOp, false, _, \
113+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
114+
::mlir::qir::getFnNameY) \
115+
ENTRY(Z, 1, 0, ::mlir::qco::ZOp, ::mlir::qc::ZOp, \
116+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::ZOp, false, _, \
117+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
118+
::mlir::qir::getFnNameZ) \
119+
ENTRY(H, 1, 0, ::mlir::qco::HOp, ::mlir::qc::HOp, \
120+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::HOp, false, _, \
121+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
122+
::mlir::qir::getFnNameH) \
123+
ENTRY(S, 1, 0, ::mlir::qco::SOp, ::mlir::qc::SOp, \
124+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::SOp, false, _, \
125+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
126+
::mlir::qir::getFnNameS) \
127+
ENTRY(Sdg, 1, 0, ::mlir::qco::SdgOp, ::mlir::qc::SdgOp, \
128+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::SOp, true, _, \
129+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
130+
::mlir::qir::getFnNameSDG) \
131+
ENTRY(T, 1, 0, ::mlir::qco::TOp, ::mlir::qc::TOp, \
132+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::TOp, false, _, \
133+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
134+
::mlir::qir::getFnNameT) \
135+
ENTRY(Tdg, 1, 0, ::mlir::qco::TdgOp, ::mlir::qc::TdgOp, \
136+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::TOp, true, _, \
137+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
138+
::mlir::qir::getFnNameTDG) \
139+
ENTRY(P, 1, 1, ::mlir::qco::POp, ::mlir::qc::POp, \
140+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::R1Op, false, _, \
141+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
142+
::mlir::qir::getFnNameP) \
143+
ENTRY(RX, 1, 1, ::mlir::qco::RXOp, ::mlir::qc::RXOp, \
144+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::RxOp, false, _, \
145+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
146+
::mlir::qir::getFnNameRX) \
147+
ENTRY(RY, 1, 1, ::mlir::qco::RYOp, ::mlir::qc::RYOp, \
148+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::RyOp, false, _, \
149+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
150+
::mlir::qir::getFnNameRY) \
151+
ENTRY(RZ, 1, 1, ::mlir::qco::RZOp, ::mlir::qc::RZOp, \
152+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::RzOp, false, _, \
153+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
154+
::mlir::qir::getFnNameRZ) \
155+
ENTRY(R, 1, 2, ::mlir::qco::ROp, ::mlir::qc::ROp, \
156+
::mlir::mqt::gates::JeffKind::Custom, void, false, r, MQT_PPR_NONE, \
157+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameR) \
158+
ENTRY(U2, 1, 2, ::mlir::qco::U2Op, ::mlir::qc::U2Op, \
159+
::mlir::mqt::gates::JeffKind::SpecialU2ToU, ::mlir::jeff::UOp, false, \
160+
_, MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
161+
::mlir::qir::getFnNameU2) \
162+
ENTRY(U, 1, 3, ::mlir::qco::UOp, ::mlir::qc::UOp, \
163+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::UOp, false, _, \
164+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
165+
::mlir::qir::getFnNameU) \
166+
ENTRY(SX, 1, 0, ::mlir::qco::SXOp, ::mlir::qc::SXOp, \
167+
::mlir::mqt::gates::JeffKind::Custom, void, false, sx, MQT_PPR_NONE, \
168+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameSX) \
169+
ENTRY(SXdg, 1, 0, ::mlir::qco::SXdgOp, ::mlir::qc::SXdgOp, \
170+
::mlir::mqt::gates::JeffKind::Custom, void, true, sx, MQT_PPR_NONE, \
171+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameSXDG) \
172+
ENTRY(SWAP, 2, 0, ::mlir::qco::SWAPOp, ::mlir::qc::SWAPOp, \
173+
::mlir::mqt::gates::JeffKind::Native, ::mlir::jeff::SwapOp, false, _, \
174+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
175+
::mlir::qir::getFnNameSWAP) \
176+
ENTRY(iSWAP, 2, 0, ::mlir::qco::iSWAPOp, ::mlir::qc::iSWAPOp, \
177+
::mlir::mqt::gates::JeffKind::Custom, void, false, iswap, \
178+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
179+
::mlir::qir::getFnNameISWAP) \
180+
ENTRY(DCX, 2, 0, ::mlir::qco::DCXOp, ::mlir::qc::DCXOp, \
181+
::mlir::mqt::gates::JeffKind::Custom, void, false, dcx, MQT_PPR_NONE, \
182+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameDCX) \
183+
ENTRY(ECR, 2, 0, ::mlir::qco::ECROp, ::mlir::qc::ECROp, \
184+
::mlir::mqt::gates::JeffKind::Custom, void, false, ecr, MQT_PPR_NONE, \
185+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameECR) \
186+
ENTRY(RXX, 2, 1, ::mlir::qco::RXXOp, ::mlir::qc::RXXOp, \
187+
::mlir::mqt::gates::JeffKind::PPR, void, false, _, MQT_PPR(1, 1), \
188+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameRXX) \
189+
ENTRY(RYY, 2, 1, ::mlir::qco::RYYOp, ::mlir::qc::RYYOp, \
190+
::mlir::mqt::gates::JeffKind::PPR, void, false, _, MQT_PPR(2, 2), \
191+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameRYY) \
192+
ENTRY(RZX, 2, 1, ::mlir::qco::RZXOp, ::mlir::qc::RZXOp, \
193+
::mlir::mqt::gates::JeffKind::PPR, void, false, _, MQT_PPR(3, 1), \
194+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameRZX) \
195+
ENTRY(RZZ, 2, 1, ::mlir::qco::RZZOp, ::mlir::qc::RZZOp, \
196+
::mlir::mqt::gates::JeffKind::PPR, void, false, _, MQT_PPR(3, 3), \
197+
::mlir::mqt::gates::QIRKind::Unitary, ::mlir::qir::getFnNameRZZ) \
198+
ENTRY(XXPlusYY, 2, 2, ::mlir::qco::XXPlusYYOp, ::mlir::qc::XXPlusYYOp, \
199+
::mlir::mqt::gates::JeffKind::Custom, void, false, xx_plus_yy, \
200+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
201+
::mlir::qir::getFnNameXXPLUSYY) \
202+
ENTRY(XXMinusYY, 2, 2, ::mlir::qco::XXMinusYYOp, ::mlir::qc::XXMinusYYOp, \
203+
::mlir::mqt::gates::JeffKind::Custom, void, false, xx_minus_yy, \
204+
MQT_PPR_NONE, ::mlir::mqt::gates::QIRKind::Unitary, \
205+
::mlir::qir::getFnNameXXMINUSYY)
206+
207+
} // namespace mlir::mqt::gates

0 commit comments

Comments
 (0)