Rust GCC back end: Why and how

2025/12/16 22:33

Rust GCC back end: Why and how

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

要約

Japanese Translation:

Rust のコンパイラ(

rustc
)は、ソースコードを実行可能な機械語に変換する一連のパスで構成されており、フロントエンドとバックエンドが明確に分離されています。フロントエンドは Rust の構文を抽象構文木(AST)へ解析し、その後 HIR(High‑Level Intermediate Representation)と MIR(Mid‑Level IR)という高レベル表現に変換します。これらの段階で型チェック、借用分析、およびその他の言語固有の検査が行われ、制御はバックエンドへ渡されます。

バックエンドは MIR を消費し、LLVM または GCC を介してターゲット特定の機械語を生成します。新しい Rust のバックエンドを書き込むには、

rustc_codegen_ssa
から
CodegenBackend
ExtraBackendMethods
WriteBackendMethods
といったトレイトを実装する必要があります。バックエンドのエントリポイントは、以下に示すエクスポートされた関数です。

#[no_mangle]
pub fn _rustc_codegen_backend() -> Box<dyn CodegenBackend>

これはバックエンド実装のインスタンスを返します。記事では、定数文字列(

const_str
)を作成し、関数パラメータにアノテーション(例:
nonnull(1)
は「パラメータ 1 が null であってはならない」)を付与するサンプルコードを示しています。

また、GCC バックエンド(

rustc_codegen_gcc
)が必要となる理由も説明されています。LLVM は Dreamcast のような古いプロセッサをサポートしていないため、libgccjit バインディング(
gccjit-sys
gccjit
)を使用して AOT コードを生成します。これは Rust 用に再実装されたパーシングと検査を行う GCC の別個の C++ フロントエンドである
gccrs
とは対照的です。

最適化は両方のバックエンドで適用されます。LLVM は到達不可能なコードを除去でき、GCC バックエンドも Rust の保証に基づく類似の最適化を行います。記事ではさらに多くの最適化(例:Matt Godbolt が「Advent of Compiler Optimizations」シリーズで議論したもの)が存在することにも触れています。

今後は、LLVM の機能セットに合わせてより多くの GCC 固有の最適化を追加し、新しいターゲットへの Rust の展開を拡大することが提案されています。これはレガシーやニッチなプロセッサで Rust を必要とする開発者に恩恵をもたらし、共有された最適化手法によって広範なコンパイラコミュニティを豊かにします。

本文

Rust でのコンパイラとバックエンドの仕組み


はじめに

Rust コンパイラ(

rustc
)は、ソースコードを読み込み、最終的にはターゲットプロセッサ用のバイナリコードを生成します。
デフォルトでは LLVM をバックエンドとして使用していますが、Cranelift や GCC など他のバックエンドも存在します。本稿では、特に GCC バックエンド がどのように機能するかを解説します。


コンパイルパス(Passes)

コンパイラは「パス」と呼ばれる複数段階で処理を行います。
各パスは独自の AST(抽象構文木)を生成し、次のパスへ渡します。Rust の簡略化例を示すと以下のようになります。

ステップ内容
AST構文が正しいかチェック
HIR型が有効か確認
MIRライフタイム検査・借用チェッカー実行
codegenバイナリコード生成(LLVM/GCC/Cranelift 等)

備考
パスの詳細を深く知りたい場合は、より長い解説を書きます。


フロントエンドとバックエンド

  • フロントエンド

    • コード解析(パース・型チェック・借用チェッカーなど)を担当
    • AST → HIR → MIR の変換まで行う
  • バックエンド

    • フロントエンドが生成した情報(AST、HIR、MIR)を取り込み、実際の機械語やアセンブリコードへ変換する
    • LLVM や GCC への API 呼び出しを通じて最適化・コード生成を行う

なぜ GCC バックエンドが必要なのか

