Quantum compute on RISC-V emulator(Spike)
RISC-VのエミュレーターとしてSpikeを使って、命令セットの拡張と実装を行ってみました。Spikeは見たところ、RISC-Vをターゲットにしているため非常にシンプルな実装になっていて改造も簡単そうです。命令セットの改造にはこちらの例が非常に参考になりました。
Spikeへの量子系の命令セットを追加する前に少し考えることが出てきました。
1. エミュレーター起動時に量子ビット数を与えられるようにする
2. エミュレーター内に量子レジスタという定義を行って、量子レジスタを使った演算を行えるようにする
といったものです。
1については非常に簡単で、エミュレーターの起動時の引数に加えることでOKです。例えば次のような感じで。
spike -q[num] pk test
といった感じで、numが量子ビット数を与えてプログラムをエミュレーター上で動かします。
2については悩んだ結果、調査段階で検討していたQuESTをスタティックリンクでSpikeと結合することによって、Spike内の量子レジスタの操作(hadamard/measure)を行えるようにすることにしました。ということで、
– QuESTをstatic link libraryとしてビルドできるように改造
– SpikeのビルドでQuESTを読み込ませて動作させる
といった実装を行います。Spike内ではprocessor.h, processor.cc内に次のような実装が入ることになります。
std::vectorprocessor.ccqubit; QuESTEnv *env = NULL;
if (env != NULL) { printf("#qregister size : %d\n", nregisters); printf("#qbit size : %d\n", nqbits); for (int i = 0; i < nregisters; i++) { Qureg q = createQureg(nqbits, *env); initZeroState(q); qubit.push_back(q); } }
processor.h 内に量子用レジスタ(qubit)を定義してみました。エミュレーターの本体(sim.h, sim.cc)で生成したQuESTEnvを個々のプロセッサに渡して、プロセッサ内で量子用の演算を行えるといった構成です。
追加する命令セットの仕様はここで検討されている通りに実装をしています。
ということで、今度は命令セットの追加です。
ここではMeasureを使う例として、riscv-isa-sim/riscv/insns/qmeas_k.h を追加します。
int qbit_measure = measure(p->get_qubits(), insn.k_qimm6()); fprintf(stderr, "qmeas : rd: %ld, rs1: %ld, rs2: %ld, qimm6: %ld\n", insn.rd(), insn.rs1(), insn.rs2(), insn.k_qimm6()); WRITE_RD(qbit_measure);
非常に簡単ですね。命令セットのパラメータ通りmeasureを実行してRDに返すような実装です。デバッグ用にfprintfをして出力の確認も簡単に行うことが出来るので、実装も捗ります。この辺の諸々の実装を行ってRISC-V上に命令セットを追加して量子演算を行うことが出来るようになりました。次のようなアセンブラコードを作ります。
テストコード
int main(int argc, char* argv[]) { int ret1 = 0; // call qooh asm volatile( "qooh.k qa0,qt1,qzero,1;" ); // call qmeas asm volatile( "qmeas.k %0,qt1,qzero,1;" :"=r"(ret1) : ); printf("%d\n", ret1); return 0; }
テストコードをビルドしたアセンブラコードの抜粋
main: addi sp, sp, -48 sd ra, 40(sp) sd s0, 32(sp) addi s0, sp, 48 sw zero, -20(s0) sw a0, -24(s0) sd a1, -32(s0) sw zero, -36(s0) qooh.k qa0,qt1,qzero,1; qmeas.k a0,qt1,qzero,1; sw a0, -36(s0) lw a1, -36(s0)
エミュレーターの実行
spike -q3 pk test #qregister size : 32 #qbit size : 3 bbl loader hadamard : rd: 10, rs1: 1, rs2: 0, qimm6: 1 qmeas : rd: 10, rs1: 1, rs2: 0, qimm6: 1 1
出力のhadamard、qmeasの所はデバックで出しているものですね。
RISC-Vプロセッサ内で量子系の演算をさせることで…
● RISC-Vエミュレータに量子系命令セットを追加
● 量子用のレジスタをエミュレーター上に定義
● 量子用の演算はプロセッサ毎に実行
● 量子用の演算にはQuESTを利用してシンプル化(アクセラレータとしても考えられる)
● 通常のgccでアセンブラとしてQ系命令を関数的に実行することで、普通のC/C++言語で作られたプログラムコードに超簡単に量子系の命令を行うことができる
特に最後のものは、量子系の演算をRISC-Vプロセッサ内で行うことが出来るので、asm volatile… を何か適当な関数化させることで、普通のソースコードに何か量子系のライブラリや実装を加えなくても簡単に量子演算を行うようになりますね。
ただ、これにはgcc側で量子系の命令セットを扱えるよう、上記のアセンブラコードの量子系命令を解釈して実行形式にする改造が必要になってきます。更にLLVMで独自の量子向け言語を作る事も考えていて、この時に上記のようなアセンブラ命令をclangで実行しても動かせる事も出来る感じですね。
まずは、このgcc-toolchain への量子系命令セットの追加実装、加えて量子レジスタの組込み(gcc-toolchainでビルド時には当然ながら命令セットだけではなく、量子用のレジスタの解釈も出来るようにする必要がある)については、次回のblogにでも。
1件の返信
[…] 前回に引き続き、次は拡張命令セットをGCC(RISC-V GNU Toolchain)に追加していく。前回はとりあえずSpike上で量子系の命令セットを追加して演算を行うまで行った。ここで目標としては…1. gnu toolchainを改造して量子系の命令セットを解釈できるようにする。2. 元のソースコードでは、asm volatile を使って命令セットを記述する。何かc/c++向けに関数を容易すれば良いのだけど、とりあえずは asm volatile を直接叩くということで。動いてしまえば関数化してしまえば問題ない。つまり、次のような流れでコンパイル~実行することになる。 […]