Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Magic: The Gathering を コンパイルターゲットにした LLVM Backe...

Avatar for えすびて えすびて
May 29, 2026
4

Magic: The Gathering を コンパイルターゲットにした LLVM Backendの紹介

Avatar for えすびて

えすびて

May 29, 2026

Transcript

  1. Magic: The Gathering(MtG)とは • 世界初 (諸説あり) のトレーディングカードゲーム • プレイヤーは魔法使いとなって、呪文(カード)を駆使して対戦相手と戦う •

    30年以上の歴史があり、これまでに2万種類以上のカードが作成されている 4 https://mtg-jp.com/reading/kochima/img/20140813/hydra_attack.jpg
  2. MtG as 計算機 • MtGにはユニークな効果を持ったカードが多く登場する ◦ プレイヤーの行動を制限・強制する ◦ ゲームのルールを変更する ◦

    カードの効果テキスト自体を書き換える • これらのカードは(もちろん)対戦で使用することを想定されているが、 これを計算機科学的な方向で 悪用 活用しようとする人たちが現れる 5 … https://arxiv.org/abs/1904.09828 ユニークな効果を持ったカードたち(例)
  3. MtG as 計算機 • 2024年、MtGを用いて計算機を実装可能であるという論文が発表される ◦ Howe Choong Yin and

    Alex Churchill. “A Programming Language Embedded in Magic: The Gathering”. FUN 2024. • 以前にもMtGを用いて チューリングマシンを構築できる ことは示されていたが、 本研究では独自のアセンブリ言語 を処理する計算機をMtGで実装 6 https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.FUN.2024.31 より
  4. MtG as 計算機 • 2024年、MtGを用いて計算機を実装可能であるという論文が発表される ◦ Howe Choong Yin and

    Alex Churchill. “A Programming Language Embedded in Magic: The Gathering”. FUN 2024. • 以前にもMtGを用いて チューリングマシンを構築できる ことは示されていたが、 本研究では独自のアセンブリ言語 を処理する計算機をMtGで実装 7 https://drops.dagstuhl.de/entities/document/10.4230/LIPIcs.FUN.2024.31 より AInput 1 Add1 R3 NumBuild 2 Add1 R3 Set R2, R1 DivCeil R2, R3 JumpBwdF 4 …
  5. (補足)計算機を実装可能である とは • MtGはレジスタやメモリといった概念が(ルール上は)存在しないので、 ゲーム上の概念(特定のカード , 領域, コンポーネントなど)を用いてそれらを表現 する •

    「計算機を実装可能」とは その表現の上で計算機と同等の挙動が行われる ことを指す 一般的な概念 MtG計算機での表現 PCが指している命令 山札の上から 1,2,3枚目にある基本土地 命令をデコード 山札の上から順に基本土地を 3枚戦場に出す 命令の種類 戦場に出た基本土地たちの組み合わせ 汎用レジスタ Rx 特定の種族 yを持つ 汎用レジスタの値 の上に置かれている +1/+1 カウンターの数 … … PCが指すアドレスから命令をデコードし、 その命令がAdd R1, R2 であるならば、 R1にR2が保持している値を加算する 山札の上から基本土地カードを 3枚戦場に出し、 それらが順に であるならば、 種族 Brushwagg を持つ の上に 種族 Camarid を持つ の上にある個数と同じだけ +1/+1カウンターを置く
  6. LLVMとは • OSSのコンパイラ基盤 • 変換は大きく分けて2段階からなる ◦ Frontend:入力されたコードを中間表現( LLVM IR)に変換 ◦

    Backend:LLVM IR をターゲットごとのアセンブリに変換 • 今回の目的を達成するためには LLVM IR → ターゲット のBackendさえ実装すれば良い 11 各種 アセンブリ プログラム コード LLVM IR LLVM Backend LLVM Frontend
  7. 何を何に変換するか • 入力はLLVM IR • 出力は MtG 計算機で動くアセンブリ ◦ 一度アセンブリに出力してしまえば、そこから実際のカード列に変換することは容易

    • このアセンブリの仕様を知る必要がある ◦ MtGのカードを用いて実装しているため、かなり癖がある • 実は、MtG ISAには論文中で紹介されているものとは別に、著者らの Webページ上で紹介されているものがあり、細部が微妙に異なっている ◦ https://cyh31.neocities.org/amepscimtg/explanation ◦ Web版の方が機能的にはリッチなので、以降はこちらの ISAを紹介する 13
  8. MtG ISA • レジスタ ◦ 汎用レジスタR0〜R11(32bit, 12本), フラグレジスタFlag (1bit, 1本)

    ◦ 仕様としては汎用レジスタには任意長の値を格納可能だが、実装の都合上 32bitに制限 ▪ ただし、一部の処理では 32bitに収まらない値を代入する(後述) • 命令 ◦ 合計で 35 命令あるが、そのうち今回の実装で用いたものに絞って(駆け足で)紹介 ◦ 大きく以下のカテゴリに別れる ▪ 代入命令 ▪ 演算命令 • 数値演算 • 論理演算 ▪ ジャンプ命令 ▪ メモリ転送命令 ▪ 入出力命令 14
  9. MtG ISA:代入命令 15 命令 効果 備考 Move Ra, Rb Ra

    ← Rb Zero Ra Ra ← 0 NumBuild #imm1, #imm2 R0 ← imm1 * 12 + imm2 前の命令が NumBuildなら代わりに R0 ← R0 * 144 + imm1 * 12 + imm2 各immが取れる値は0~11 SetF Ra Ra ← Flag ? 1 : 0 SetNF Ra Ra ← Flag ? 0 : 1
  10. MtG ISA:演算命令(数値演算) 16 命令 効果 備考 Add Ra, Rb Ra

    ← Ra + Rb Add1 Ra Ra ← Ra + 1 SubCond Ra, Rb Flag ← (Ra - Rb < 0) Ra - Rb ≧ 0 なら Ra ← Ra - Rb 演算結果が負になる場合、 演算が行われない Sub1Cond Ra Flag ← (Ra - 1 < 0) Ra - 1 ≧ 0 なら Ra ← Ra - 1 Mult Ra, Rb Ra ← Ra * Rb Divide Ra R6 ← Ra // R0 Ra ← Ra % R0 RaとしてR0, R6を用いる or R0=0の場合は未定義動作 Halve Ra Flag ← (Ra % 2 == 1) Ra ← Ra // 2
  11. MtG ISA:演算命令(数値演算) 17 命令 効果 備考 Add Ra, Rb Ra

    ← Ra + Rb Add1 Ra Ra ← Ra + 1 SubCond Ra, Rb Flag ← (Ra - Rb < 0) Ra - Rb ≧ 0 なら Ra ← Ra - Rb 演算結果が負になる場合、 演算が行われない Sub1Cond Ra Flag ← (Ra - 1 < 0) Ra - 1 ≧ 0 なら Ra ← Ra - 1 Mult Ra, Rb Ra ← Ra * Rb Divide Ra R6 ← Ra // R0 Ra ← Ra % R0 RaとしてR0, R6を用いる or R0=0の場合は未定義動作 Halve Ra Flag ← (Ra % 2 == 1) Ra ← Ra // 2
  12. MtG ISA:演算命令(論理演算) 18 命令 効果 備考 FIsZero Ra Flag ←

    (Ra == 0) 直前の命令が論理演算なら代わりに Flag ← Flag | (Ra == 0) FLess Ra, Rb Flag ← (Ra < Rb) 直前の命令が論理演算なら代わりに Flag ← Flag | (Ra < Rb)
  13. MtG ISA:ジャンプ命令 19 命令 効果 仕様 JumpFwd PC ← PC

    + R0 JumpBwd PC ← PC - R0 JumpFwdNF Flag == False なら PC ← PC + R0 JumpBwdNF Flag == False なら PC ← PC - R0 Return Ra プログラムを終了する ISAとしてはCall命令からの復 帰も可能だが、今回は省略
  14. MtG ISA:メモリ転送/入出力命令 20 命令 効果 備考 Store Ra, Rb Mem[Ra]

    ← Rb アドレス, 値はレジスタ経由で渡す必要がある Load Ra, Rb Ra ← Mem[Rb] Output Ra Raの値を出力 ISAとしてはInput命令も存在するが、 今回は省略
  15. MtG ISA:メモリ転送/入出力命令 21 命令 効果 備考 Store Ra, Rb Mem[Ra]

    ← Rb アドレス, 値はレジスタ経由で渡す必要がある Load Ra, Rb Ra ← Mem[Rb] Output Ra Raの値を出力 ISAとしてはInput命令も存在するが、 今回は省略
  16. 課題①レジスタスピル時に落ちる 概要 • コンパイル時に利用可能なレジスタを使い切った場合、今不要なレジスタをメモリのスタッ ク領域に退避する処理が挿入される(レジスタスピル) • スタック領域への退避にはStore命令(Store Ra, Rb; Mem[Ra]←Rb

    を使う) • ここで、Storeは即値を扱えないので、アドレス代入用のレジスタが別途必要 • が、レジスタスピルの処理中なので空きレジスタは存在しない! →エラー 対処 • 12本のレジスタのうち、一部を作業用としてReserve ◦ これによってレジスタスピル発生時にも実際には利用可能なレジスタが残る • (綺麗な解決法ではないので、別の方法があれば見つけたい) 24
  17. 課題②結果が負になる減算が(そのままでは)できない 概要 • MtG ISAで減算を行う命令は SubCond Ra, Rbだが、この命令は Ra -

    Rb が 0以上の場合にしか計算を行わない • 減算結果が負になるときに対応したい 対処 • SubCondの代わりに Rb ← -Rb, Add Ra+Rb の2命令を用いる • そうすると今度は-Rbの計算方法を考える必要があるが、MtG ISAにおいては レジスタに2^32をそのまま代入できるので、2^32 - Rb で可能 ◦ プログラム上はレジスタを 32bit整数で扱っているので、この SubCondは必ず成功する 25
  18. 27

  19. 28