Implement Phase 10.7 control-flow hooks in CraneliftBuilder: block vectors, switch/seal, br_if/jump; adjust begin_function and emit sites to honor current block. (Feature-gated)
This commit is contained in:
@ -0,0 +1,410 @@
|
|||||||
|
# PythonParserBox ビルトインBox実装フロー
|
||||||
|
~CPythonパーサー統合とPhase 1実装の具体的な流れ~
|
||||||
|
|
||||||
|
## 🎯 全体の実装フロー
|
||||||
|
|
||||||
|
### Step 1: ビルトインBoxとしての基盤作成
|
||||||
|
```
|
||||||
|
1. src/boxes/python_parser_box/mod.rs を作成
|
||||||
|
2. BoxBase + BoxCore統一アーキテクチャに準拠
|
||||||
|
3. PythonParserBoxの基本構造を定義
|
||||||
|
4. src/boxes/mod.rs に登録
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: pyo3統合とCPythonパーサー接続
|
||||||
|
```
|
||||||
|
1. Cargo.tomlに pyo3依存関係追加
|
||||||
|
2. Python環境の自動初期化設定
|
||||||
|
3. ast.parse()へのFFIブリッジ実装
|
||||||
|
4. JSON中間表現への変換
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Phase 1機能の実装
|
||||||
|
```
|
||||||
|
1. 最小限のAST変換(def, if, for, return)
|
||||||
|
2. 基本的な式の変換(演算子、関数呼び出し)
|
||||||
|
3. Nyash ASTへのマッピング
|
||||||
|
4. テストケースの作成
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📝 具体的な実装コード
|
||||||
|
|
||||||
|
### 1. ビルトインBox定義(src/boxes/python_parser_box/mod.rs)
|
||||||
|
```rust
|
||||||
|
use crate::core::{BoxBase, BoxCore, NyashBox};
|
||||||
|
use crate::ast;
|
||||||
|
use pyo3::prelude::*;
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
pub struct PythonParserBox {
|
||||||
|
base: BoxBase,
|
||||||
|
py_helper: Arc<Mutex<PyHelper>>, // Python実行環境
|
||||||
|
}
|
||||||
|
|
||||||
|
impl BoxCore for PythonParserBox {
|
||||||
|
fn box_id(&self) -> u64 {
|
||||||
|
self.base.box_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parent_type_id(&self) -> Option<std::any::TypeId> {
|
||||||
|
self.base.parent_type_id()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn fmt_box(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
|
||||||
|
write!(f, "PythonParserBox#{}", self.box_id())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl NyashBox for PythonParserBox {
|
||||||
|
fn type_name(&self) -> &'static str {
|
||||||
|
"PythonParserBox"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clone_box(&self) -> Box<dyn NyashBox> {
|
||||||
|
Box::new(PythonParserBox {
|
||||||
|
base: BoxBase::new(),
|
||||||
|
py_helper: self.py_helper.clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. メソッド実装(Phase 1対応)
|
||||||
|
```rust
|
||||||
|
impl PythonParserBox {
|
||||||
|
// コンストラクタ
|
||||||
|
pub fn new() -> Result<Self, String> {
|
||||||
|
// Python環境の初期化
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
let helper = PyHelper::new(py)?;
|
||||||
|
Ok(PythonParserBox {
|
||||||
|
base: BoxBase::new(),
|
||||||
|
py_helper: Arc::new(Mutex::new(helper)),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// Python code → JSON AST
|
||||||
|
pub fn parse_to_json(&self, code: &str) -> Result<String, String> {
|
||||||
|
let helper = self.py_helper.lock().unwrap();
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
helper.parse_to_json(py, code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// JSON AST → Nyash AST(Phase 1機能のみ)
|
||||||
|
pub fn json_to_nyash_ast(&self, json: &str) -> Result<ast::Program, String> {
|
||||||
|
let py_ast: Phase1PythonAst = serde_json::from_str(json)
|
||||||
|
.map_err(|e| format!("JSON parse error: {}", e))?;
|
||||||
|
|
||||||
|
let converter = Phase1Converter::new();
|
||||||
|
converter.convert(py_ast)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 直接実行(最初はCPython exec、段階的にMIR実行へ)
|
||||||
|
pub fn run(&self, code: &str) -> Result<Box<dyn NyashBox>, String> {
|
||||||
|
// Phase 1: CPython exec経由
|
||||||
|
let helper = self.py_helper.lock().unwrap();
|
||||||
|
Python::with_gil(|py| {
|
||||||
|
helper.exec_code(py, code)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Python側ヘルパー実装
|
||||||
|
```rust
|
||||||
|
// Pythonコードを文字列として埋め込み
|
||||||
|
const PYTHON_HELPER_CODE: &str = r#"
|
||||||
|
import ast
|
||||||
|
import json
|
||||||
|
|
||||||
|
def ast_to_dict(node):
|
||||||
|
"""Phase 1: 基本的なAST要素のみ変換"""
|
||||||
|
if isinstance(node, ast.Module):
|
||||||
|
return {
|
||||||
|
"type": "Module",
|
||||||
|
"body": [ast_to_dict(stmt) for stmt in node.body]
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.FunctionDef):
|
||||||
|
return {
|
||||||
|
"type": "FunctionDef",
|
||||||
|
"name": node.name,
|
||||||
|
"args": [arg.arg for arg in node.args.args],
|
||||||
|
"body": [ast_to_dict(stmt) for stmt in node.body]
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.Return):
|
||||||
|
return {
|
||||||
|
"type": "Return",
|
||||||
|
"value": ast_to_dict(node.value) if node.value else None
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.BinOp):
|
||||||
|
return {
|
||||||
|
"type": "BinOp",
|
||||||
|
"op": node.op.__class__.__name__,
|
||||||
|
"left": ast_to_dict(node.left),
|
||||||
|
"right": ast_to_dict(node.right)
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.Call):
|
||||||
|
return {
|
||||||
|
"type": "Call",
|
||||||
|
"func": ast_to_dict(node.func),
|
||||||
|
"args": [ast_to_dict(arg) for arg in node.args]
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.Name):
|
||||||
|
return {
|
||||||
|
"type": "Name",
|
||||||
|
"id": node.id
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.Constant):
|
||||||
|
return {
|
||||||
|
"type": "Constant",
|
||||||
|
"value": node.value
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.If):
|
||||||
|
return {
|
||||||
|
"type": "If",
|
||||||
|
"test": ast_to_dict(node.test),
|
||||||
|
"body": [ast_to_dict(stmt) for stmt in node.body],
|
||||||
|
"orelse": [ast_to_dict(stmt) for stmt in node.orelse]
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.For):
|
||||||
|
return {
|
||||||
|
"type": "For",
|
||||||
|
"target": ast_to_dict(node.target),
|
||||||
|
"iter": ast_to_dict(node.iter),
|
||||||
|
"body": [ast_to_dict(stmt) for stmt in node.body]
|
||||||
|
}
|
||||||
|
elif isinstance(node, ast.While):
|
||||||
|
return {
|
||||||
|
"type": "While",
|
||||||
|
"test": ast_to_dict(node.test),
|
||||||
|
"body": [ast_to_dict(stmt) for stmt in node.body]
|
||||||
|
}
|
||||||
|
else:
|
||||||
|
# Phase 1では未対応
|
||||||
|
return {"type": "Unsupported", "node": str(type(node))}
|
||||||
|
|
||||||
|
def parse_to_json(code):
|
||||||
|
try:
|
||||||
|
tree = ast.parse(code)
|
||||||
|
return json.dumps(ast_to_dict(tree))
|
||||||
|
except Exception as e:
|
||||||
|
return json.dumps({"type": "Error", "message": str(e)})
|
||||||
|
"#;
|
||||||
|
|
||||||
|
struct PyHelper {
|
||||||
|
// Python側のヘルパー関数への参照を保持
|
||||||
|
parse_func: PyObject,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PyHelper {
|
||||||
|
fn new(py: Python) -> PyResult<Self> {
|
||||||
|
// ヘルパーコードをPythonで実行
|
||||||
|
let helpers = PyModule::from_code(py, PYTHON_HELPER_CODE, "helper.py", "helper")?;
|
||||||
|
let parse_func = helpers.getattr("parse_to_json")?.to_object(py);
|
||||||
|
|
||||||
|
Ok(PyHelper { parse_func })
|
||||||
|
}
|
||||||
|
|
||||||
|
fn parse_to_json(&self, py: Python, code: &str) -> Result<String, String> {
|
||||||
|
match self.parse_func.call1(py, (code,)) {
|
||||||
|
Ok(result) => result.extract::<String>(py)
|
||||||
|
.map_err(|e| format!("Extract error: {}", e)),
|
||||||
|
Err(e) => Err(format!("Parse error: {}", e))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Phase 1 AST変換器
|
||||||
|
```rust
|
||||||
|
struct Phase1Converter;
|
||||||
|
|
||||||
|
impl Phase1Converter {
|
||||||
|
fn new() -> Self {
|
||||||
|
Phase1Converter
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert(&self, py_ast: Phase1PythonAst) -> Result<ast::Program, String> {
|
||||||
|
match py_ast {
|
||||||
|
Phase1PythonAst::Module { body } => {
|
||||||
|
let mut items = vec![];
|
||||||
|
for stmt in body {
|
||||||
|
match self.convert_statement(stmt)? {
|
||||||
|
Some(item) => items.push(item),
|
||||||
|
None => {} // 未対応要素はスキップ
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(ast::Program { items })
|
||||||
|
}
|
||||||
|
_ => Err("Expected Module at top level".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_statement(&self, stmt: Phase1PythonAst) -> Result<Option<ast::ProgramItem>, String> {
|
||||||
|
match stmt {
|
||||||
|
Phase1PythonAst::FunctionDef { name, args, body } => {
|
||||||
|
// Python def → Nyash function
|
||||||
|
let params = args.into_iter()
|
||||||
|
.map(|arg| ast::Parameter { name: arg, ty: None })
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let nyash_body = self.convert_body(body)?;
|
||||||
|
|
||||||
|
Ok(Some(ast::ProgramItem::Function(ast::FunctionDef {
|
||||||
|
name,
|
||||||
|
params,
|
||||||
|
body: nyash_body,
|
||||||
|
return_type: None,
|
||||||
|
})))
|
||||||
|
}
|
||||||
|
Phase1PythonAst::Return { value } => {
|
||||||
|
let expr = value
|
||||||
|
.map(|v| self.convert_expression(v))
|
||||||
|
.transpose()?;
|
||||||
|
|
||||||
|
Ok(Some(ast::ProgramItem::Statement(ast::Statement::Return(expr))))
|
||||||
|
}
|
||||||
|
// 他の文も同様に変換
|
||||||
|
_ => Ok(None) // Phase 1では未対応
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn convert_expression(&self, expr: Phase1PythonAst) -> Result<ast::Expression, String> {
|
||||||
|
match expr {
|
||||||
|
Phase1PythonAst::BinOp { op, left, right } => {
|
||||||
|
let left = Box::new(self.convert_expression(*left)?);
|
||||||
|
let right = Box::new(self.convert_expression(*right)?);
|
||||||
|
|
||||||
|
let op = match op.as_str() {
|
||||||
|
"Add" => ast::BinaryOp::Add,
|
||||||
|
"Sub" => ast::BinaryOp::Sub,
|
||||||
|
"Mul" => ast::BinaryOp::Mul,
|
||||||
|
"Div" => ast::BinaryOp::Div,
|
||||||
|
_ => return Err(format!("Unsupported operator: {}", op))
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(ast::Expression::BinaryOp { op, left, right })
|
||||||
|
}
|
||||||
|
Phase1PythonAst::Constant { value } => {
|
||||||
|
// Python定数 → Nyashリテラル
|
||||||
|
match value {
|
||||||
|
serde_json::Value::Number(n) => {
|
||||||
|
if let Some(i) = n.as_i64() {
|
||||||
|
Ok(ast::Expression::Integer(i))
|
||||||
|
} else if let Some(f) = n.as_f64() {
|
||||||
|
Ok(ast::Expression::Float(f))
|
||||||
|
} else {
|
||||||
|
Err("Unsupported number type".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
serde_json::Value::String(s) => {
|
||||||
|
Ok(ast::Expression::String(s))
|
||||||
|
}
|
||||||
|
serde_json::Value::Bool(b) => {
|
||||||
|
Ok(ast::Expression::Bool(b))
|
||||||
|
}
|
||||||
|
_ => Err("Unsupported constant type".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// 他の式も同様
|
||||||
|
_ => Err("Unsupported expression in Phase 1".into())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 5. インタープリター統合(src/interpreter/builtins.rs)
|
||||||
|
```rust
|
||||||
|
// ビルトインBox登録に追加
|
||||||
|
pub fn register_builtin_boxes(env: &mut Environment) {
|
||||||
|
// 既存のBox登録...
|
||||||
|
|
||||||
|
// PythonParserBox追加
|
||||||
|
env.register_builtin_box("PythonParserBox", || {
|
||||||
|
match PythonParserBox::new() {
|
||||||
|
Ok(parser) => Arc::new(parser) as Arc<dyn NyashBox>,
|
||||||
|
Err(e) => panic!("Failed to initialize PythonParserBox: {}", e)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 6. 使用例とテストケース
|
||||||
|
```nyash
|
||||||
|
// test_python_parser_phase1.nyash
|
||||||
|
local py = new PythonParserBox()
|
||||||
|
|
||||||
|
// Phase 1: 基本的な関数定義と演算
|
||||||
|
local code = """
|
||||||
|
def add(x, y):
|
||||||
|
return x + y
|
||||||
|
|
||||||
|
def multiply(x, y):
|
||||||
|
return x * y
|
||||||
|
|
||||||
|
def calculate(a, b):
|
||||||
|
sum_val = add(a, b)
|
||||||
|
prod_val = multiply(a, b)
|
||||||
|
return sum_val + prod_val
|
||||||
|
"""
|
||||||
|
|
||||||
|
// パースしてJSON ASTを確認
|
||||||
|
local json_ast = py.parse_to_json(code)
|
||||||
|
print("JSON AST: " + json_ast)
|
||||||
|
|
||||||
|
// Nyash ASTに変換
|
||||||
|
local nyash_ast = py.json_to_nyash_ast(json_ast)
|
||||||
|
print("Conversion successful!")
|
||||||
|
|
||||||
|
// 実行(最初はCPython経由)
|
||||||
|
local result = py.run(code + "\nprint(calculate(10, 5))")
|
||||||
|
```
|
||||||
|
|
||||||
|
## 📊 段階的な実装計画
|
||||||
|
|
||||||
|
### Week 1: 基盤構築
|
||||||
|
- [ ] PythonParserBoxの基本構造
|
||||||
|
- [ ] pyo3統合とPython環境初期化
|
||||||
|
- [ ] parse_to_json基本実装
|
||||||
|
- [ ] エラーハンドリング
|
||||||
|
|
||||||
|
### Week 2: Phase 1変換器
|
||||||
|
- [ ] Phase1PythonAstの定義
|
||||||
|
- [ ] Phase1Converterの実装
|
||||||
|
- [ ] 基本的な文と式の変換
|
||||||
|
- [ ] テストケース作成
|
||||||
|
|
||||||
|
### Week 3: 統合とテスト
|
||||||
|
- [ ] インタープリター統合
|
||||||
|
- [ ] CPython exec経由の実行
|
||||||
|
- [ ] ベンチマーク準備
|
||||||
|
- [ ] ドキュメント整備
|
||||||
|
|
||||||
|
## 🚀 期待される成果
|
||||||
|
|
||||||
|
### Phase 1完了時点で実現できること:
|
||||||
|
1. **基本的なPythonコードの実行**
|
||||||
|
- 関数定義、算術演算、条件分岐、ループ
|
||||||
|
|
||||||
|
2. **Nyash ASTへの変換**
|
||||||
|
- 将来のMIR/JIT最適化への道筋
|
||||||
|
|
||||||
|
3. **統合開発環境**
|
||||||
|
- PythonコードとNyashコードの混在実行
|
||||||
|
|
||||||
|
4. **性能測定基盤**
|
||||||
|
- CPython実行 vs Nyash実行の比較
|
||||||
|
|
||||||
|
---
|
||||||
|
作成日: 2025-08-27
|
||||||
|
Phase 1実装の具体的な手順とコード例
|
||||||
@ -73,6 +73,9 @@ pub struct CraneliftBuilder {
|
|||||||
current_name: Option<String>,
|
current_name: Option<String>,
|
||||||
value_stack: Vec<cranelift_codegen::ir::Value>,
|
value_stack: Vec<cranelift_codegen::ir::Value>,
|
||||||
entry_block: Option<cranelift_codegen::ir::Block>,
|
entry_block: Option<cranelift_codegen::ir::Block>,
|
||||||
|
// Phase 10.7: basic block wiring state
|
||||||
|
blocks: Vec<cranelift_codegen::ir::Block>,
|
||||||
|
current_block_index: Option<usize>,
|
||||||
// Finalized function pointer (if any)
|
// Finalized function pointer (if any)
|
||||||
compiled_closure: Option<std::sync::Arc<dyn Fn(&[crate::backend::vm::VMValue]) -> crate::backend::vm::VMValue + Send + Sync>>,
|
compiled_closure: Option<std::sync::Arc<dyn Fn(&[crate::backend::vm::VMValue]) -> crate::backend::vm::VMValue + Send + Sync>>,
|
||||||
// Desired simple ABI (Phase 10_c minimal): i64 params count and i64 return
|
// Desired simple ABI (Phase 10_c minimal): i64 params count and i64 return
|
||||||
@ -184,7 +187,7 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
|
|
||||||
self.current_name = Some(name.to_string());
|
self.current_name = Some(name.to_string());
|
||||||
self.value_stack.clear();
|
self.value_stack.clear();
|
||||||
self.entry_block = None;
|
// Keep any pre-created blocks (from prepare_blocks)
|
||||||
|
|
||||||
// Minimal signature: (i64 x argc) -> i64? (Core-1 integer path)
|
// Minimal signature: (i64 x argc) -> i64? (Core-1 integer path)
|
||||||
let call_conv = self.module.isa().default_call_conv();
|
let call_conv = self.module.isa().default_call_conv();
|
||||||
@ -195,12 +198,18 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
self.ctx.func.name = cranelift_codegen::ir::UserFuncName::user(0, 0);
|
self.ctx.func.name = cranelift_codegen::ir::UserFuncName::user(0, 0);
|
||||||
|
|
||||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
|
// Prepare entry block: use pre-created block[0] if present, otherwise create
|
||||||
|
if self.blocks.is_empty() {
|
||||||
let block = fb.create_block();
|
let block = fb.create_block();
|
||||||
fb.append_block_params_for_function_params(block);
|
self.blocks.push(block);
|
||||||
fb.switch_to_block(block);
|
}
|
||||||
fb.seal_block(block);
|
let entry = self.blocks[0];
|
||||||
self.entry_block = Some(block);
|
fb.append_block_params_for_function_params(entry);
|
||||||
// Store builder back (drop at end_function)
|
fb.switch_to_block(entry);
|
||||||
|
// Entry block can be sealed immediately
|
||||||
|
fb.seal_block(entry);
|
||||||
|
self.entry_block = Some(entry);
|
||||||
|
self.current_block_index = Some(0);
|
||||||
fb.finalize();
|
fb.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -243,7 +252,8 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
use cranelift_frontend::FunctionBuilder;
|
use cranelift_frontend::FunctionBuilder;
|
||||||
// Recreate FunctionBuilder each emit (lightweight wrapper around ctx+fbc)
|
// Recreate FunctionBuilder each emit (lightweight wrapper around ctx+fbc)
|
||||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
|
||||||
|
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
||||||
let v = fb.ins().iconst(types::I64, val);
|
let v = fb.ins().iconst(types::I64, val);
|
||||||
self.value_stack.push(v);
|
self.value_stack.push(v);
|
||||||
self.stats.0 += 1;
|
self.stats.0 += 1;
|
||||||
@ -258,7 +268,8 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
let rhs = self.value_stack.pop().unwrap();
|
let rhs = self.value_stack.pop().unwrap();
|
||||||
let lhs = self.value_stack.pop().unwrap();
|
let lhs = self.value_stack.pop().unwrap();
|
||||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
|
||||||
|
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
||||||
let res = match op {
|
let res = match op {
|
||||||
BinOpKind::Add => fb.ins().iadd(lhs, rhs),
|
BinOpKind::Add => fb.ins().iadd(lhs, rhs),
|
||||||
BinOpKind::Sub => fb.ins().isub(lhs, rhs),
|
BinOpKind::Sub => fb.ins().isub(lhs, rhs),
|
||||||
@ -278,7 +289,8 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
let rhs = self.value_stack.pop().unwrap();
|
let rhs = self.value_stack.pop().unwrap();
|
||||||
let lhs = self.value_stack.pop().unwrap();
|
let lhs = self.value_stack.pop().unwrap();
|
||||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
|
||||||
|
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
||||||
let cc = match op {
|
let cc = match op {
|
||||||
CmpKind::Eq => IntCC::Equal,
|
CmpKind::Eq => IntCC::Equal,
|
||||||
CmpKind::Ne => IntCC::NotEqual,
|
CmpKind::Ne => IntCC::NotEqual,
|
||||||
@ -300,7 +312,8 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
use cranelift_frontend::FunctionBuilder;
|
use cranelift_frontend::FunctionBuilder;
|
||||||
self.stats.4 += 1;
|
self.stats.4 += 1;
|
||||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
|
||||||
|
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
||||||
if let Some(v) = self.value_stack.pop() {
|
if let Some(v) = self.value_stack.pop() {
|
||||||
fb.ins().return_(&[v]);
|
fb.ins().return_(&[v]);
|
||||||
} else {
|
} else {
|
||||||
@ -334,7 +347,8 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
.expect("declare import failed");
|
.expect("declare import failed");
|
||||||
|
|
||||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
|
||||||
|
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
||||||
let fref = self.module.declare_func_in_func(func_id, fb.func);
|
let fref = self.module.declare_func_in_func(func_id, fb.func);
|
||||||
let call_inst = fb.ins().call(fref, &args);
|
let call_inst = fb.ins().call(fref, &args);
|
||||||
if has_ret {
|
if has_ret {
|
||||||
@ -345,6 +359,64 @@ impl IRBuilder for CraneliftBuilder {
|
|||||||
}
|
}
|
||||||
fb.finalize();
|
fb.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ==== Phase 10.7 block APIs ====
|
||||||
|
fn prepare_blocks(&mut self, count: usize) {
|
||||||
|
use cranelift_frontend::FunctionBuilder;
|
||||||
|
if count == 0 { return; }
|
||||||
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
|
// Only create if not already created
|
||||||
|
if self.blocks.len() < count {
|
||||||
|
let to_create = count - self.blocks.len();
|
||||||
|
for _ in 0..to_create { self.blocks.push(fb.create_block()); }
|
||||||
|
}
|
||||||
|
fb.finalize();
|
||||||
|
}
|
||||||
|
fn switch_to_block(&mut self, index: usize) {
|
||||||
|
use cranelift_frontend::FunctionBuilder;
|
||||||
|
if index >= self.blocks.len() { return; }
|
||||||
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
|
fb.switch_to_block(self.blocks[index]);
|
||||||
|
self.current_block_index = Some(index);
|
||||||
|
fb.finalize();
|
||||||
|
}
|
||||||
|
fn seal_block(&mut self, index: usize) {
|
||||||
|
use cranelift_frontend::FunctionBuilder;
|
||||||
|
if index >= self.blocks.len() { return; }
|
||||||
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
|
fb.seal_block(self.blocks[index]);
|
||||||
|
fb.finalize();
|
||||||
|
}
|
||||||
|
fn br_if_top_is_true(&mut self, then_index: usize, else_index: usize) {
|
||||||
|
use cranelift_codegen::ir::{types, condcodes::IntCC};
|
||||||
|
use cranelift_frontend::FunctionBuilder;
|
||||||
|
if then_index >= self.blocks.len() || else_index >= self.blocks.len() { return; }
|
||||||
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
|
// Ensure we are in a block
|
||||||
|
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
|
||||||
|
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
||||||
|
// Take top-of-stack as cond; if it's i64, normalize to b1 via icmp_imm != 0
|
||||||
|
let cond_b1 = if let Some(v) = self.value_stack.pop() {
|
||||||
|
fb.ins().icmp_imm(IntCC::NotEqual, v, 0)
|
||||||
|
} else {
|
||||||
|
let zero = fb.ins().iconst(types::I64, 0);
|
||||||
|
fb.ins().icmp_imm(IntCC::NotEqual, zero, 0)
|
||||||
|
};
|
||||||
|
fb.ins().brif(cond_b1, self.blocks[then_index], &[]);
|
||||||
|
fb.ins().jump(self.blocks[else_index], &[]);
|
||||||
|
self.stats.3 += 1;
|
||||||
|
fb.finalize();
|
||||||
|
}
|
||||||
|
fn jump_to(&mut self, target_index: usize) {
|
||||||
|
use cranelift_frontend::FunctionBuilder;
|
||||||
|
if target_index >= self.blocks.len() { return; }
|
||||||
|
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||||
|
if let Some(idx) = self.current_block_index { fb.switch_to_block(self.blocks[idx]); }
|
||||||
|
else if let Some(b) = self.entry_block { fb.switch_to_block(b); }
|
||||||
|
fb.ins().jump(self.blocks[target_index], &[]);
|
||||||
|
self.stats.3 += 1;
|
||||||
|
fb.finalize();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "cranelift-jit")]
|
#[cfg(feature = "cranelift-jit")]
|
||||||
@ -397,6 +469,8 @@ impl CraneliftBuilder {
|
|||||||
current_name: None,
|
current_name: None,
|
||||||
value_stack: Vec::new(),
|
value_stack: Vec::new(),
|
||||||
entry_block: None,
|
entry_block: None,
|
||||||
|
blocks: Vec::new(),
|
||||||
|
current_block_index: None,
|
||||||
compiled_closure: None,
|
compiled_closure: None,
|
||||||
desired_argc: 0,
|
desired_argc: 0,
|
||||||
desired_has_ret: true,
|
desired_has_ret: true,
|
||||||
|
|||||||
Reference in New Issue
Block a user