活性分析へのオディ:SSA レジスタへ

2026/11/08 0:17

活性分析へのオディ:SSA レジスタへ

RSS: https://news.ycombinator.com/rss

要約▶

日本語翻訳:

元の要約は整合性はあるものの、以下のバージョンは「Key Points List」(特定のレジスタタイプ、phi ノードの欠如、CLI フラグの詳細、および特定の制限事項)に記載されていた欠落していた技術的な詳細を明示的に統合することで明瞭性を向上させつつ、円滑な流れを保っています:

要約(改善版)

著者は、「purple-garden」プロジェクト向けの Just-In-Time (JIT) コンパイラーとレジスタアロケータを開発中である。本システムは、仮想レジスタを GPR、FPR、スタックといった限られたハードウェアリソースへ効率的にマッピングすることを目標としている。即時表現(IR)では Static Single Assignment (SSA) フォームを採用しており、ブロックパラメータおよびターミネーターを用いてブロック間データフローを管理するため、標準的な SSA とは区別される。レジスタ使用量の最適化のために、値のスパイル(メモリーへのダンプ)前における生残期間(liveliness)を決定する生残性解析(liveness analysis)を採用している。この仕組みは、CLI フラグ(-I で最適化された IR、-II で仮想レジスタの寿命アノテーション

lo
/
hi
)および Rust 関数(
ensure_register
、
def_register
)によってサポートされている。ワークフローには、IR 命令(例:
Bin
、
BinImm
)を VM オPCODE(
IAdd
、
ISub
など)または JIT コンパイラー向けの直接 x86 アセンブリに変換する前処理フェーズにおいて、Cc::prealloc を使用して Liveset を計算する段階が含まれる。現在の課題としては、アロケーター内で追加の作業を必要とする全てのブロック遷移をエージートランスファーとして扱う点があり、これが検討中である。これらの改善およびバックエンド開発に関する将来の更新は、利用可能な RSS フィードを通じて発表される予定である。

本文

愛の手紙:Purple Garden 仮想マシンとレジスタ割り当ての実装記

記事の概要

「喜びの歌(Ode to Joy)」の精神を受け継ぎ、私のプログラミング言語 Purple Garden の開発について解説します。 このプロジェクトでは、レジスタ指向バイトコード仮想マシン と、x86 アーキテクチャ向けの リアルタイムコンパイラ(JIT コンパイラ) の開発を並行して進めています。

  • 生命(ライフ)の分析:本記事で紹介するピクセルアートの象徴は、コード実行におけるデータフローとレジスタのライフサイクルを理解することです🤓
  • 開発焦点:レジスタ割り当て(Register Allocation) アルゴリズムの実装と最適化。

1. レジスタ割り当てとは何か?

レジスタ割り当てとは、理論上無限にある仮想的なレジスタを、ハードウェアの物理的な制約(GPRs、FPRs、スタック)に合わせて割り当てるプロセスです。

この課題を解決する第一歩となるのは、「活性度分析(Liveness Analysis)」 です。 これは、各変数や値がコード内で実際に使用されている期間(ライフタイム)を追跡し、いつまでメモリまたはレジスタ上に存在させる必要があるかを決定するための解析手法です。


2. ガーデニング:最小単位の例題

最適化の原理をわかりやすく解説するために、簡素な関数の変換例を見てみましょう。

プログラム源(Purple Garden)

以下の関数は階乗の計算に関連するロジックを持っています。

fn f(a:Int n:Int acc:Int) Int {
    match {
        n < 1 { a + acc }
        { f(a n-1 acc*n) }
    }
}

C コードへのディスアセンブル

元の IR を理解するために、Max Bernstein の論文「Linear scan register allocation」から引用された C コードと比較します。Purple Garden ではループ構造を明示的に持たないため、等価な呼び出しは

f(a, n, 1)
です。

long f(long a, long n) {
    long acc = 1;
    while (n >= 1) {
        acc = acc * n;
        n = n - 1;
    }
    return a + acc;
}

Purple Garden IR(最適化後)

-I
フラグを使用することで生成される即時表現(Immediate Representation) です。不要な変数が削除され、効率的になっています。

