どうもです。GMOインターネット 新里です。定期的に何か今回から書いていこうと思っています。本エントリーではIPA未踏ターゲット事業で行った事について書こうと思います。※編集注 IPA未踏とは、経済産業省所管である独立行政法人情報処理推進機構が主催し実施している、”突出したIT人材の発掘と育成”を目的として、ITを活用して世の中を変えていくような、日本の天才的なクリエータを発掘し育てるための事業です。
https://www.youtube.com/watch?v=ts4WP3nBXMc
8bit
こんな物とかも作りました。音がすごいので再生する時はご注意ください。
RISC-Vってなに
RISC-V量子拡張の参照実装とマイクロ波制御量子ファームウェアの開発(2019)〜量子コンパイル基盤の最適化処理・分岐並列制御の開発と量子計算を体感するプレゼンテーション(2020)で採択いただきました。
未踏ターゲット事業は「量子コンピューティング技術を活用したソフトウェア開発」を対象分野とした物で、アニーリング・ゲート・それ以外と分かれています。量子コンピューターについては何となくキーワードとして聞いたこともあるという人も多いはずです。ただ、RISC-Vについてはあまり聞き慣れない人も多いかな、と体感では思っています。
ぶっちゃけ"RISC-V"でググった方がたくさんの情報が得られるので、詳しくは検索してみた方が早いでしょう。ザックリだと
・ライセンスフリーで使えるISA・仕様は開発環境もすべてRISC-V Foundationで公開されている・命令セットがシンプルで拡張性も高い
といった感じでしょうか。ISAはx86/64、ARM、MIPS、POWER...etcとたくさんあるなかでも、RISC-VはマイコンからHPC・メニーコアといった広いターゲットになっています。個人的に気になって使ったりしたものが、64bit RISC-V dual core Kendryte K210ですね。マイコンで機械学習を実行できるAIアクセラレータにおいて1TOPSで実行できる環境は素敵です。
命令セットをライセンスフリーで拡張可能ということで、量子向けの命令セットを実装する古典コンピューター(身の回りにある古典力学で作られている、0/1で表現されているコンピューターのこと)、としてRISC-Vを使うことにしました。
RISC-Vの開発環境を整える
RISC-Vの拡張命令はK extensionとして定義して、custom領域を使うように設計しました。どういった命令セット・レジスタを用意したのか?については、この辺(RISC-V Quantum Extension)にまとめてあります。
命令セット群を追加した時に動作する環境はどうすれば良いでしょう?プログラムや何か動く環境がないと絵に書いた餅ですね。つまり...
1.命令セット、レジスタを拡張する仕様決め2.プログラム(gccとか)から命令セット、レジスタにアクセス出来る。3.エミュレーターや動作環境を整える。
といった流れに。命令セットを拡張するにしても、動作するCPUは存在しない訳なので、エミュレータで動作を確認するといった感じです。まぁ簡単な感じだと、「何かプログラミング言語を命令セットに対応させてエミュレーターを用意すれば、拡張命令セット・レジスタの検証ができる」といった感じですね。
何はともあれ、とりあえずRISC-V・エミュレーターの開発環境を作って、何か動かしてみましょう。環境はdockerのUbuntu 20.04版を利用する前提です。
# use docker ubuntu 20.04 as root
apt-get update
apt-get -y install autoconf automake autotools-dev curl python3 libmpc-dev libmpfr-dev libgmp-dev \
gawk build-essential bison flex texinfo gperf libtool patchutils bc zlib1g-dev libexpat-dev git cmake \
device-tree-compiler liboscpack-dev liboscpack1
# riscv install dir
mkdir /opt/riscv
export RISCV=/opt/riscv
# make riscv gcc toolchain
cd /root/
git clone https://github.com/riscv/riscv-gnu-toolchain --recursive
cd riscv-gnu-toolchain
./configure --prefix=/opt/riscv --enable-multilib
make
export PATH=$PATH:$RISCV/bin
# make spike emulator
cd /root
git clone https://github.com/riscv/riscv-isa-sim
cd $HOME/riscv-isa-sim
mkdir build
cd build
../configure --prefix=$RISCV
make
make install
# make proxy kernel
cd /root
git clone https://github.com/riscv/riscv-pk
cd $HOME/riscv-pk
mkdir build
cd build
../configure --prefix=$RISCV --host=riscv64-unknown-elf
make
make install
export PATH=$PATH:$RISCV/riscv64-unknown-elf/bin/
RISC-V向けのクロスコンパイラ環境(riscv-gnu-toolchain)をビルドしたら、エミュレーター環境(riscv-isa-sim)、プログラムのI/Oをホストに委託して動作させる実行環境であるプロキシカーネル(riscv-pk)をそれぞれビルドします。簡単にテストコードを書いて動かしてみましょう。
cat <<EOF> test.c
#include <stdio.h>
int main() {
printf("Hello World RISCV\n");
return 0;
}
EOF
riscv64-unknown-elf-gcc -o test test.c
spike pk test
これでRISC-V向けにプログラムを作って動作確認できる開発環境ができましたね。spikeエミュレーターではプロセッサ数をエミュレートしたり(デフォルトは1プロセッサ)、ISA拡張機能(デフォルトはRV64IMAFDC)といったように面白いオプションが使えます。実験的に1000プロセッサで動作させた事もありますが、普通に動かすことができました。
gccへの量子命令セット拡張
RISC-Vの環境ができたら、量子向けの命令セット・レジスタをgccとエミュレータに実装します。Xゲート、Hゲート、Measurement(読み出し)...etc といった基本的なゲート処理に対応する命令セット群をgccの拡張機能(k extension: 量子向けにkを定義)として入れていくことになります。
具体的には、この辺のgccの改造(Add Extend Instruction set to RISC-V GNU Toolchain)、エミュレータに対する命令セット拡張(Quantum compute on RISC-V emulator(Spike))にどうやってgccを改造するか?エミュレーターに対する命令セットの拡張をまとめています。何か独自の命令セットや拡張・アセンブラの解釈をサクッと作る時の何か参考にでもなればと。ザックリだと...
・gccに命令セット・レジスタの追加・拡張機能のフラグ追加・アセンブリの解釈(命令セットのopcode)を追加
この2点を実装すれば、gccへのオレオレ命令セットの追加も可能です。ちなみにgcc(c/c++)の方は、構文木(AST)の方はアタッチしていません。LLVMを使った独自言語・最適化実装の方では、LLVMを使った構文木の処理をしましたが、gccの方はバックエンド側として使うため、命令セット・アセンブラの処理に留めおいた感じですね。
LLVMでの独自言語開発と最適化
gccとエミュレーター、実際の量子ファームウェアの全体構成は次の図のようになっています。古典と量子のプログラムを同時に扱うので、なかなかジワってくる難しさがありますね。
2019年度開発版
2020年度開発版
ここで、次にLLVMを使います。目的としては...
・LLVMを基盤として使うことで、色々なプログラミング言語への展開が可能・フロントエンド〜LLVM IR部分で量子向け言語実装・バックエンドは量子拡張をしたgccで結合
といった構成を取ることができる。MicrosoftもLLVMへの拡張を書いているIntroducing Quantum Intermediate Representation (QIR)通り、LLVMを基盤にするのは有用でしょう。Rust・Swift...etc を含めたLLVM基盤を使った言語への展開も考えられるようになる。そしてLLVMを使うと、わりと簡単に言語実装が出来るというのも嬉しいですね。具体的にはgolang風のqlangという量子向け参照実装をしました。そしてLLVM Pathを使ったゲート最適化ですね。
わりと身近だと思うのは最適化の方かなとおもいます。よくコンパイラオプションで付ける"-O3"とか付けるあれですね。最適化するとバイナリサイズが小さくなったりしますが、あれって一体どのような事でしょうか?ちょっとclang(LLVM)のフロントエンドで見てみましょう。
テストコード(test.c)
int main() {
int i = 0;
for (int j = 0; j < 10; j++) {
i += 1;
}
return i;
}
最適化無し IR
define i32 @main() #0 {
%1 = alloca i32, align 4
%2 = alloca i32, align 4
%3 = alloca i32, align 4
store i32 0, i32* %1, align 4
store i32 0, i32* %2, align 4
store i32 0, i32* %3, align 4
br label %4
4: ; preds = %10, %0
%5 = load i32, i32* %3, align 4
%6 = icmp slt i32 %5, 10
br i1 %6, label %7, label %13
7: ; preds = %4
%8 = load i32, i32* %2, align 4
%9 = add nsw i32 %8, 1
store i32 %9, i32* %2, align 4
br label %10
10: ; preds = %7
%11 = load i32, i32* %3, align 4
%12 = add nsw i32 %11, 1
store i32 %12, i32* %3, align 4
br label %4
13: ; preds = %4
%14 = load i32, i32* %2, align 4
ret i32 %14
}
最適化 IR(-O3)
define i32 @main() local_unnamed_addr #0 {
ret i32 10
}
最適化をしないと、いちいち処理をしていますが、最適化をすると"10"という結果のみになりました。IRがバックエンドでコンパイルされて実行されるとき、逐次CPUを動かして計算するより、1回で済む方が良いのは言うまでもありませんね。
LLVM Pathを使った最適化は、独自の最適化Pathライブラリとして作っておいくと、普通のプログラムにおいても、コンパイル時にPathを経由させることができるので非常に便利です。つまり、独自の言語最適化Pathライブラリを作って自分のプログラムを高速化する時にも役立つでしょう。
体感するプレゼンテーションアプリ制作
一通りRISC-Vをプラットフォームとした、量子コンピューター向けのコンパイル基盤・エミュレーターを作ったので、次は何かアプリを作りたくなるのは自然な流れですね。ざーっとサーベイしてみたのですが、2020年初頭の時点では量子コンピューターを使った触って遊べるようなアプリケーションはまだこれからでした。
そこで量子ファームウェア(超電導型量子コンピューターで使われているマイクロ波)に着目して、ゲート操作に割り当てたマイクロ波をダウンコンバートしてクラドニ図として見せるアプリケーションを作ることにしました。実際のクラドニ図の制作とかはこの辺(クラドニ図の作りかた)、8 bitにまとめています。
テストをしている様子
量子コンピュータへの期待
IBMが2023年までに1000ビットの量子コンピューターを開発予定というニュースも出ています。ですが、いま私達が使っているPCのような、(誤り耐性汎用)量子コンピュータとして使われるまでは、まだ時間がかかるでしょう。感覚的には遠くない未来、2050年頃には対象となる問題やアプリケーションも出てきて、普通に使えるような気はしています。量子コンピュータのマシンもIBM・Amazon・Microsoftのクラウド上で遊んで使うことも出来ます。いまから将来を見据えて、「何に使えるか?」試してみるのも良いでしょう。