2. 量子指令集与中间表示

量子编译器前端面对的第一类工程问题,不是“如何优化”,而是“用什么语言描述量子程序”。量子指令集与中间表示(IR)承担着把人类可读的量子算法,逐步翻译为硬件可执行脉冲或门序列的职责。不同 IR 的设计动机差异很大:有的面向文本可读性与教学,有的面向经典-量子混合编译,有的面向硬件时序控制。理解它们的语法语义与互操作边界,是搭建量子软件栈的基础。

四类主流 IR 的定位差异

OpenQASM 是最接近“量子汇编”的文本 IR。它以 qreg、creg 声明量子与经典寄存器,用 h q[0];、cx q[0],q[1]; 这类语句描述门操作,并支持 measure、reset、barrier 等指令。OpenQASM 2.0 语义简单、易解析,但缺少经典控制流与作用域;OpenQASM 3.0 引入了 if、for、while、子程序与类型系统,使其能表达带经典反馈的混合程序。它的设计动机是“可读、可交换、可被工具链消费”。

QIR(Quantum Intermediate Representation) 建立在 LLVM IR 之上,用 %Qubit*、%Result* 等类型和 __quantum__qis__h、__quantum__qis__mz 等内在函数表示量子操作。它的核心动机是复用 LLVM 的优化、链接与多后端能力,让量子程序与经典代码在同一编译框架内协同。QIR 不追求人类直接书写,而是作为编译器之间的“通用货币”。

Quil 由 Rigetti 提出,语法上以 H 0、CNOT 0 1、MEASURE 0 ro[0] 为基本形式,并支持 DEFGATE 自定义门、DEFCIRCUIT 电路宏以及 PRAGMA 元数据。它的设计动机是兼顾硬件控制与可扩展性,尤其适合表达参数化门与脉冲级指令。

eQASM 则更贴近量子控制处理器(QCP)的指令集,强调精确时序、触发与反馈。它把量子操作、经典寄存器操作和时序控制统一到一条指令流中,设计动机是“让硬件直接执行”,而非作为高层交换格式。

量子 IR 分层与互操作路径 高层算法描述 文本交换 IR 编译器 IR 硬件控制 IR OpenQASM 2.0 / 3.0 qreg / creg / h / cx / measure 3.0 支持 if / for / 子程序 Quil H 0 / CNOT 0 1 / MEASURE DEFGATE / DEFCIRCUIT / PRAGMA QIR (LLVM-based) %Qubit* / %Result* __quantum__qis__h / __mz eQASM 量子操作 + 时序 + 触发 面向 QCP 直接执行 量子处理器 / 脉冲 微波脉冲 / 激光 / 门序列 物理量子比特 编译 / 降级 编译 / 降级 互操作 下发执行 互操作 互操作关键点: • OpenQASM ↔ Quil:通过门集映射与寄存器重命名转换,保留 measure 语义。 • OpenQASM → QIR:将 qreg/creg 映射为 %Qubit*/%Result*,门映射为 __quantum__qis__ 内在函数。 • QIR → eQASM:LLVM 后端将量子内在函数降级为带时序的硬件指令。

语法语义的关键差异

从语义层面看,四类 IR 对“量子态”和“经典信息”的处理方式不同。OpenQASM 2.0 中,qreg q[3]; 声明一个 3 量子比特寄存器,门操作直接作用于索引;测量结果写入 creg c[3];,但 2.0 不允许根据测量结果动态控制后续门。OpenQASM 3.0 则允许 if (c[0] == 1) x q[1];,这使量子纠错、反馈控制等程序可以被直接表达。

QIR 的语义建立在 LLVM 的 SSA 形式上。每个量子比特是一个不透明指针 %Qubit*,测量返回 %Result*,再通过 __quantum__rt__result_equal 等运行时函数比较结果。这种设计让经典控制流天然可用,因为 LLVM 本身就支持分支、循环和函数调用。代价是 QIR 程序难以手工阅读,通常由 Clang 或 Q# 编译器生成。

Quil 的语义特点是“指令即操作”。MEASURE 0 ro[0] 把量子比特 0 的测量结果写入经典寄存器 ro[0],而 DEFCIRCUIT 允许把常用门序列封装为宏,在编译时展开。Quil 还支持 PRAGMA 指令,用于向编译器或硬件传递元信息,例如 PRAGMA INITIAL_REWIRING "NAIVE" 可指定初始映射策略。

eQASM 的语义更接近微码。它把“何时执行”“执行什么”“结果写到哪里”编码在同一条指令中,并显式管理触发信号与等待周期。例如,一条 eQASM 指令可能同时包含“在 t=20ns 触发 X 门”和“等待反馈结果后条件执行 Z 门”。这种语义适合实时反馈,但可移植性较差。

互操作的实际做法

在实际工具链中,互操作通常发生在“门集映射”和“寄存器重命名”两个层面。以 OpenQASM 转 Quil 为例,假设输入为:

OPENQASM 2.0;
include "qelib1.inc";
qreg q[2];
creg c[2];
h q[0];
cx q[0],q[1];
measure q[0] -> c[0];
measure q[1] -> c[1];

转换到 Quil 时,需要把 qreg q[2] 映射为 DECLARE ro BIT[2],把 h q[0] 映射为 H 0,把 cx q[0],q[1] 映射为 CNOT 0 1,测量则映射为 MEASURE 0 ro[0] 和 MEASURE 1 ro[1]。转换后的 Quil 程序为:

DECLARE ro BIT[2]
H 0
CNOT 0 1
MEASURE 0 ro[0]
MEASURE 1 ro[1]

如果目标后端是 QIR,则同一段 OpenQASM 会先被解析为 AST,再生成 LLVM IR:q[0] 和 q[1] 变为两个 %Qubit*,h 变为 call void @__quantum__qis__h(%Qubit* %q0),cx 变为 call void @__quantum__qis__cx(%Qubit* %q0, %Qubit* %q1),测量则调用 __quantum__qis__mz 并返回 %Result*。这种转换保留了经典控制流的扩展空间。

互操作检查清单:
  • 门集是否一致?目标 IR 是否支持源 IR 中的全部门?不支持时需先做门分解。
  • 寄存器模型是否匹配?量子寄存器与经典寄存器的位宽、索引方式是否对齐。
  • 测量语义是否保留?测量后的经典结果是否被正确写入目标 IR 的经典寄存器。
  • 控制流是否可表达?若源程序含 if 或循环,目标 IR 是否支持经典控制。
  • 元数据是否丢失?如 barrier、PRAGMA、时序约束等是否需要在目标 IR 中重建。

设计动机背后的工程取舍

选择哪种 IR,本质上是在“可读性、可优化性、可移植性、硬件贴近度”之间做取舍。OpenQASM 优先可读性与交换性,适合作为教学与算法交换格式;QIR 优先可优化性与经典-量子协同,适合作为编译器中间层;Quil 优先硬件控制与宏扩展,适合表达参数化电路;eQASM 优先实时性与时序精度,适合作为控制处理器的指令集。

在量子编译器架构中,常见的做法是“多前端、单中间层、多后端”。前端接受 OpenQASM、Quil 或 Q#,统一降级到 QIR 或自定义 IR,再根据目标硬件生成 eQASM 或脉冲序列。这样既保留了各前端的表达优势,又避免了为每种语言单独实现全部优化。理解这些 IR 的语法语义与互操作边界,是设计量子软件栈时不可跳过的一步。