Phase 11-12: LLVM backend initial, semantics layer, plugin unification
Major changes: - LLVM backend initial implementation (compiler.rs, llvm mode) - Semantics layer integration in interpreter (operators.rs) - Phase 12 plugin architecture revision (3-layer system) - Builtin box removal preparation - MIR instruction set documentation (26→Core-15 migration) - Cross-backend testing infrastructure - Await/nowait syntax support New features: - LLVM AOT compilation support (--backend llvm) - Semantics layer for interpreter→VM flow - Tri-backend smoke tests - Plugin-only registry mode Bug fixes: - Interpreter plugin box arithmetic operations - Branch test returns incorrect values Documentation: - Phase 12 README.md updated with new plugin architecture - Removed obsolete NYIR proposals - Added LLVM test programs documentation Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@ -28,6 +28,9 @@ pub trait IRBuilder {
|
||||
fn emit_jump(&mut self);
|
||||
fn emit_branch(&mut self);
|
||||
fn emit_return(&mut self);
|
||||
/// Select between two i64 values using top-of-stack condition (b1 or i64 0/1).
|
||||
/// Stack order: ... cond then_val else_val -> result
|
||||
fn emit_select_i64(&mut self) { }
|
||||
/// Phase 10_d scaffolding: host-call emission (symbolic)
|
||||
fn emit_host_call(&mut self, _symbol: &str, _argc: usize, _has_ret: bool) { }
|
||||
/// Typed host-call emission: params kinds and return type hint (f64 when true)
|
||||
@ -101,6 +104,7 @@ impl IRBuilder for NoopBuilder {
|
||||
fn emit_jump(&mut self) { self.branches += 1; }
|
||||
fn emit_branch(&mut self) { self.branches += 1; }
|
||||
fn emit_return(&mut self) { self.rets += 1; }
|
||||
fn emit_select_i64(&mut self) { self.binops += 1; }
|
||||
fn emit_host_call_typed(&mut self, _symbol: &str, _params: &[ParamKind], has_ret: bool, _ret_is_f64: bool) { if has_ret { self.consts += 1; } }
|
||||
fn emit_plugin_invoke(&mut self, _type_id: u32, _method_id: u32, _argc: usize, has_ret: bool) { if has_ret { self.consts += 1; } }
|
||||
fn emit_plugin_invoke_by_name(&mut self, _method: &str, _argc: usize, has_ret: bool) { if has_ret { self.consts += 1; } }
|
||||
@ -134,6 +138,9 @@ pub struct CraneliftBuilder {
|
||||
typed_sig_prepared: bool,
|
||||
// Return-type hint: function returns boolean (footing only; ABI remains i64 for now)
|
||||
ret_hint_is_b1: bool,
|
||||
// Single-exit epilogue (jit-direct stability): ret block + i64 slot
|
||||
ret_block: Option<cranelift_codegen::ir::Block>,
|
||||
ret_slot: Option<cranelift_codegen::ir::StackSlot>,
|
||||
}
|
||||
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
@ -144,6 +151,15 @@ use cranelift_codegen::ir::InstBuilder;
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
extern "C" fn nyash_host_stub0() -> i64 { 0 }
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
extern "C" fn nyash_jit_dbg_i64(tag: i64, val: i64) -> i64 {
|
||||
eprintln!("[JIT-DBG] tag={} val={}", tag, val);
|
||||
val
|
||||
}
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
extern "C" fn nyash_jit_block_enter(idx: i64) {
|
||||
eprintln!("[JIT-BLOCK] enter={}", idx);
|
||||
}
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
extern "C" fn nyash_plugin_invoke3_i64(type_id: i64, method_id: i64, argc: i64, a0: i64, a1: i64, a2: i64) -> i64 {
|
||||
use crate::runtime::plugin_loader_v2::PluginBoxV2;
|
||||
let trace = crate::jit::observe::trace_enabled();
|
||||
@ -539,6 +555,8 @@ use super::extern_thunks::{
|
||||
nyash_string_concat_hh, nyash_string_eq_hh, nyash_string_lt_hh,
|
||||
nyash_any_length_h, nyash_any_is_empty_h, nyash_console_birth_h,
|
||||
};
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
use crate::jit::r#extern::r#async::nyash_future_await_h;
|
||||
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
use crate::{
|
||||
@ -746,6 +764,16 @@ impl IRBuilder for CraneliftBuilder {
|
||||
// Defer sealing to allow entry PHI params when needed
|
||||
self.entry_block = Some(entry);
|
||||
self.current_block_index = Some(0);
|
||||
// Prepare single-exit epilogue artifacts (ret_block with one i64 param)
|
||||
{
|
||||
use cranelift_codegen::ir::types;
|
||||
let rb = fb.create_block();
|
||||
self.ret_block = Some(rb);
|
||||
// Single i64 param to carry merged return value
|
||||
fb.append_block_param(rb, types::I64);
|
||||
// Stop using ret_slot in block-param mode
|
||||
self.ret_slot = None;
|
||||
}
|
||||
fb.finalize();
|
||||
}
|
||||
|
||||
@ -756,6 +784,38 @@ impl IRBuilder for CraneliftBuilder {
|
||||
return;
|
||||
}
|
||||
|
||||
// Build single-exit epilogue before defining function
|
||||
{
|
||||
use cranelift_frontend::FunctionBuilder;
|
||||
use cranelift_codegen::ir::types;
|
||||
if let Some(rb) = self.ret_block {
|
||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||
fb.switch_to_block(rb);
|
||||
if fb.func.signature.returns.is_empty() {
|
||||
fb.ins().return_(&[]);
|
||||
} else {
|
||||
let params = fb.func.dfg.block_params(rb).to_vec();
|
||||
let mut v = params.get(0).copied().unwrap_or_else(|| fb.ins().iconst(types::I64, 0));
|
||||
// Optional debug
|
||||
if std::env::var("NYASH_JIT_TRACE_RET").ok().as_deref() == Some("1") {
|
||||
use cranelift_codegen::ir::{AbiParam, Signature}; use cranelift_module::Linkage;
|
||||
let mut sig = Signature::new(self.module.isa().default_call_conv());
|
||||
sig.params.push(AbiParam::new(types::I64));
|
||||
sig.params.push(AbiParam::new(types::I64));
|
||||
sig.returns.push(AbiParam::new(types::I64));
|
||||
let fid = self.module.declare_function("nyash.jit.dbg_i64", Linkage::Import, &sig).expect("declare dbg_i64");
|
||||
let fref = self.module.declare_func_in_func(fid, fb.func);
|
||||
let tag = fb.ins().iconst(types::I64, 200);
|
||||
let _ = fb.ins().call(fref, &[tag, v]);
|
||||
}
|
||||
let ret_ty = fb.func.signature.returns.get(0).map(|p| p.value_type).unwrap_or(types::I64);
|
||||
if ret_ty == types::F64 { v = fb.ins().fcvt_from_sint(types::F64, v); }
|
||||
fb.ins().return_(&[v]);
|
||||
}
|
||||
fb.finalize();
|
||||
}
|
||||
}
|
||||
|
||||
// Declare a unique function symbol for JIT
|
||||
let sym_name = self.current_name.clone().unwrap_or_else(|| "jit_fn".to_string());
|
||||
let func_id = self.module.declare_function(&sym_name, Linkage::Local, &self.ctx.func.signature)
|
||||
@ -873,6 +933,9 @@ impl IRBuilder for CraneliftBuilder {
|
||||
jb.symbol(c::SYM_STRING_CONCAT_HH, nyash_string_concat_hh as *const u8);
|
||||
jb.symbol(c::SYM_STRING_EQ_HH, nyash_string_eq_hh as *const u8);
|
||||
jb.symbol(c::SYM_STRING_LT_HH, nyash_string_lt_hh as *const u8);
|
||||
use crate::jit::lower::extern_thunks::nyash_semantics_add_hh;
|
||||
// Unified semantics ops
|
||||
jb.symbol(crate::jit::r#extern::collections::SYM_SEMANTICS_ADD_HH, nyash_semantics_add_hh as *const u8);
|
||||
jb.symbol(b::SYM_BOX_BIRTH_H, nyash_box_birth_h as *const u8);
|
||||
jb.symbol("nyash.box.birth_i64", nyash_box_birth_i64 as *const u8);
|
||||
// Handle helpers
|
||||
@ -1006,60 +1069,85 @@ impl IRBuilder for CraneliftBuilder {
|
||||
self.stats.2 += 1;
|
||||
fb.finalize();
|
||||
}
|
||||
fn emit_select_i64(&mut self) {
|
||||
use cranelift_frontend::FunctionBuilder; use cranelift_codegen::ir::{types, condcodes::IntCC};
|
||||
// Expect stack: ... cond then else
|
||||
if self.value_stack.len() < 3 { return; }
|
||||
let mut else_v = self.value_stack.pop().unwrap();
|
||||
let mut then_v = self.value_stack.pop().unwrap();
|
||||
let mut cond_v = self.value_stack.pop().unwrap();
|
||||
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); }
|
||||
// Normalize types
|
||||
let cty = fb.func.dfg.value_type(cond_v);
|
||||
if cty == types::I64 {
|
||||
cond_v = fb.ins().icmp_imm(IntCC::NotEqual, cond_v, 0);
|
||||
crate::jit::rt::b1_norm_inc(1);
|
||||
}
|
||||
let tty = fb.func.dfg.value_type(then_v);
|
||||
if tty != types::I64 { then_v = fb.ins().fcvt_to_sint(types::I64, then_v); }
|
||||
let ety = fb.func.dfg.value_type(else_v);
|
||||
if ety != types::I64 { else_v = fb.ins().fcvt_to_sint(types::I64, else_v); }
|
||||
// Optional runtime debug
|
||||
if std::env::var("NYASH_JIT_TRACE_SEL").ok().as_deref() == Some("1") {
|
||||
use cranelift_codegen::ir::{AbiParam, Signature};
|
||||
use cranelift_module::Linkage;
|
||||
let mut sig = Signature::new(self.module.isa().default_call_conv());
|
||||
sig.params.push(AbiParam::new(types::I64));
|
||||
sig.params.push(AbiParam::new(types::I64));
|
||||
sig.returns.push(AbiParam::new(types::I64));
|
||||
let fid = self.module
|
||||
.declare_function("nyash.jit.dbg_i64", Linkage::Import, &sig)
|
||||
.expect("declare dbg_i64");
|
||||
let fref = self.module.declare_func_in_func(fid, fb.func);
|
||||
let t_cond = fb.ins().iconst(types::I64, 100);
|
||||
let one = fb.ins().iconst(types::I64, 1);
|
||||
let zero = fb.ins().iconst(types::I64, 0);
|
||||
let ci = fb.ins().select(cond_v, one, zero);
|
||||
let _ = fb.ins().call(fref, &[t_cond, ci]);
|
||||
let t_then = fb.ins().iconst(types::I64, 101);
|
||||
let _ = fb.ins().call(fref, &[t_then, then_v]);
|
||||
let t_else = fb.ins().iconst(types::I64, 102);
|
||||
let _ = fb.ins().call(fref, &[t_else, else_v]);
|
||||
}
|
||||
let sel = fb.ins().select(cond_v, then_v, else_v);
|
||||
self.value_stack.push(sel);
|
||||
fb.finalize();
|
||||
}
|
||||
fn emit_jump(&mut self) { self.stats.3 += 1; }
|
||||
fn emit_branch(&mut self) { self.stats.3 += 1; }
|
||||
|
||||
fn emit_return(&mut self) {
|
||||
use cranelift_frontend::FunctionBuilder;
|
||||
use cranelift_codegen::ir::{types, condcodes::IntCC};
|
||||
self.stats.4 += 1;
|
||||
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); }
|
||||
// If function has no return values, emit a plain return
|
||||
if fb.func.signature.returns.is_empty() {
|
||||
fb.ins().return_(&[]);
|
||||
fb.finalize();
|
||||
return;
|
||||
}
|
||||
if let Some(mut v) = self.value_stack.pop() {
|
||||
// Normalize return type if needed
|
||||
let ret_ty = fb.func.signature.returns.get(0).map(|p| p.value_type).unwrap_or(cranelift_codegen::ir::types::I64);
|
||||
let v_ty = fb.func.dfg.value_type(v);
|
||||
if v_ty != ret_ty {
|
||||
use cranelift_codegen::ir::types;
|
||||
if ret_ty == types::F64 && v_ty == types::I64 {
|
||||
v = fb.ins().fcvt_from_sint(types::F64, v);
|
||||
} else if ret_ty == types::I64 && v_ty == types::F64 {
|
||||
v = fb.ins().fcvt_to_sint(types::I64, v);
|
||||
} else if ret_ty == types::I64 {
|
||||
// If returning i64 but we currently have a boolean, normalize via select(b1,1,0)
|
||||
use cranelift_codegen::ir::types;
|
||||
let one = fb.ins().iconst(types::I64, 1);
|
||||
let zero = fb.ins().iconst(types::I64, 0);
|
||||
v = fb.ins().select(v, one, zero);
|
||||
}
|
||||
#[cfg(feature = "jit-b1-abi")]
|
||||
{
|
||||
use cranelift_codegen::ir::types;
|
||||
if ret_ty == types::B1 && v_ty == types::I64 {
|
||||
use cranelift_codegen::ir::condcodes::IntCC;
|
||||
v = fb.ins().icmp_imm(IntCC::NotEqual, v, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
fb.ins().return_(&[v]);
|
||||
} else {
|
||||
// Return 0 if empty stack (defensive)
|
||||
use cranelift_codegen::ir::types;
|
||||
let ret_ty = fb.func.signature.returns.get(0).map(|p| p.value_type).unwrap_or(types::I64);
|
||||
if ret_ty == types::F64 {
|
||||
let z = fb.ins().f64const(0.0);
|
||||
fb.ins().return_(&[z]);
|
||||
} else {
|
||||
let zero = fb.ins().iconst(types::I64, 0);
|
||||
fb.ins().return_(&[zero]);
|
||||
}
|
||||
let mut v = if let Some(x) = self.value_stack.pop() { x } else { fb.ins().iconst(types::I64, 0) };
|
||||
let v_ty = fb.func.dfg.value_type(v);
|
||||
if v_ty != types::I64 {
|
||||
if v_ty == types::F64 { v = fb.ins().fcvt_to_sint(types::I64, v); }
|
||||
else { let one = fb.ins().iconst(types::I64, 1); let zero = fb.ins().iconst(types::I64, 0); v = fb.ins().select(v, one, zero); }
|
||||
}
|
||||
if std::env::var("NYASH_JIT_TRACE_RET").ok().as_deref() == Some("1") {
|
||||
use cranelift_codegen::ir::{AbiParam, Signature}; use cranelift_module::Linkage;
|
||||
let mut sig = Signature::new(self.module.isa().default_call_conv());
|
||||
sig.params.push(AbiParam::new(types::I64));
|
||||
sig.params.push(AbiParam::new(types::I64));
|
||||
sig.returns.push(AbiParam::new(types::I64));
|
||||
let fid = self.module.declare_function("nyash.jit.dbg_i64", Linkage::Import, &sig).expect("declare dbg_i64");
|
||||
let fref = self.module.declare_func_in_func(fid, fb.func);
|
||||
let tag = fb.ins().iconst(types::I64, 201);
|
||||
let _ = fb.ins().call(fref, &[tag, v]);
|
||||
}
|
||||
if let Some(rb) = self.ret_block { fb.ins().jump(rb, &[v]); }
|
||||
fb.finalize();
|
||||
}
|
||||
|
||||
@ -1303,6 +1391,7 @@ impl IRBuilder for CraneliftBuilder {
|
||||
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 had_cond = !self.value_stack.is_empty();
|
||||
let cond_b1 = if let Some(v) = self.value_stack.pop() {
|
||||
let ty = fb.func.dfg.value_type(v);
|
||||
if ty == types::I64 {
|
||||
@ -1319,7 +1408,16 @@ impl IRBuilder for CraneliftBuilder {
|
||||
crate::jit::rt::b1_norm_inc(1);
|
||||
out
|
||||
};
|
||||
fb.ins().brif(cond_b1, self.blocks[then_index], &[], self.blocks[else_index], &[]);
|
||||
if std::env::var("NYASH_JIT_TRACE_BR").ok().as_deref() == Some("1") {
|
||||
eprintln!("[JIT-CLIF] br_if cond_present={} then={} else={}", had_cond, then_index, else_index);
|
||||
}
|
||||
// NOTE: If branch direction appears inverted, swap targets here to validate mapping.
|
||||
let swap = std::env::var("NYASH_JIT_SWAP_THEN_ELSE").ok().as_deref() == Some("1");
|
||||
if swap {
|
||||
fb.ins().brif(cond_b1, self.blocks[else_index], &[], self.blocks[then_index], &[]);
|
||||
} else {
|
||||
fb.ins().brif(cond_b1, self.blocks[then_index], &[], self.blocks[else_index], &[]);
|
||||
}
|
||||
self.stats.3 += 1;
|
||||
fb.finalize();
|
||||
}
|
||||
@ -1348,6 +1446,9 @@ impl IRBuilder for CraneliftBuilder {
|
||||
let _v = fb.append_block_param(b, types::I64);
|
||||
}
|
||||
self.block_param_counts.insert(index, needed);
|
||||
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
|
||||
eprintln!("[JIT-CLIF] ensure_block_params bb={} now={}", index, needed);
|
||||
}
|
||||
}
|
||||
fb.finalize();
|
||||
}
|
||||
@ -1363,6 +1464,9 @@ impl IRBuilder for CraneliftBuilder {
|
||||
// Ensure we have an active insertion point before emitting any instructions
|
||||
fb.switch_to_block(b);
|
||||
let params = fb.func.dfg.block_params(b).to_vec();
|
||||
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
|
||||
eprintln!("[JIT-CLIF] push_block_param_i64_at pos={} available={}", pos, params.len());
|
||||
}
|
||||
if let Some(v) = params.get(pos).copied() { self.value_stack.push(v); }
|
||||
else {
|
||||
// defensive fallback
|
||||
@ -1377,6 +1481,9 @@ impl IRBuilder for CraneliftBuilder {
|
||||
let mut fb = FunctionBuilder::new(&mut self.ctx.func, &mut self.fbc);
|
||||
let b = if let Some(idx) = self.current_block_index { self.blocks[idx] } else if let Some(b) = self.entry_block { b } else { fb.create_block() };
|
||||
let params = fb.func.dfg.block_params(b).to_vec();
|
||||
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
|
||||
eprintln!("[JIT-CLIF] push_block_param_b1_at pos={} available={}", pos, params.len());
|
||||
}
|
||||
if let Some(v) = params.get(pos).copied() {
|
||||
let ty = fb.func.dfg.value_type(v);
|
||||
let b1 = if ty == types::I64 { fb.ins().icmp_imm(IntCC::NotEqual, v, 0) } else { v };
|
||||
@ -1395,7 +1502,14 @@ impl IRBuilder for CraneliftBuilder {
|
||||
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); }
|
||||
// Condition
|
||||
// Pop else args then then args (so stack order can be value-friendly)
|
||||
let mut else_args: Vec<cranelift_codegen::ir::Value> = Vec::new();
|
||||
for _ in 0..else_n { if let Some(v) = self.value_stack.pop() { else_args.push(v); } }
|
||||
else_args.reverse();
|
||||
let mut then_args: Vec<cranelift_codegen::ir::Value> = Vec::new();
|
||||
for _ in 0..then_n { if let Some(v) = self.value_stack.pop() { then_args.push(v); } }
|
||||
then_args.reverse();
|
||||
// Now pop condition last (it was pushed first by LowerCore)
|
||||
let cond_b1 = if let Some(v) = self.value_stack.pop() {
|
||||
let ty = fb.func.dfg.value_type(v);
|
||||
if ty == types::I64 { let out = fb.ins().icmp_imm(IntCC::NotEqual, v, 0); crate::jit::rt::b1_norm_inc(1); out } else { v }
|
||||
@ -1405,13 +1519,9 @@ impl IRBuilder for CraneliftBuilder {
|
||||
crate::jit::rt::b1_norm_inc(1);
|
||||
out
|
||||
};
|
||||
// Pop else args then then args (so stack order can be value-friendly)
|
||||
let mut else_args: Vec<cranelift_codegen::ir::Value> = Vec::new();
|
||||
for _ in 0..else_n { if let Some(v) = self.value_stack.pop() { else_args.push(v); } }
|
||||
else_args.reverse();
|
||||
let mut then_args: Vec<cranelift_codegen::ir::Value> = Vec::new();
|
||||
for _ in 0..then_n { if let Some(v) = self.value_stack.pop() { then_args.push(v); } }
|
||||
then_args.reverse();
|
||||
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
|
||||
eprintln!("[JIT-CLIF] br_if_with_args then_n={} else_n={}", then_n, else_n);
|
||||
}
|
||||
fb.ins().brif(cond_b1, self.blocks[then_index], &then_args, self.blocks[else_index], &else_args);
|
||||
self.stats.3 += 1;
|
||||
fb.finalize();
|
||||
@ -1425,6 +1535,9 @@ impl IRBuilder for CraneliftBuilder {
|
||||
let mut args: Vec<cranelift_codegen::ir::Value> = Vec::new();
|
||||
for _ in 0..n { if let Some(v) = self.value_stack.pop() { args.push(v); } }
|
||||
args.reverse();
|
||||
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
|
||||
eprintln!("[JIT-CLIF] jump_with_args target={} n={}", target_index, n);
|
||||
}
|
||||
fb.ins().jump(self.blocks[target_index], &args);
|
||||
self.stats.3 += 1;
|
||||
fb.finalize();
|
||||
@ -1683,26 +1796,25 @@ impl IRBuilder for ObjectBuilder {
|
||||
fn emit_jump(&mut self) { self.stats.3 += 1; }
|
||||
fn emit_branch(&mut self) { self.stats.3 += 1; }
|
||||
fn emit_return(&mut self) {
|
||||
use cranelift_frontend::FunctionBuilder; use cranelift_codegen::ir::types;
|
||||
use cranelift_frontend::FunctionBuilder; use cranelift_codegen::ir::{types, condcodes::IntCC};
|
||||
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); }
|
||||
// If function has no return, just return
|
||||
if fb.func.signature.returns.is_empty() {
|
||||
fb.ins().return_(&[]);
|
||||
fb.finalize();
|
||||
return;
|
||||
}
|
||||
if let Some(mut v) = self.value_stack.pop() {
|
||||
let ret_ty = fb.func.signature.returns.get(0).map(|p| p.value_type).unwrap_or(types::I64);
|
||||
let v_ty = fb.func.dfg.value_type(v);
|
||||
if v_ty != ret_ty {
|
||||
if ret_ty == types::F64 && v_ty == types::I64 { v = fb.ins().fcvt_from_sint(types::F64, v); }
|
||||
else if ret_ty == types::I64 && v_ty == types::F64 { v = fb.ins().fcvt_to_sint(types::I64, v); }
|
||||
else if ret_ty == types::I64 { let one = fb.ins().iconst(types::I64, 1); let zero = fb.ins().iconst(types::I64, 0); use cranelift_codegen::ir::condcodes::IntCC; let b1 = fb.ins().icmp_imm(IntCC::NotEqual, v, 0); v = fb.ins().select(b1, one, zero); }
|
||||
}
|
||||
fb.ins().return_(&[v]);
|
||||
} else {
|
||||
let z = fb.ins().iconst(types::I64, 0); fb.ins().return_(&[z]);
|
||||
// Normalize to function return type and return directly (ObjectBuilder has no ret_block)
|
||||
let mut v = if let Some(x) = self.value_stack.pop() { x } else { fb.ins().iconst(types::I64, 0) };
|
||||
let ret_ty = fb.func.signature.returns.get(0).map(|p| p.value_type).unwrap_or(types::I64);
|
||||
let v_ty = fb.func.dfg.value_type(v);
|
||||
if ret_ty != v_ty {
|
||||
if ret_ty == types::F64 && v_ty == types::I64 { v = fb.ins().fcvt_from_sint(types::F64, v); }
|
||||
else if ret_ty == types::I64 && v_ty == types::F64 { v = fb.ins().fcvt_to_sint(types::I64, v); }
|
||||
else if ret_ty == types::I64 { let one = fb.ins().iconst(types::I64, 1); let zero = fb.ins().iconst(types::I64, 0); let b1 = fb.ins().icmp_imm(IntCC::NotEqual, v, 0); v = fb.ins().select(b1, one, zero); }
|
||||
}
|
||||
fb.ins().return_(&[v]);
|
||||
fb.finalize();
|
||||
}
|
||||
fn emit_host_call(&mut self, symbol: &str, argc: usize, has_ret: bool) {
|
||||
@ -1751,7 +1863,7 @@ impl IRBuilder for ObjectBuilder {
|
||||
fb.finalize();
|
||||
}
|
||||
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); if self.blocks.len() < count { for _ in 0..(count - self.blocks.len()) { 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 switch_to_block(&mut self, index: usize) { use cranelift_frontend::FunctionBuilder; use cranelift_codegen::ir::{types, AbiParam, Signature}; use cranelift_module::Linkage; 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]); if std::env::var("NYASH_JIT_TRACE_BLOCKS").ok().as_deref() == Some("1") { let mut sig = Signature::new(self.module.isa().default_call_conv()); sig.params.push(AbiParam::new(types::I64)); let fid = self.module.declare_function("nyash.jit.block_enter", Linkage::Import, &sig).expect("declare block_enter"); let fref = self.module.declare_func_in_func(fid, fb.func); let bi = fb.ins().iconst(types::I64, index as i64); let _ = fb.ins().call(fref, &[bi]); } 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};
|
||||
@ -1780,6 +1892,9 @@ impl IRBuilder for ObjectBuilder {
|
||||
let b = self.blocks[index];
|
||||
for _ in have..count { let _ = fb.append_block_param(b, cranelift_codegen::ir::types::I64); }
|
||||
self.block_param_counts.insert(index, count);
|
||||
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
|
||||
eprintln!("[JIT-CLIF] ensure_block_params bb={} now={}", index, count);
|
||||
}
|
||||
}
|
||||
fb.finalize();
|
||||
}
|
||||
@ -1790,6 +1905,9 @@ impl IRBuilder for ObjectBuilder {
|
||||
let b = if let Some(idx) = self.current_block_index { self.blocks[idx] } else if let Some(b) = self.entry_block { b } else { fb.create_block() };
|
||||
fb.switch_to_block(b);
|
||||
let params = fb.func.dfg.block_params(b).to_vec();
|
||||
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
|
||||
eprintln!("[JIT-CLIF] push_block_param_i64_at pos={} available={}", pos, params.len());
|
||||
}
|
||||
if let Some(v) = params.get(pos).copied() { self.value_stack.push(v); }
|
||||
else { let z = fb.ins().iconst(types::I64, 0); self.value_stack.push(z); }
|
||||
fb.finalize();
|
||||
@ -1820,6 +1938,13 @@ impl CraneliftBuilder {
|
||||
.expect("failed to create JITBuilder");
|
||||
// Register host-call symbols (PoC: map to simple C-ABI stubs)
|
||||
builder.symbol("nyash.host.stub0", nyash_host_stub0 as *const u8);
|
||||
builder.symbol("nyash.jit.dbg_i64", nyash_jit_dbg_i64 as *const u8);
|
||||
// Async/Future
|
||||
builder.symbol(crate::jit::r#extern::r#async::SYM_FUTURE_AWAIT_H, nyash_future_await_h as *const u8);
|
||||
builder.symbol("nyash.jit.block_enter", nyash_jit_block_enter as *const u8);
|
||||
// Async/Future
|
||||
builder.symbol(crate::jit::r#extern::r#async::SYM_FUTURE_AWAIT_H, nyash_future_await_h as *const u8);
|
||||
builder.symbol("nyash.jit.dbg_i64", nyash_jit_dbg_i64 as *const u8);
|
||||
{
|
||||
use crate::jit::r#extern::collections as c;
|
||||
use crate::jit::r#extern::{handles as h, birth as b, runtime as r};
|
||||
@ -1869,6 +1994,9 @@ impl CraneliftBuilder {
|
||||
// Plugin invoke shims (i64/f64)
|
||||
builder.symbol("nyash_plugin_invoke3_i64", nyash_plugin_invoke3_i64 as *const u8);
|
||||
builder.symbol("nyash_plugin_invoke3_f64", nyash_plugin_invoke3_f64 as *const u8);
|
||||
// JIT debug helpers (conditionally called when env toggles are set)
|
||||
builder.symbol("nyash.jit.dbg_i64", nyash_jit_dbg_i64 as *const u8);
|
||||
builder.symbol("nyash.jit.block_enter", nyash_jit_block_enter as *const u8);
|
||||
// By-name plugin invoke shims (method-name specific)
|
||||
builder.symbol("nyash_plugin_invoke_name_getattr_i64", nyash_plugin_invoke_name_getattr_i64 as *const u8);
|
||||
builder.symbol("nyash_plugin_invoke_name_call_i64", nyash_plugin_invoke_name_call_i64 as *const u8);
|
||||
@ -1895,6 +2023,8 @@ impl CraneliftBuilder {
|
||||
desired_ret_is_f64: false,
|
||||
typed_sig_prepared: false,
|
||||
ret_hint_is_b1: false,
|
||||
ret_block: None,
|
||||
ret_slot: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user