LLVM は比較的新しく(2003 年)作られたため、古いプロセッサはサポートされていません。
例:Dreamcast のような旧世代プラットフォーム向けに Rust プログラムをビルドしたい場合、GCC バックエンドが唯一の選択肢となります。

Dreamcast 用 Rust ビルドガイド などは別途紹介しています。


gccrs
と GCC バックエンド

名称内容
gccrsC++ で書かれた GCC のフロントエンド。Rust の
rustc
フロントエンドを再実装する必要がある
GCC バックエンド(
rustc_codegen_gcc
Rust コンパイラのコード生成部分に特化したバックエンド。AST → GCC API への橋渡しのみ行う

GCC は内部 API を公開していないため、libgccjit を利用します。

libgccjit
は AOT(Ahead‑of‑Time)コンパイルをサポートするライブラリです。

libgccjit の構成

  1. gccjit-sys
    – 必要な C インターフェースを再宣言
  2. gccjit
    gccjit-sys
    上にラッパー API を提供

Rust で書いたコンパイラから GCC を利用する場合、これらのバインディングを使います。


Rust バックエンドの実装

Rust コンパイラは

rustc_codegen_ssa
クレートで抽象化されたインターフェースを提供しています。
バックエンドは以下のトレイトを実装します。

CodegenBackend
ExtraBackendMethods
WriteBackendMethods

また、必ず次のエントリポイント関数を定義する必要があります。

#[no_mangle]
pub fn _rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    /* ここにバックエンド実装を返す */
}

GCC バックエンドでの例:定数文字列生成

ConstCodegenMethods
トレイト内の
const_str
を実装します。
以下はコメント付きサンプルです。

impl<'gcc, 'tcx> ConstCodegenMethods for CodegenCx<'gcc, 'tcx> {
    /// Returns the pointer to the string and its length.
    fn const_str(&self, s: &str) -> (RValue<'gcc>, RValue<'gcc>) {
        // 1. キャッシュ取得
        let mut const_str_cache = self.const_str_cache.borrow_mut();

        // 2. 既に登録済みか確認、未登録なら作成
        let str_global = const_str_cache.get(s).copied().unwrap_or_else(|| {
            // GCC API を使って文字列リテラルを生成
            let string = self.context.new_string_literal(s);

            // シンボル名を決定し、グローバル変数として宣言
            let sym = self.generate_local_symbol_name("str");
            let global = self.declare_private_global(&sym, self.val_ty(string));

            // キャッシュに保存して返す
            const_str_cache.insert(s.to_owned(), global);
            global
        });

        // 3. 長さを取得
        let len = s.len();

        // 4. ポインタ型へキャスト(C の `*const char` に相当)
        let cs = self.const_ptrcast(
            str_global.get_address(None),
            self.type_ptr_to(self.layout_of(self.tcx.types.str_).gcc_type(self)),
        );

        // 5. (ポインタ, 長さ) を返す
        (cs, self.const_usize(len as _))
    }
}

重要ポイント

  • キャッシュ:同じ文字列を複数回生成しないようにする
  • 型変換:Rust の
    &str
    → C の
    *const char
    に適切にキャスト
  • 長さ:C では文字列の終端は必ず 0 であるため、実際の長さを渡す

Rust バックエンドが行う追加情報・最適化

GCC(や LLVM)に渡す前に、Rust の知識を利用してコード生成時に属性を付与します。
例:参照は NULL になり得ないので

nonnull
属性を付けます。

// Rust コード
fn t(a: &i32) -> i32 { *a }

C 版(属性無し):

int t(int *a) {
    if (!a) return -1;
    return *a;
}

LLVM/GCC に

nonnull(1)
属性を付与すると、以下のようにコンパイルされます。

_attribute_((nonnull(1)))
int t(int *a) {
    return *a;  // NULL チェックが不要
}

なぜチェックを残す?
Rust の型情報を活かして最適化を行い、不要な分岐を削除します。


