Lock in $30 Savings on PRO—Offer Ends Soon! ⏳

Python札幌 LT資料

Avatar for t3tra t3tra
December 18, 2025

Python札幌 LT資料

私が半年くらい前から作っているコンパイラの紹介と進捗です。

Avatar for t3tra

t3tra

December 18, 2025
Tweet

Other Decks in Programming

Transcript

  1. Python Syntax, C Performance, Powered by Type Theory NAME OF

    PROJECT: Lython PRESENTED BY: t3tra Python 札幌 シーズンXI Vol.1 2025 年・年末スペシャル Lython a compiler for Python 1/15
  2. What is Lython? Lython とは? 静的型付けPython 型アノテーションを必須とし、静的に解釈 LLVM/MLIR ベース 独自のDialect

    を経由しネイティブコードへコンパイル シングルバイナリ 実行可能ファイルでの配布が可能 2/15 設計思想 既存の文法の中で言語機能を拡張, 安全性を理論的に定式化・保証 ユーザーの仕事 ユーザーはPython の文法で書く ( 文法レベルでの独自拡張は無し) コンパイラの仕事 全体の検証・最適化, 暗黙の型変換を絶対に行わない
  3. Why MLIR? LLVM compiler infrastructure のMLIR を用いた理由 LLVM IR 強力だが、Python

    の高水準な概念 ( クラス、オブジェクトシステム、etc...) との距離が遠すぎる MLIR (Multi-Level IR) 独自の「ダイアレクト ( 中間表現) 」を定義できる Python Dialect を定義し、Python の構造を保持したまま最適化 段階的にLLVM IR へとLowering ( 変換) 3/15 LLVM の資産 LLVM はC/C++ やRust, Swift, Julia, Zig などで幅広く使われている 様々な最適化パスからJIT までコンパイラ基盤としての実績
  4. Two Worlds Lython では、CPython 互換のオブジェクト (Boxed) とC 言語的なプリミティブ (Unboxed) を共存させています

    Boxed World (PyObject) 従来のPython 同様、参照カウントGC で管理 int (PyLongObject), float (PyFloatObject), str (PyUnicodeObject) etc... Unboxed World (Primitive) C 言語ライクな生の値で、GC なし& オーバーヘッドなし Int[8], Int[32], Float[64], etc... Design 暗黙の型変換を禁止し、明示的な変換を強制 4/15
  5. Inspiration: Modal Logic 2 つの世界を扱う上で「様相論理」の考え方を取り入れています 様相論理とは 必然性 □ や可能性 ◇

    といった様相を扱う論理体系 可能世界論 (Kripke Semantics) 世界と世界の到達可能性 Lython における解釈 Boxed な世界と、Unboxed な世界は「別の世界」である 世界間の移動には明示的な「手続き」が必要 ( プリミティブのコンストラクタと from_prim 関数が相当) @native な関数内は「純粋なプリミティブの世界」であり、PyObject の存在は許されない (MLIR Verifier で保証) 5/15
  6. Quantitative Type Theory 量的型理論による参照カウント最適化 課題 参照カウント (RefCounting) は遅い。特にCPython ではメモリを丁寧に扱うため、かなりのコストが掛かる QTT

    とは 変数が「何回使われるか」を型レベルで扱う理論 (0 回 / 1 回 / 複数回) Lython のアプローチ 変数の消費回数を追跡 MLIR のLowering パスで、不要な incref / decref を削除 6/15 結果 メモリ安全を保証 & GC コストを大幅に削減
  7. Example: Fibonacci CPython 互換オブジェクトと固有プリミティブの比較 CPython 互換オブジェクト def fib(n: int) ->

    int: if n <= 1: return n return fib(n - 1) + fib(n - 2) print(fib(35)) GC overhead ・arbitrary-precision integer 7/15 固有プリミティブ from lyrt import from_prim, native from lyrt.prim import Int p1 = Int[32](1) p2 = Int[32](2) @native(gc="none") def fib(n: Int[32]) -> Int[32]: if n <= p1: return n return fib(n - p1) + fib(n - p2) print(from_prim(fib(Int[32](35)))) No GC, Machine Code (Just like C) Valid as CPython syntax
  8. Example: Fibonacci CPython 互換オブジェクトにおける実際のGC 最適化の例 [ 比較 n <= 1]

    PyLong_FromLong(1) → INCREF ( 定数 1) PyObject_RichCompare() → INCREF ( 比較結果 bool) 使用後 → DECREF ( 定数 1) 判定後 → DECREF ( 比較結果 ) [fib(n-1) の呼び出し ] PyLong_FromLong(1) → INCREF ( 定数 1) PyNumber_Subtract() → INCREF (n-1 結果 ) 減算後 → DECREF ( 定数 1) PyTuple_New(1) → INCREF ( 引数タプル ) PyTuple_SetItem() → 所有権移動 (n-1 を tuple に ) 関数呼び出し → INCREF ( 戻り値 ) 呼び出し後 → DECREF ( 引数タプル ) [fib(n-2) の呼び出し ] PyLong_FromLong(2) → INCREF ( 定数 2) PyNumber_Subtract() → INCREF (n-2 結果 ) 減算後 → DECREF ( 定数 2) PyTuple_New(1) → INCREF ( 引数タプル ) PyTuple_SetItem() → 所有権移動 関数呼び出し → INCREF ( 戻り値 ) 呼び出し後 → DECREF ( 引数タプル ) [ 加算 fib(n-1) + fib(n-2)] PyNumber_Add() → INCREF ( 加算結果 ) 加算後 → DECREF (fib(n-1) 結果 ) 加算後 → DECREF (fib(n-2) 結果 ) 8/15 最適化前 (CPython インタプリタ同等) 約 12 INCREF + 10 DECREF = 22 参照カウント操作
  9. Example: Fibonacci CPython 互換オブジェクトにおける実際のGC 最適化の例 [ 比較 n <= 1]

    LyLong_FromI64(1) → 小整数キャッシュ (INCREF 不要 ) LyLong_Compare() → 直接 i32 返却 icmp sle → 直接 i1 比較 (Bool boxing 削除 ) ✗ DECREF 不要 ( 小整数 + Bool elimination) [fib(n-1) の呼び出し ] ✗ 定数 1 再利用 ( 共通部分式除去 ; CSE) 、 INCREF 不要 LyLong_Sub() → INCREF (n-1 結果 ) ✗ タプル作成なし ( 直接呼び出しに最適化 ) 関数呼び出し → INCREF ( 戻り値 ) 呼び出し後 → DECREF (n-1 結果 ) ← 1 回だけ [fib(n-2) の呼び出し ] LyLong_FromI64(2) → 小整数キャッシュ (INCREF 不要 ) LyLong_Sub() → INCREF (n-2 結果 ) ✗ タプル作成なし ( 直接呼び出しに最適化 ) 関数呼び出し → INCREF ( 戻り値 ) 呼び出し後 → DECREF (n-2 結果 ) ← 1 回だけ [ 加算 fib(n-1) + fib(n-2)] LyLong_Add() → INCREF ( 加算結果 ) 加算後 → DECREF (fib(n-1) 結果 ) 加算後 → DECREF (fib(n-2) 結果 ) 9/15 最適化前 (CPython インタプリタ同等) 約 12 INCREF + 10 DECREF = 22 参照カウント操作 最適化後 5 INCREF + 4 DECREF = 9 参照カウント操作
  10. カテゴリ CPython Lython (JIT) 参照カウント操作 ~22 ~9 関数呼び出しオーバーヘッド ~15 ~2

    バイトコード実行 ~40 0 オブジェクト生成 6 4 合計 ~83 ~15 実行時間 (fib(40)) 7305 ms ± 126 ms (x 1.0) 2983 ms ± 176 ms (x 2.5) Example: Fibonacci CPython 互換オブジェクトにおける計算量の比較 10/15
  11. Example: Fibonacci CPython 互換オブジェクトと固有プリミティブの比較 CPython 互換オブジェクト def fib(n: int) ->

    int: if n <= 1: return n return fib(n - 1) + fib(n - 2) print(fib(35)) GC overhead ・arbitrary-precision integer 11/15 固有プリミティブ from lyrt import from_prim, native from lyrt.prim import Int p1 = Int[32](1) p2 = Int[32](2) @native(gc="none") def fib(n: Int[32]) -> Int[32]: if n <= p1: return n return fib(n - p1) + fib(n - p2) print(from_prim(fib(Int[32](35)))) No GC, Machine Code (Just like C) Valid as CPython syntax
  12. Example: Fibonacci Lython 固有プリミティブにおける高速化 12/15 Primitive types Int[32], Float[64] といった明示的かつCPython

    の文法として妥当な型アノテーション @native decorator 「関数全体をUnboxed World に閉じてコンパイルする」という宣言 @native 内でPyObject (Boxed な値) が生じる操作はコンパイルエラー One-to-one correspondence with C ABI 型が全てC 準拠なのでほぼ「Python の文法でC を書く」形 オーバーフローなどを許容するが、代わりに高速 ユーザーは自身の目的に応じて明示的に選択できる
  13. カテゴリ CPython Lython Primitive (JIT) 実行時間 (fib(40)) 7305 ms ±

    126 ms (x 1.0) 327.7 ms ± 50.5 ms (x22.3) Example: Fibonacci CPython 互換オブジェクトにおける計算量の比較 13/15 Without using arbitrary-precision integers 多倍長整数を用いないため、動的メモリ確保等のコストが大幅に省略できる オーバーフローする可能性が生まれる Provide C ABI-based FFI 最も使われているABI (Application Binary Interface) であるC ABI を用いて関数をエクスポート 他の言語からでも dlopen (Unix) / LoadLibrary (Windows) でこの関数を使うことが出来る これがFFI (Foreign Function Interface) の仕組み
  14. Roadmap 今後の展望 Current status AOT/JIT コンパイル: 動作済み vectorcall: 実装済み 基本演算のLowering:

    実装済み 基本的なクラスの定義とインスタンス化: 実装済み 14/15 Future Work: 高階プリミティブ: Vector, Matrix, Tensor BLAS/LAPACK へ委譲し高速化 WASM/WASI support: ブラウザやエッジ環境での実行 クロスコンパイル abi3 互換レイヤ
  15. Summary まとめ Lython Python の見た目をした静的型付け言語 Theoretical Backbone MLIR: 最適化基盤 Modal

    Logic: Boxed/Unboxed の世界の分離と安全性 QTT: 参照カウントの静的最適化 Goal Python の体験・C の速度・Rust 的な堅牢さ 15/15