fn f1(%v0:Int, %v1:Int, %v2:Int) -> Int {
    b0(%v0, %v1, %v2):
        %v4:Bool = ILt %v1, 1
        br %v4, b1(%v0, %v1, %v2), b2(%v0, %v1, %v2)
    b1(%v5, %v6, %v7):
        %v8:Int = IAdd %v5, %v7
        ret %v8
    b2(%v9, %v10, %v11):
        %v13:Int = ISub %v10, 1
        %v14:Int = IMul %v11, %v10
        tail f1(%v9, %v13, %v14)
}

3. Purple Garden の IR 構造と表記法

Purple Garden の IR は 静的単一割り当て(SSA) 形式に基づいています。

主な特徴

  • 不変性:各値/仮想的なレジスタは
    exactly once
    だけ定義され、不変です。
  • 表記法:仮想レジスタは
    %vN
    と表記します。
  • ブロック構造:Phi ノード(φノード)を使用せず、ブロックパラメータとターミネーターのみで制御流を表現します。

LLVM IR 構造の詳解

各ブロックは「パラメータリスト」+「指令本体(SSA 形式)」+「ターミネーター」で構成されます。すべての値はブロックローカルであり、データフローはこの境界を通じてのみ実装されます。

Rust による型定義(参考)

pub struct Block<'b, A: Allocator = Global> {
    pub id: Id,
    pub instructions: Vec<Instr<'b>, A>,
    pub params: ParamsId,
    pub term: Option<Terminator>,
}

// 一部の重要な指令例
pub enum Instr<'i> {
    BinImm { op: BinOp, dst: TypeId<'i>, lhs: Id, imm: i32 },
    // ... 他のインストラクション ...
}

pub enum Terminator {
    Return { value: Option<Id> },
    Tail { func: Id, args: ParamsId },
    // ... 他のターミネーター ...
}

4. 仮想的なレジスタのライフタイム分析

SSA IR を可視化することで、各値のライフタイム(開始位置

lo
と終了位置
hi
)を把握できます。

ライフタイムアノテーション付き IR

CLI に

-II
フラグを指定すると、以下の図のように各レジスタの生きている範囲が視覚的に表現されます(ブロックパラメータはオフセット 0 で始まります)。

ライフタイム表(線形化された位置)

valuelo (開始)hi (終了)
%v002
%v102
%v202
%v412
%v534
%v734
%v845
%v969
%v1068
%v1168
%v1379
%v1489

5. シンプルかつ効率的な実装(活性度分析)

このアルゴリズムは以下の 4 つのステップに分解できます:

  1. ブロックの巡回
  2. ターミネーターの観察(使用状況の確認)
  3. 指令の逆順処理(定義と使用の観察)
  4. パラメータの観察

観察ロジック (
observe
)

値が「現在アクティブ」なことをマークし、ライフタイムを記録します。

/// Oxidised 用語での実装例
fn observe<V: Allocator>(out: &mut Vec<(u32, u32), V>, id: Id, pos: u32) {
    let idx = id.0 as usize;
    let e = &mut out[idx];

    // hi は未定義 (0) の場合のみ設定
    if e.1 == 0 {
        e.1 = pos;
    }
    // lo は常に現在の位置として更新
    e.0 = pos;
}

ヘルパー関数:使用と定義の取得

  • def_of
    : 指令内で値が定義されるかどうかを返します。
  • for_each_use_of_instr
    : 指令内の値がどこで使用されているかを走査します。
  • for_each_use_of_term
    : ターミネーター内のパラメータを使用状況を走査します。

これらの関数は、Rust のパターンマッチングを用いて各インストラクションタイプを細かく分解し、対応する

Id
を集めます。この設計により、複雑な制御フローでも堅牢に活性度解析が可能です。


6. 統合された実装とレジスタ割り当てへの適用

計算された活性度セット(Liveset)は、実際のレジスタ割り当てアルゴリズムの入力として機能します。これにより、ハードウェアの物理レジスタやスタックスロットに適切な値を配置できます。

レジスタ割り当て予備パス

Cc::prealloc
を実行することで、降下処理(Lowering)の前に IR を巡回し、簡易的な検索による割り当てを行います。