まとめ

  • Rust コンパイラはフロントエンドとバックエンドに分離されている。
  • GCC バックエンド(
    rustc_codegen_gcc
    )は、Rust の AST を GCC に渡す橋渡し役である。
  • libgccjit
    を介して AOT コンパイルが可能。
  • バックエンド実装ではキャッシュや型変換、属性付与などの最適化を行う。

このように、Rust のバックエンドは単なるコード生成だけでなく、コンパイラ独自の情報を活かして効率的なバイナリを作り出します。

この記事は私の猫にインスピレーションをもらって書きました。

同じ日のほかのニュース

一覧に戻る →

2025/12/17 6:14

Prediction: AI will make formal verification go mainstream

## Japanese Translation: > 記事は、人工知能がソフトウェアが仕様を満たしていることを数学的に証明する「形式検証」を、ニッチな研究活動から日常のエンジニアリング実務へと導くと主張しています。Coq、Isabelle、Lean、F*、Agda などの証明支援ツールはすでに OS カーネル、コンパイラ、暗号スタックなど大規模システムを形式的に検証することを可能にしています。現在では言語モデル型コーディングアシスタントが実装コードとそれに付随する証明スクリプトの両方をドラフトでき、極小の検証済みチェッカーは無効な証明を拒否し、AI エージェントが幻覚(hallucinate)した場合には再試行を強制します。2009 年に公開された seL4 マイクロカーネル(8,700 行の C コードで 20 人年と 20 万行の Isabelle コード)が示すように、従来は労力集約的な検証が行われてきましたが、世界中で数百人程度の専門家しかそのような証明を作成できず、コストはバグ修正費用を上回ることも多いです。著者は AI がこれらのコストを低減するにつれて、より多くのソフトウェアが形式検証され、人間によるレビューではなく AI 生成コードに依存するようになると予測しています。残された最大の障壁は正確な仕様書を書くことです——仕様書作成は証明より容易ですが、それでも専門知識を要します。AI は自然言語での要求を形式的に翻訳する手助けができるかもしれませんが、ニュアンスの損失リスクがあります。広範な採用はバグと脆弱性を削減し、エンジニアリングワークフローを再構築し、仕様書作成に関する新たなスキルを要求しますが、文化的受容こそが主流化への主要障壁となります。

2025/12/17 1:54

alpr.watch

## Japanese Translation: 米国全土の自治体は急速に監視技術を導入しており、既に8万台以上のカメラが設置されています。 新しいプラットフォーム **alpr.watch** は、市議会の議題リストから「flock」「license plate reader」「ALPR」などのキーワードをスキャンし、それぞれの議論をマップ上にピン留めします。住民はこれらのシステムについて議論が行われている場所を確認でき、必要に応じて行動を起こすことができます。ユーザーはメールアドレスで登録すると、自分のエリア内の会議通知を受け取ることが可能です。 12月中旬以前に収集された全データは未検証です。今後提出される情報は正確性を確認するためにモデレートされます。 **ALPR** システムは、24時間365日すべての通行車両からナンバープレートデータを取得し、読み取り、保存します。最大規模のメーカーの一つである **Flock Safety** は、そのユニットを直接近隣住民や警察署に販売しています。カメラは機関・管轄区域間でデータを共有し、数百万の米国人を追跡する監視ウェブを構築します。これらのシステムは、意図された範囲を超えて拡張されることが多く、例えば移民取り締まりに使用されたり、恒久的なインフラストラクチャーとなったりします。 Electronic Frontier Foundation(EFF)、ACLU、Fight for the Future、STOP、Institute for Justice、および地域コミュニティグループなどのプライバシー擁護団体は、すでにこれらの動向を監視しています。 *この改訂された要約はリストからすべての主要ポイントを反映し、未確認推測を含まず、メインメッセージを明確かつ簡潔に保っています。*

2025/12/17 4:20

No Graphics API