Skip to content

Commit

Permalink
Merge pull request #14 from t3tra-dev/feat/rename
Browse files Browse the repository at this point in the history
  • Loading branch information
t3tra-dev authored Feb 17, 2025
2 parents b7d0336 + 2ba1fa7 commit 305bdcb
Show file tree
Hide file tree
Showing 41 changed files with 185 additions and 372 deletions.
158 changes: 78 additions & 80 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
> Note: Please do not send pull requests to this repository.
> [!NOTE]
> Please do not send pull requests to this repository.
# pyc - Python to LLVM IR transpiler & compiler
# Lython - Python compiler toolchain based on LLVM

> [!TIP]
> Searching for **pyc**? You are in the right repo. **pyc** has been renamed to **Lython**.
```
🚀 Benchmark Results
Expand All @@ -13,7 +17,7 @@
│ C(O3) │ 17.30ms (x0.76) │ 9227465 │
│ C(O2) │ 17.88ms (x0.79) │ 9227465 │
│ LLVM(O2) │ 20.32ms (x0.90) │ 9227465 │
Python(pyc) │ 22.68ms (x1.00) │ 9227465 │
Lython │ 22.68ms (x1.00) │ 9227465 │
│ LLVM(O0) │ 23.15ms (x1.02) │ 9227465 │
│ C(O0) │ 33.34ms (x1.47) │ 9227465 │
│ Bun │ 54.52ms (x2.40) │ 9227465 │
Expand All @@ -24,14 +28,14 @@
└────────────────┴───────────────────┴──────────┘
```

**pyc** は、Python コードを LLVM IR に変換 (トランスパイル) し、さらに機械語へコンパイルすることを目指した実験的プロジェクトです。
CPython とは異なる形で静的型付けのように扱いながらPythonソースを解析し`clang` などのツールチェーンを利用してネイティブバイナリを生成することを目標としています
**Lython** は、Python コードを LLVM IR に変換 (トランスパイル) し、機械語へコンパイルすることを目指した実験的プロジェクトです。
LLVM を基盤にしつつ、CPython とは異なる形で静的型付けのように扱いながら Python ソースを解析し`clang` などのツールチェーンでネイティブバイナリを生成することをゴールとしています

## Features
- Python AST をトラバースし、LLVM IR を生成
- 生成された IR をさらに `clang``llc` などでコンパイルして実行ファイル化を目指す
- Python によるソースコード解析部分は静的型に近い形で扱う実験的実装
- ランタイム (`runtime/`) として最低限のメモリ管理・`print` 関数などを C 実装で提供
- **Python AST のトラバース**: Python の抽象構文木を解析して LLVM IR を生成
- **ツールチェーン活用**: 生成した IR をさらに `clang``llc` などでコンパイルし、実行ファイル化を狙う
- **実験的な静的型解析**: Python によるソースコード解析部分を簡易的に静的型チェック風に処理
- **ランタイム (`runtime/`) の自前実装**: メモリ管理 (Boehm GC) や `print` 関数などを最低限 C 言語で提供

---