// 概要:活性度セットの計算 -> prealloc の実行 -> ブロック・指令反復処理
fun.live_set_into(&mut self.live_set);
self.prealloc(fun);

// レジスタ割り当て後のポスト処理(スタックへの溢れ出しなど)
if let Some(Location::Stack(slot)) =
    Func::def_of(instruction).and_then(|dst| self.regalloc.location(dst))
{
    self.emit(Op::StoreSlot { slot, src: TMP });
}

IR 操作の降下処理(Lowering)

Bin
および
BinImm
などの演算子を、VM レジスタ上の物理的な操作に変換します。

  • 二項演算:左辺と右辺をレジスタ確保し、オペコードを発行します。
  • 即時値演算:即座に命令セット化され、メモリアクセスを減らします。

Rust マクロを活用することで、すべての二項演算とその即時版を約 57 行で記述しています。これはコンパイラ実装における洗練された手法です🤓。

レジスタの確保と定義

仮想レジスタを VM レジスタに変換する際に、以下の 2 つの重要な動作を行います:

  1. ensure_register
    :値が物理レジスタに割り当てられていればそのまま使用し、スタック上であれば一時レジスタを使ってメモリから読み込み(リストア)します。
  2. def_register
    :演算の結果を格納する先頭レジスタを決定します。既にレジスタにあればそれを返し、なければ
    TMP
    を使用します。これにより、溢れ出した結果は自動的にスタックスロットに保存されます。

7. バイトコードと JIT アセンブリの統合

活性度解析とレジスタ割り当ての結果が反映されたアセンブル出力を確認できます。

バイトコード生成(-I フラグ)

SSA 値に割り当てられた仮想マシンレジスタが見えます。

000000000 <f>:
  0000:    ilt_imm r3, r1, #1        ; n < 1 の判定
  0001:    jmpf r3, 0004 <f.bb_0004>
  0002:    iadd r0, r0, r2           ; a + acc
  0003:    ret
000000004 <f.bb_0004>:
  0004:    isub_imm r3, r1, #1       ; n - 1
  0005:    imul r2, r2, r1           ; acc * n
  0006:    mov r1, r3                ; 値の移動
  0007:    tail 0000 <f>             ; リカーシブ呼び出し

JIT コンパイル(x86)

JIT モードでは、さらに最適化されたネイティブコードが生成されます。比較命令と条件分岐を単一の指令に統合するなどの高度な技術が使われています🤓。

0000000000000000 <jit_f>:
   0:   48 81 fa 01 00 00 00    cmp    $0x1,%rdx          ; n < 1 の比較(cmp)
   7:   49 c7 c0 00 00 00 00    mov    $0x0,%r8           ; リセットフラグ設定
  ... (最適化されたループと計算ロジック) ...

今後の展望

現在、IR デザイン、レジスタアロケーター、バックエンド間の相互作用を「完璧に」調整する段階です。

  • 追加の課題:レジスタアロケーターの入力(活性度セット)と出力(物理レジスタ割り当て)については詳述しましたが、ブロック遷移(ジャンプやリターン)をエッジ移動として扱い、これらを解決するための追加の実装についてはまだ未発表です。
  • 今後の予定:動機が維持される場合、これらのトピックについてフォローアップの記事を書く予定です。

私の不整合なたわごとを共有するための RSS フィードもありますので、ご興味がある方はぜひそちらもご覧ください。

同じ日のほかのニュース

一覧に戻る →

2026/11/10 4:58

USPS が公式の郵便番号境界多角形を提供開始

## Japanese Translation: 米国郵便公社(USPS)が、実時間の配信住所および位置情報データを基に正確な ZIP コード境界を定義する新たな全国マップを発表しました。これは、人口統計情報や位置情報を整理するための不可欠な「地上の真実(ground truth)」を確立します。歴史的に配送ロジスティクスをルーティングするために主に配送場所の集約手段として用いられてきた ZIP コードとは異なり、これらの更新されたポリゴンには新規または変更された配信場所における実際の変動が反映されており、保険、不動産、マッピング、郵送、マーケティング、ナビゲーション、物流、輸送など、重要な業界に対してより優れた精度を提供します。ユーザーは USPS® ZIP コード境界 - 内部(Internal)を活用することで、更新されたポリゴンを自社のシステムに直接組み込むことができ、これを単なる共同機能として採用することも、既存の ZIP コードデータを修正することも可能です。データの最新性を確保するため、USPS は主要データセット(エンタープライズティアおよびパブリケーションティアを含む)を四半期ごとの 4 回の刷新を含め、3 ヶ月到月に更新しています。限定アクセスバージョンも特定の制約の下で配布されますが、同じくこの更新サイクルを共有します。郵送、マーケティング、輸送分野の企業は、この高解像度なデータを活用して運用を最適化でき、様々なセクターにおける人口統計情報の整理と運用作業効率を著しく向上させることができます。