Expand All @@ -50,16 +54,17 @@ CPython とは異なる形で静的型付けのように扱いながらPythonソ
│ ├── llfib.ll
│ └── pyfib.py
├── helloworld.ll # サンプルの "Hello, world!" LLVM IR
├── pyc/
│ ├── __init__.py
│ ├── __main__.py # `python -m pyc` で呼ばれるエントリーポイント
│ ├── codegen/ # Python -> LLVM IR 変換ロジック
│ │ ├── ir/ # LLVM IR を構築するためのビルダー等
│ │ └── visitors/ # 各種 AST ノードへの Visitor 実装
│ └── compiler/ # 生成された LLVM IR をバイナリに変換するロジック (ll2bin など)
├── src # メインソース
│ └── lython
│ ├── __init__.py
│ ├── __main__.py # CLIのエントリポイント
│ ├── codegen
│ │ ├── ir/ # LLVM IR を構築するためのビルダー等
│ │ └── visitors/ # 各種 AST ノードへの Visitor 実装
│ └── compiler/ # 生成された LLVM IR をバイナリに変換するロジック (ll2bin など)
├── pyproject.toml # Python プロジェクト管理用 (PEP 621)
├── runtime/ # C で実装したランタイム
│ └── builtin/ # ビルトインの関数や型
├── runtime/ # C で実装したランタイム (Boehm GC)
│ └── builtin/
│ ├── functions.c
│ ├── functions.h
│ ├── types.c
Expand All @@ -81,120 +86,113 @@ CPython とは異なる形で静的型付けのように扱いながらPythonソ
このリポジトリでは [uv](https://docs.astral.sh/uv) というパッケージ管理ツールを使用しています。
Python 3.12 以上が必要です (`.python-version` で 3.12 を指定しています)。

1. **uv のインストール**
Unix:
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
Windows:
```bash
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
```

2. **依存関係の同期**
1. **uv のインストール**
- **Unix (Linux/macOS)**:
```bash
curl -LsSf https://astral.sh/uv/install.sh | sh
```
- **Windows**:
```powershell
powershell -c "irm https://astral.sh/uv/install.ps1 | iex"
```
2. **依存関係の同期**
```bash
uv sync
```
`uv.lock` の内容に従って各種パッケージ (black, isort, rich など) をインストールします。

これにより `uv.lock` の内容に従い、black, isort, rich などをまとめてインストールします。
3. **コンパイラツールチェーン**
LLVM/Clang がインストールされている必要があります。
`clang --version``llc --version` が使用できる状態にしてください (環境に応じてインストール)。

4. **ランタイムのビルド**
```bash
make
```
Makefileに基づき `runtime.o` を生成します。
`make clean` でキャッシュやライブラリバイナリを消去できます。
- LLVM/Clang が必要です。`clang --version``llc --version` が使用できる状態にしておきましょう。
4. **ランタイムのビルド**
- ルートディレクトリにある `Makefile` を使い、`runtime.o` を生成します:
```bash
make
```
- `make clean` でキャッシュやバイナリを削除可能です。

---

## 使用方法

### LLVM IR の生成

```bash
python -m pyc --emit-llvm <input-path>
```
### 1. LLVM IR の生成

例: `source.py` を LLVM IR 化して `source.py.ll` を出力する:
```bash
python -m pyc --emit-llvm source.py
python -m lythonc --emit-llvm <input-path>
```
実行後、同じフォルダに `source.py.ll` が生成されます。

### バイナリへのコンパイル
- 例:
```bash
python -m lythonc --emit-llvm source.py
```
実行後、`source.py.ll` が同一ディレクトリに生成されます。

```bash
python -m pyc --compile <input-path> <output-path>
```
### 2. バイナリへのコンパイル

例: `source.py` を機械語バイナリにコンパイルする:
```bash
python -m pyc --compile source.py main
python -m lythonc --compile <input-path> <output-path>
```
実行後、 `main` が生成される想定です。
- 例:
```bash
python -m lythonc --compile source.py main
```
実行後、 `main` バイナリが生成されます。

### AST のダンプ
### 3. AST のダンプ

```bash
python -m pyc --dump-ast <input-path>
python -m lythonc --dump-ast <input-path>
```
Python の AST (抽象構文木) を文字列としてダンプします。
内部的には `ast.dump()` 相当の機能を使用しています。
- Python の AST (抽象構文木) を文字列としてダンプします。内部的に `ast.dump()` を利用しています。
---
## ベンチマーク
`bench.py` を使うと、以下のような言語/コンパイルパターンでフィボナッチ (n=35) の実行時間を比較できます:
`bench.py` を使うと、以下のような言語/ランタイム/コンパイルパターンでフィボナッチ (n=35) の実行時間を比較できます:
- Node.js / Bun / Deno (JavaScript)
- C (clang) with -O0, -O1, -O2, -O3
- LLVM IR (clang) with -O0, -O1, -O2, -O3
- Python (pyc で LLVM IR 化したバイナリ)
- Python (CPython), Python(no GIL) (3.13 スレッドフリー版など)
- **Lython**
- Python (CPython), Python(no GIL)
#### 使い方
```bash
python bench.py
```

スクリプトの冒頭 `setup()` 関数で C や LLVM IR のコンパイルを行い、その後各エグゼを繰り返し呼び出して平均実行時間を比較します
結果はターミナルに表形式で表示されます (内部で `rich` を使用)
- スクリプト内の `setup()` 関数で事前に C や LLVM IR のコンパイルを行い、その後それぞれ実行して平均実行時間を測定します
- 結果はターミナル上に表形式(`rich`)で出力されます

---

## ランタイム

`runtime/` ディレクトリ以下に、C 言語で実装された最小限のランタイムが含まれています
`runtime/` ディレクトリ配下に C言語で実装した最小限のランタイム(Boehm GC 使用)が置かれています

- `builtin/functions.c` / `builtin/functions.h`
- `PyInt_FromI32`, `PyList_New`, `int2str`, `print` などの関数を提供
- LLVM IR 上で `declare` してコールすることで、Python の組み込み風の機能を実装
- `builtin/types.c` / `builtin/types.h`
- `String`, `PyInt`, `PyList` などの型を提供
- `builtin/functions.c` から操作される擬似的に再現された Python 固有の型を提供
- `builtin/functions.c / .h`
- `PyInt_FromI32`, `PyList_New`, `int2str`, `print` などを提供
- LLVM IR から `declare` 呼び出しすることで、Python 組み込み風の関数を実装
- `builtin/types.c / .h`
- `String`, `PyInt`, `PyList` などの型を定義
- 動的メモリ管理は Boehm GC に任せ、Python 的なオブジェクトを簡易的に再現

このランタイムをリンクして最終的なバイナリを生成することにより`print("Hello, world!")` などが動作します
これらのランタイムをリンクすることで`print("Hello, world!")` やリスト操作などの処理が可能になります

---

## 今後の予定 / 注意点

- **型推論の強化**: 現在は非常に簡易的に int/str などを仮定しているのみ。関数呼び出しにおける引数・戻り値の型チェックなどは未実装に近いです。
- **制御構文の拡張**: `if` 以外の制御構文 (`while`, `for`, `try` など) はまだ多くが未実装。
- **クラス・例外対応**: クラス定義や例外処理など、Python の主要機能のほとんどは未対応。
- **最適化パス**: 生成した LLVM IR をどのように最適化するかは今後の課題です。
- **Windows など他プラットフォーム対応**: 開発環境は Unix 系 (Linux, macOS) を想定しています。Windows での動作確認は限定的です。
- **型推論の強化**: まだ `int` / `str` など一部型にしか対応していない
- **制御構文の拡張**: `while`, `for`, `try` やクラス定義は未実装
- **最適化パス**: ほぼ `clang -O2` などに丸投げ。将来的に LLVM の最適化パスをカスタムする可能性あり
- **Windows 等のサポート**: 開発は主に Unix 系 (Linux, macOS) を想定。Windows での検証は限定的です

本プロジェクトはあくまで実験的段階のため、上記のように不完全な部分や将来的に大きな変更が入る可能性があります。
本プロジェクトは実験的段階のため、今後仕様変更が入る場合があります。
興味を持っていただけた方は、連載ブログ記事やサンプルを参考に、ぜひ試してみてください!

---

## ライセンス

本リポジトリのソースコードは、特記がない限り [MIT License](https://opensource.org/licenses/MIT) で配布されています。
詳細はソースコード内の記述(`pyc/__init__.py` など)をご参照ください。
詳細はソースコード内の記述(`lython/__init__.py` など)をご参照ください。
8 changes: 4 additions & 4 deletions bench.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ def setup() -> None:
for opt in optimization_levels:
subprocess.run(f"clang ./benchmark/llfib.ll -o llfib_{opt} -{opt}".split())

subprocess.run("python -m pyc --compile ./benchmark/pyfib.py pyfib".split())
subprocess.run("python -m lythonc --compile ./benchmark/pyfib.py pyfib".split())


def run_command(command: str) -> Tuple[str, float]:
Expand Down Expand Up @@ -59,7 +59,7 @@ def run_benchmarks() -> List[BenchmarkResult]:
"LLVM(O1)": "./llfib_O1",
"LLVM(O2)": "./llfib_O2",
"LLVM(O3)": "./llfib_O3",
"Python(pyc)": "./pyfib",
"Lython": "./pyfib",
"Python": "python ./benchmark/pyfib.py",
"Python(no GIL)": "python3.13t -X gil=1 ./benchmark/pyfib.py"
}
Expand All @@ -80,13 +80,13 @@ def display_results(results: List[BenchmarkResult]):
table.add_column("time", style="green")
table.add_column("result", style="yellow")

pyc_time = next((result.execution_time for result in results if result.name == "Python(pyc)"), None)
lython_time = next((result.execution_time for result in results if result.name == "Lython"), None)

sorted_results = sorted(results, key=lambda x: x.execution_time)

for result in sorted_results:
# "Python(pyc)"を基準に相対速度を計算
relative_speed = f"(x{result.execution_time / pyc_time:.2f})" # type: ignore
relative_speed = f"(x{result.execution_time / lython_time:.2f})" # type: ignore
time_str = f"{result.execution_time * 1000:.2f}ms {relative_speed}"
table.add_row(result.name, time_str, f"{result.output} ")

Expand Down
2 changes: 1 addition & 1 deletion flake.nix
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
pkgs = nixpkgs.legacyPackages.x86_64-linux;
in {
packages.x86_64-linux.build = pkgs.stdenv.mkDerivation {
name = "pyc";
name = "lython";
nativeBuildInputs = with pkgs; [
boehmgc
bun
Expand Down
11 changes: 10 additions & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[project]
name = "pyc"
name = "lython"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
Expand All @@ -10,5 +10,14 @@ dependencies = []
dev = [
"black>=24.10.0",
"isort>=5.13.2",
"lython",
"rich>=13.9.4",
]

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
only-include = ["src"]
sources = ["src"]
70 changes: 0 additions & 70 deletions source.py.ll

This file was deleted.

Loading

0 comments on commit 305bdcb

Please sign in to comment.