2026/11/10 6:56

TPU

## Japanese Translation: Google は、Google Cloud Next で発表された 4 つの新しいシステム(TPU 8t、8i、8tx、および 8i Max)によって、第 8 世代 TPU ポートフォリオの開発を加速させました。これらのアップグレードは、最多 2.7 倍の高速なトレーニングと、大幅に向上した推論における価格パフォーマンスを実現し、ハードウェアレベルのセキュリティ(AMD EPYC ホストを通じたもの)および大規模なコンテキストスケーリングに対する緊急のニーズに対応します。エコシステムは TorchTPU、vLLM、SGLang などの PyTorch フレームワークとネイティブに統合されており、開発者がロジックを書き直すことなくコードを実行できるようにしています。主要な革新には、メモリ階層を統一しレイテンシを 90% 以上削減する TPU Sync と、アイドル中のセッションを自動的に停止してコストを削減する Agent Compute Engine が含まれます。さらに、GKE 上の Cloud Pathways を通じた動的スライシングによるデプロイの簡素化など、追加の進歩があり、ジョブ起動時間を最大 5 倍削減します。今後のアップデートには、インフラストラクチャ管理およびカーネルチューニングを自動化するためのオープンソース TPE アジェントスイートが含まれる予定です。

2026/11/10 5:04

人工分析(Artificial Analysis)にて Claude Fable 5.2 が最高得点の 65 を獲得、過去最高を更新

## Japanese Translation: 主な革新点は、API アクセスに依存せずに特定の代理タスクにおける高度な AI モデルを評価するように設計された固有のベンチマークスイート「人工分析知能インデックス v5.0.1」です。正確性とパフォーマンスは、9 つの異なる評価を通じて検証されています:AA-Briefcase v1.1(知識作業向け)、AutomationBench-AA、Terminal-Bench 4.0、FrontierCode 2.0、GDP.pdf、HLE-Diamond、CritPt v2(Hard Subset)、AA-Omniscience v1.1、および Terminal-Bench-Science 0.1。これらの評価は、代理による科学的研究ワークフロー、法律代理作業、医療向け長文脈推論、そして構造化された言語といった特定のカパビリティを対象としています。 AA-Briefcase Elo は、rubric 通過率、分析品質 Elo、およびプレゼンテーション Elo(0 でクランプ)を統合し、AA-Omniscience v1.1 は知識の信頼性とハルシネーションを測定し、-100 から 100 の範囲で Net Score を算出します。ここで、0 は正しい答えと間違いなりの答えが同等であることを示し、正しい答えには報酬を与えつつ、拒否に対してはペナルティを課さないハルシネーションのみを処罰します。パフォーマンスは、タスクあたりの所要時間(分)、出力速度(トークン/秒)、および最初の回答トークンまでの時間(秒)で測定されます。 コストは、入力トークン、キャッシュヒット/ライト、推論、および回答トークンの価格をタスク数で割った加重平均(USD)として計算され、キャッシュヒット、入力、および出力トークンに対して異なる価格体系が適用されます。キャッシュヒットの価格には大幅な割引が付与されています。運営効率は、ベンチマークを自動的に 6 時間ごりに実行することによって維持され、非推奨モデルはリソース節約のため 18 時間周期で動作します。モデルの重みの入手可能性は表示されており、「商用利用制限付き」または「非商用」というラベルがライセンス条件に基づいて付与されます。これにより、エコシステム内での責任ある使用が確保されます。

活性分析へのオディ:SSA レジスタへ | そっか~ニュース