archive: Move JIT/Cranelift to archive during Phase 15 focus
Phase 15 requires concentrated development on PyVM and LLVM backends only. JIT/Cranelift was causing build confusion and distracting AI developers. ## Archived Components - src/jit/ → archive/jit-cranelift/src/jit/ - src/backend/cranelift/ → archive/jit-cranelift/src/backend/cranelift/ - JIT Box modules → archive/jit-cranelift/src/boxes/ - JIT scripts → archive/jit-cranelift/scripts/, tools/ - clif_adapter.rs → archive/jit-cranelift/src/semantics/ ## Build Changes - Cargo.toml: Comment out cranelift-jit feature and dependencies - src/lib.rs: Disable JIT module declaration - src/boxes/mod.rs: Disable JIT Box module declarations - src/semantics/mod.rs: Disable clif_adapter module - debug_box.rs: Replace JIT calls with archive stubs ## Documentation - archive/jit-cranelift/ARCHIVE_NOTES.md: Complete restoration guide - Reason: Phase 15 selfhosting focus (80k→20k line reduction) - Restoration: Full procedure documented for future revival This eliminates build errors and AI developer confusion, enabling focused Phase 15 development on PyVM/LLVM backends only. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
201
archive/jit-cranelift/src/backend/cranelift/builder.rs
Normal file
201
archive/jit-cranelift/src/backend/cranelift/builder.rs
Normal file
@ -0,0 +1,201 @@
|
||||
/*!
|
||||
* ClifBuilder - IRBuilder implementation for Cranelift (skeleton)
|
||||
*
|
||||
* This satisfies the IRBuilder trait so LowerCore can target it.
|
||||
* Actual CLIF emission will be added incrementally.
|
||||
*/
|
||||
|
||||
#![cfg(feature = "cranelift-jit")]
|
||||
|
||||
use crate::jit::lower::builder::{BinOpKind, CmpKind, IRBuilder, ParamKind};
|
||||
use cranelift_codegen::ir::InstBuilder;
|
||||
|
||||
// Minimal recorded opcodes for Const/Add/Return first
|
||||
enum RecOp {
|
||||
ConstI64(i64),
|
||||
ConstF64(f64),
|
||||
BinOp(BinOpKind),
|
||||
Return,
|
||||
}
|
||||
|
||||
pub struct ClifBuilder {
|
||||
pub consts: usize,
|
||||
pub binops: usize,
|
||||
pub cmps: usize,
|
||||
pub branches: usize,
|
||||
pub rets: usize,
|
||||
ops: Vec<RecOp>,
|
||||
}
|
||||
|
||||
impl ClifBuilder {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
consts: 0,
|
||||
binops: 0,
|
||||
cmps: 0,
|
||||
branches: 0,
|
||||
rets: 0,
|
||||
ops: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Build and execute the recorded ops as a native function using Cranelift
|
||||
pub fn finish_and_execute(&self) -> Result<i64, String> {
|
||||
use cranelift_codegen::ir::{types, AbiParam, Signature};
|
||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||
use cranelift_module::{Linkage, Module};
|
||||
// JIT setup
|
||||
let isa_builder = cranelift_native::builder().map_err(|e| e.to_string())?;
|
||||
let flag_builder = cranelift_codegen::settings::builder();
|
||||
let flags = cranelift_codegen::settings::Flags::new(flag_builder);
|
||||
let isa = isa_builder.finish(flags).map_err(|e| e.to_string())?;
|
||||
let jit_builder =
|
||||
cranelift_jit::JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
let mut module = cranelift_jit::JITModule::new(jit_builder);
|
||||
// Signature ()->i64
|
||||
let mut sig = Signature::new(module.target_config().default_call_conv);
|
||||
sig.returns.push(AbiParam::new(types::I64));
|
||||
let func_id = module
|
||||
.declare_function("ny_lowercore_main", Linkage::Export, &sig)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let mut ctx = module.make_context();
|
||||
ctx.func.signature = sig;
|
||||
let mut fbc = FunctionBuilderContext::new();
|
||||
let mut fb = FunctionBuilder::new(&mut ctx.func, &mut fbc);
|
||||
let entry = fb.create_block();
|
||||
fb.switch_to_block(entry);
|
||||
|
||||
// Interpret ops with a small value stack of CLIF Values
|
||||
let mut vs: Vec<cranelift_codegen::ir::Value> = Vec::new();
|
||||
let mut did_return = false;
|
||||
for op in &self.ops {
|
||||
match *op {
|
||||
RecOp::ConstI64(i) => {
|
||||
vs.push(fb.ins().iconst(types::I64, i));
|
||||
}
|
||||
RecOp::ConstF64(f) => {
|
||||
let fv = fb.ins().f64const(f);
|
||||
let iv = fb.ins().fcvt_to_sint(types::I64, fv);
|
||||
vs.push(iv);
|
||||
}
|
||||
RecOp::BinOp(BinOpKind::Add) => {
|
||||
if vs.len() < 2 {
|
||||
vs.clear();
|
||||
vs.push(fb.ins().iconst(types::I64, 0));
|
||||
} else {
|
||||
let r = vs.pop().unwrap();
|
||||
let l = vs.pop().unwrap();
|
||||
vs.push(fb.ins().iadd(l, r));
|
||||
}
|
||||
}
|
||||
RecOp::BinOp(_) => { /* ignore others for now */ }
|
||||
RecOp::Return => {
|
||||
let retv = if let Some(v) = vs.last().copied() {
|
||||
v
|
||||
} else {
|
||||
fb.ins().iconst(types::I64, 0)
|
||||
};
|
||||
fb.ins().return_(&[retv]);
|
||||
did_return = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Ensure function ends with return
|
||||
if !did_return {
|
||||
let retv = if let Some(v) = vs.last().copied() {
|
||||
v
|
||||
} else {
|
||||
fb.ins().iconst(types::I64, 0)
|
||||
};
|
||||
fb.ins().return_(&[retv]);
|
||||
}
|
||||
fb.seal_block(entry);
|
||||
fb.finalize();
|
||||
module
|
||||
.define_function(func_id, &mut ctx)
|
||||
.map_err(|e| e.to_string())?;
|
||||
module.clear_context(&mut ctx);
|
||||
let _ = module.finalize_definitions();
|
||||
let code = module.get_finalized_function(func_id);
|
||||
let func = unsafe { std::mem::transmute::<_, extern "C" fn() -> i64>(code) };
|
||||
Ok(func())
|
||||
}
|
||||
}
|
||||
|
||||
impl IRBuilder for ClifBuilder {
|
||||
fn begin_function(&mut self, _name: &str) {}
|
||||
fn end_function(&mut self) {}
|
||||
fn prepare_signature_i64(&mut self, _argc: usize, _has_ret: bool) {}
|
||||
fn prepare_signature_typed(&mut self, _params: &[ParamKind], _ret_is_f64: bool) {}
|
||||
fn emit_param_i64(&mut self, _index: usize) {}
|
||||
fn emit_const_i64(&mut self, val: i64) {
|
||||
self.consts += 1;
|
||||
self.ops.push(RecOp::ConstI64(val));
|
||||
}
|
||||
fn emit_const_f64(&mut self, val: f64) {
|
||||
self.consts += 1;
|
||||
self.ops.push(RecOp::ConstF64(val));
|
||||
}
|
||||
fn emit_binop(&mut self, op: BinOpKind) {
|
||||
self.binops += 1;
|
||||
self.ops.push(RecOp::BinOp(op));
|
||||
}
|
||||
fn emit_compare(&mut self, _op: CmpKind) {
|
||||
self.cmps += 1;
|
||||
}
|
||||
fn emit_jump(&mut self) {}
|
||||
fn emit_branch(&mut self) {
|
||||
self.branches += 1;
|
||||
}
|
||||
fn emit_return(&mut self) {
|
||||
self.rets += 1;
|
||||
self.ops.push(RecOp::Return);
|
||||
}
|
||||
fn emit_host_call(&mut self, _symbol: &str, _argc: usize, _has_ret: bool) {}
|
||||
fn emit_host_call_typed(
|
||||
&mut self,
|
||||
_symbol: &str,
|
||||
_params: &[ParamKind],
|
||||
_has_ret: bool,
|
||||
_ret_is_f64: bool,
|
||||
) {
|
||||
}
|
||||
fn emit_plugin_invoke(&mut self, _type_id: u32, _method_id: u32, _argc: usize, _has_ret: bool) {
|
||||
}
|
||||
fn emit_plugin_invoke_by_name(&mut self, _method: &str, _argc: usize, _has_ret: bool) {}
|
||||
fn prepare_blocks(&mut self, _count: usize) {}
|
||||
fn switch_to_block(&mut self, _index: usize) {}
|
||||
fn seal_block(&mut self, _index: usize) {}
|
||||
fn br_if_top_is_true(&mut self, _then_index: usize, _else_index: usize) {}
|
||||
fn jump_to(&mut self, _target_index: usize) {}
|
||||
fn ensure_block_params_i64(&mut self, _index: usize, _count: usize) {}
|
||||
fn ensure_block_params_b1(&mut self, index: usize, count: usize) {
|
||||
self.ensure_block_params_i64(index, count);
|
||||
}
|
||||
fn ensure_block_param_i64(&mut self, index: usize) {
|
||||
self.ensure_block_params_i64(index, 1);
|
||||
}
|
||||
fn push_block_param_i64_at(&mut self, _pos: usize) {}
|
||||
fn push_block_param_b1_at(&mut self, pos: usize) {
|
||||
self.push_block_param_i64_at(pos);
|
||||
}
|
||||
fn push_block_param_i64(&mut self) {
|
||||
self.push_block_param_i64_at(0);
|
||||
}
|
||||
fn br_if_with_args(
|
||||
&mut self,
|
||||
_then_index: usize,
|
||||
_else_index: usize,
|
||||
_then_n: usize,
|
||||
_else_n: usize,
|
||||
) {
|
||||
self.emit_branch();
|
||||
}
|
||||
fn jump_with_args(&mut self, _target_index: usize, _n: usize) {
|
||||
self.emit_jump();
|
||||
}
|
||||
fn hint_ret_bool(&mut self, _is_b1: bool) {}
|
||||
fn ensure_local_i64(&mut self, _index: usize) {}
|
||||
fn store_local_i64(&mut self, _index: usize) {}
|
||||
fn load_local_i64(&mut self, _index: usize) {}
|
||||
}
|
||||
114
archive/jit-cranelift/src/backend/cranelift/context.rs
Normal file
114
archive/jit-cranelift/src/backend/cranelift/context.rs
Normal file
@ -0,0 +1,114 @@
|
||||
#![cfg(feature = "cranelift-jit")]
|
||||
|
||||
use std::collections::HashMap;
|
||||
|
||||
use cranelift_codegen::ir::{types, AbiParam, Block, Signature};
|
||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||
use cranelift_jit::{JITBuilder, JITModule};
|
||||
use cranelift_module::{FuncId, Linkage, Module};
|
||||
|
||||
use crate::mir::{BasicBlockId, MirFunction, ValueId};
|
||||
|
||||
/// Simple block map (MIR BB -> CLIF Block)
|
||||
pub struct BlockMap(pub HashMap<BasicBlockId, Block>);
|
||||
|
||||
impl BlockMap {
|
||||
pub fn new() -> Self {
|
||||
Self(HashMap::new())
|
||||
}
|
||||
pub fn get(&self, bb: &BasicBlockId) -> Option<&Block> {
|
||||
self.0.get(bb)
|
||||
}
|
||||
pub fn insert(&mut self, bb: BasicBlockId, blk: Block) {
|
||||
self.0.insert(bb, blk);
|
||||
}
|
||||
/// Create a CLIF block for each MIR block id
|
||||
pub fn create_for_function(func: &MirFunction, builder: &mut FunctionBuilder) -> Self {
|
||||
let mut m = HashMap::new();
|
||||
for (bb_id, _) in &func.blocks {
|
||||
m.insert(*bb_id, builder.create_block());
|
||||
}
|
||||
Self(m)
|
||||
}
|
||||
}
|
||||
|
||||
/// Value environment for CLIF lowering: holds current SSA values and pseudo-memory for Load/Store
|
||||
pub struct ValueEnv {
|
||||
vals: HashMap<ValueId, cranelift_codegen::ir::Value>,
|
||||
mem: HashMap<ValueId, cranelift_codegen::ir::Value>,
|
||||
}
|
||||
|
||||
impl ValueEnv {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
vals: HashMap::new(),
|
||||
mem: HashMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn get_val(&self, id: &ValueId) -> Result<cranelift_codegen::ir::Value, String> {
|
||||
self.vals
|
||||
.get(id)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("undef {:?}", id))
|
||||
}
|
||||
pub fn set_val(&mut self, id: ValueId, v: cranelift_codegen::ir::Value) {
|
||||
self.vals.insert(id, v);
|
||||
}
|
||||
pub fn get_mem_or(
|
||||
&self,
|
||||
id: &ValueId,
|
||||
default: cranelift_codegen::ir::Value,
|
||||
) -> cranelift_codegen::ir::Value {
|
||||
*self.mem.get(id).unwrap_or(&default)
|
||||
}
|
||||
pub fn set_mem(&mut self, id: ValueId, v: cranelift_codegen::ir::Value) {
|
||||
self.mem.insert(id, v);
|
||||
}
|
||||
}
|
||||
|
||||
/// Cranelift JIT module wrapper (context)
|
||||
pub struct ClifContext {
|
||||
pub module: JITModule,
|
||||
}
|
||||
|
||||
impl ClifContext {
|
||||
pub fn new() -> Result<Self, String> {
|
||||
let isa_builder = cranelift_native::builder().map_err(|e| e.to_string())?;
|
||||
let flag_builder = cranelift_codegen::settings::builder();
|
||||
let flags = cranelift_codegen::settings::Flags::new(flag_builder);
|
||||
let isa = isa_builder.finish(flags).map_err(|e| e.to_string())?;
|
||||
let jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
Ok(Self {
|
||||
module: JITModule::new(jit_builder),
|
||||
})
|
||||
}
|
||||
|
||||
/// Declare an exported i64-return function and return its id and Cranelift context/signature
|
||||
pub fn declare_i64_fn(
|
||||
&mut self,
|
||||
name: &str,
|
||||
) -> Result<(FuncId, cranelift_codegen::Context, Signature), String> {
|
||||
let mut sig = Signature::new(self.module.target_config().default_call_conv);
|
||||
sig.returns.push(AbiParam::new(types::I64));
|
||||
let func_id = self
|
||||
.module
|
||||
.declare_function(name, Linkage::Export, &sig)
|
||||
.map_err(|e| e.to_string())?;
|
||||
let mut ctx = self.module.make_context();
|
||||
ctx.func.signature = sig.clone();
|
||||
Ok((func_id, ctx, sig))
|
||||
}
|
||||
|
||||
pub fn finalize(
|
||||
&mut self,
|
||||
func_id: FuncId,
|
||||
ctx: &mut cranelift_codegen::Context,
|
||||
) -> Result<*const u8, String> {
|
||||
self.module
|
||||
.define_function(func_id, ctx)
|
||||
.map_err(|e| e.to_string())?;
|
||||
self.module.clear_context(ctx);
|
||||
let _ = self.module.finalize_definitions();
|
||||
Ok(self.module.get_finalized_function(func_id))
|
||||
}
|
||||
}
|
||||
185
archive/jit-cranelift/src/backend/cranelift/jit.rs
Normal file
185
archive/jit-cranelift/src/backend/cranelift/jit.rs
Normal file
@ -0,0 +1,185 @@
|
||||
#![cfg(feature = "cranelift-jit")]
|
||||
|
||||
use cranelift_codegen::ir::{
|
||||
condcodes::IntCC, types, AbiParam, InstBuilder, Signature, StackSlot, StackSlotData,
|
||||
StackSlotKind,
|
||||
};
|
||||
use cranelift_codegen::isa;
|
||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||
use cranelift_jit::{JITBuilder, JITModule};
|
||||
use cranelift_module::{Linkage, Module};
|
||||
|
||||
use crate::mir::{BasicBlockId, CompareOp, ConstValue, MirFunction, MirInstruction, ValueId};
|
||||
|
||||
/// Compile a minimal subset of MIR(main) to a native function and execute it.
|
||||
/// Supported: Const(Integer), BinOp(Add for integers), Return(Integer or default 0).
|
||||
pub fn compile_and_execute_minimal(main: &MirFunction) -> Result<i64, String> {
|
||||
// ISA (native)
|
||||
let isa_builder = cranelift_native::builder().map_err(|e| e.to_string())?;
|
||||
let flag_builder = cranelift_codegen::settings::builder();
|
||||
let flags = cranelift_codegen::settings::Flags::new(flag_builder);
|
||||
let isa = isa_builder.finish(flags).map_err(|e| e.to_string())?;
|
||||
|
||||
let jit_builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
|
||||
let mut module = JITModule::new(jit_builder);
|
||||
|
||||
// Signature: () -> i64
|
||||
let mut sig = Signature::new(module.target_config().default_call_conv);
|
||||
sig.returns
|
||||
.push(AbiParam::new(cranelift_codegen::ir::types::I64));
|
||||
let func_id = module
|
||||
.declare_function("ny_main", Linkage::Export, &sig)
|
||||
.map_err(|e| e.to_string())?;
|
||||
|
||||
let mut ctx = module.make_context();
|
||||
ctx.func.signature = sig;
|
||||
let mut fb_ctx = FunctionBuilderContext::new();
|
||||
let mut builder = FunctionBuilder::new(&mut ctx.func, &mut fb_ctx);
|
||||
|
||||
// Prepare blocks for the entire MIR function
|
||||
use std::collections::HashMap;
|
||||
let mut clif_blocks: HashMap<BasicBlockId, cranelift_codegen::ir::Block> = HashMap::new();
|
||||
let mut vals: HashMap<ValueId, cranelift_codegen::ir::Value> = HashMap::new();
|
||||
let mut slots: HashMap<ValueId, StackSlot> = HashMap::new();
|
||||
|
||||
for (bb_id, _) in &main.blocks {
|
||||
clif_blocks.insert(*bb_id, builder.create_block());
|
||||
}
|
||||
// Switch to entry
|
||||
let entry = *clif_blocks.get(&main.entry_block).unwrap();
|
||||
builder.switch_to_block(entry);
|
||||
builder.append_block_params_for_function_params(entry);
|
||||
|
||||
// Emit each block
|
||||
// Deterministic order by id
|
||||
let mut bb_ids: Vec<_> = main.blocks.keys().copied().collect();
|
||||
bb_ids.sort_by_key(|b| b.0);
|
||||
for bb_id in bb_ids {
|
||||
let bb = main.blocks.get(&bb_id).unwrap();
|
||||
let cb = *clif_blocks.get(&bb_id).unwrap();
|
||||
builder.switch_to_block(cb);
|
||||
for inst in &bb.instructions {
|
||||
match inst {
|
||||
MirInstruction::Const { dst, value } => {
|
||||
let v = match value {
|
||||
ConstValue::Integer(i) => builder.ins().iconst(types::I64, *i),
|
||||
ConstValue::Bool(b) => {
|
||||
builder.ins().iconst(types::I64, if *b { 1 } else { 0 })
|
||||
}
|
||||
ConstValue::Float(f) => {
|
||||
let fv = builder.ins().f64const(*f);
|
||||
builder.ins().fcvt_to_sint(types::I64, fv)
|
||||
}
|
||||
ConstValue::String(_) | ConstValue::Null | ConstValue::Void => {
|
||||
builder.ins().iconst(types::I64, 0)
|
||||
}
|
||||
};
|
||||
vals.insert(*dst, v);
|
||||
}
|
||||
MirInstruction::BinOp { dst, op, lhs, rhs } => {
|
||||
use crate::mir::BinaryOp;
|
||||
let l = *vals.get(lhs).ok_or_else(|| format!("undef {:?}", lhs))?;
|
||||
let r = *vals.get(rhs).ok_or_else(|| format!("undef {:?}", rhs))?;
|
||||
let out = match op {
|
||||
BinaryOp::Add => builder.ins().iadd(l, r),
|
||||
BinaryOp::Sub => builder.ins().isub(l, r),
|
||||
BinaryOp::Mul => builder.ins().imul(l, r),
|
||||
BinaryOp::Div => builder.ins().sdiv(l, r),
|
||||
BinaryOp::Mod => builder.ins().srem(l, r),
|
||||
_ => builder.ins().iconst(types::I64, 0),
|
||||
};
|
||||
vals.insert(*dst, out);
|
||||
}
|
||||
MirInstruction::Compare { dst, op, lhs, rhs } => {
|
||||
let l = *vals.get(lhs).ok_or_else(|| format!("undef {:?}", lhs))?;
|
||||
let r = *vals.get(rhs).ok_or_else(|| format!("undef {:?}", rhs))?;
|
||||
let cc = match op {
|
||||
CompareOp::Eq => IntCC::Equal,
|
||||
CompareOp::Ne => IntCC::NotEqual,
|
||||
CompareOp::Lt => IntCC::SignedLessThan,
|
||||
CompareOp::Le => IntCC::SignedLessThanOrEqual,
|
||||
CompareOp::Gt => IntCC::SignedGreaterThan,
|
||||
CompareOp::Ge => IntCC::SignedGreaterThanOrEqual,
|
||||
};
|
||||
let b1 = builder.ins().icmp(cc, l, r);
|
||||
let one = builder.ins().iconst(types::I64, 1);
|
||||
let zero = builder.ins().iconst(types::I64, 0);
|
||||
let i64v = builder.ins().select(b1, one, zero);
|
||||
vals.insert(*dst, i64v);
|
||||
}
|
||||
MirInstruction::Load { dst, ptr } => {
|
||||
if let Some(ss) = slots.get(ptr).copied() {
|
||||
let v = builder.ins().stack_load(types::I64, ss, 0);
|
||||
vals.insert(*dst, v);
|
||||
} else {
|
||||
vals.insert(*dst, builder.ins().iconst(types::I64, 0));
|
||||
}
|
||||
}
|
||||
MirInstruction::Store { value, ptr } => {
|
||||
let v = *vals
|
||||
.get(value)
|
||||
.ok_or_else(|| format!("undef {:?}", value))?;
|
||||
let ss = *slots.entry(*ptr).or_insert_with(|| {
|
||||
builder.create_sized_stack_slot(StackSlotData::new(
|
||||
StackSlotKind::ExplicitSlot,
|
||||
8,
|
||||
))
|
||||
});
|
||||
builder.ins().stack_store(v, ss, 0);
|
||||
}
|
||||
MirInstruction::Copy { dst, src } => {
|
||||
let v = *vals.get(src).ok_or_else(|| format!("undef {:?}", src))?;
|
||||
vals.insert(*dst, v);
|
||||
}
|
||||
_ => { /* ignore unhandled for now */ }
|
||||
}
|
||||
}
|
||||
// Terminator
|
||||
match &bb.terminator {
|
||||
Some(MirInstruction::Return { value }) => {
|
||||
let retv = if let Some(v) = value {
|
||||
*vals.get(v).unwrap_or(&builder.ins().iconst(types::I64, 0))
|
||||
} else {
|
||||
builder.ins().iconst(types::I64, 0)
|
||||
};
|
||||
builder.ins().return_(&[retv]);
|
||||
}
|
||||
Some(MirInstruction::Jump { target }) => {
|
||||
let t = *clif_blocks.get(target).unwrap();
|
||||
builder.ins().jump(t, &[]);
|
||||
}
|
||||
Some(MirInstruction::Branch {
|
||||
condition,
|
||||
then_bb,
|
||||
else_bb,
|
||||
}) => {
|
||||
let cond_i64 = *vals
|
||||
.get(condition)
|
||||
.unwrap_or(&builder.ins().iconst(types::I64, 0));
|
||||
let is_true = builder.ins().icmp_imm(IntCC::NotEqual, cond_i64, 0);
|
||||
let tb = *clif_blocks.get(then_bb).unwrap();
|
||||
let eb = *clif_blocks.get(else_bb).unwrap();
|
||||
builder.ins().brif(is_true, tb, &[], eb, &[]);
|
||||
}
|
||||
_ => {
|
||||
/* fallthrough not allowed: insert return 0 to keep verifier happy */
|
||||
let z = builder.ins().iconst(types::I64, 0);
|
||||
builder.ins().return_(&[z]);
|
||||
}
|
||||
}
|
||||
builder.seal_block(cb);
|
||||
}
|
||||
|
||||
builder.finalize();
|
||||
|
||||
module
|
||||
.define_function(func_id, &mut ctx)
|
||||
.map_err(|e| e.to_string())?;
|
||||
module.clear_context(&mut ctx);
|
||||
let _ = module.finalize_definitions();
|
||||
|
||||
let code = module.get_finalized_function(func_id);
|
||||
let func = unsafe { std::mem::transmute::<_, extern "C" fn() -> i64>(code) };
|
||||
let result = func();
|
||||
Ok(result)
|
||||
}
|
||||
259
archive/jit-cranelift/src/backend/cranelift/mod.rs
Normal file
259
archive/jit-cranelift/src/backend/cranelift/mod.rs
Normal file
@ -0,0 +1,259 @@
|
||||
/*!
|
||||
* Cranelift Backend (skeleton) - Compile MIR to native code for JIT/AOT
|
||||
*
|
||||
* Phase 11.7 kick-off: minimal stubs behind the `cranelift-jit` feature.
|
||||
*/
|
||||
|
||||
#![cfg(feature = "cranelift-jit")]
|
||||
|
||||
use crate::box_trait::{BoolBox, IntegerBox, NyashBox, StringBox, VoidBox};
|
||||
use crate::jit::lower::{
|
||||
builder::{IRBuilder, NoopBuilder},
|
||||
core::LowerCore,
|
||||
};
|
||||
use crate::jit::semantics::clif::ClifSemanticsSkeleton;
|
||||
use crate::mir::{function::MirModule, BinaryOp, ConstValue, MirInstruction, ValueId};
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
use crate::semantics::Semantics;
|
||||
use std::collections::HashMap;
|
||||
|
||||
pub mod builder;
|
||||
pub mod context; // Context/Block/Value env wrappers // Clif IRBuilder implementation (skeleton)
|
||||
pub mod lower {}
|
||||
pub mod jit; // JIT compile/execute using Cranelift (minimal)
|
||||
pub mod object {}
|
||||
|
||||
/// JIT: compile and execute a MIR module (skeleton)
|
||||
pub fn compile_and_execute(
|
||||
mir_module: &MirModule,
|
||||
_temp_name: &str,
|
||||
) -> Result<Box<dyn NyashBox>, String> {
|
||||
// Minimal semantics: Const/Return/Add only (straight-line code)
|
||||
let main = mir_module
|
||||
.functions
|
||||
.get("main")
|
||||
.ok_or("missing main function")?;
|
||||
|
||||
// Minimal ClifSem lowering pass (NoopBuilder): Const/Return/Add カバレッジ確認
|
||||
if std::env::var("NYASH_JIT_DUMP").ok().as_deref() == Some("1") {
|
||||
let mut builder = NoopBuilder::new();
|
||||
let mut lower = LowerCore::new();
|
||||
let _ = lower.lower_function(main, &mut builder);
|
||||
eprintln!(
|
||||
"[CLIF-LOWER] covered={} unsupported={}",
|
||||
lower.covered, lower.unsupported
|
||||
);
|
||||
}
|
||||
|
||||
// まずは新JITエンジン経路を試す(LowerCore -> CraneliftBuilder -> 実行)
|
||||
#[cfg(feature = "cranelift-jit")]
|
||||
{
|
||||
let mut engine = crate::jit::engine::JitEngine::new();
|
||||
if let Some(h) = engine.compile_function(&main.signature.name, main) {
|
||||
// 実行(引数なし)。戻り値は MIR の型に合わせて変換
|
||||
let out = engine.execute_handle(h, &[]);
|
||||
if let Some(jv) = out {
|
||||
let vmv =
|
||||
crate::jit::boundary::CallBoundaryBox::to_vm(&main.signature.return_type, jv);
|
||||
let boxed: Box<dyn NyashBox> = match vmv {
|
||||
crate::backend::vm::VMValue::Integer(i) => Box::new(IntegerBox::new(i)),
|
||||
crate::backend::vm::VMValue::Float(f) => {
|
||||
Box::new(crate::boxes::FloatBox::new(f))
|
||||
}
|
||||
crate::backend::vm::VMValue::Bool(b) => Box::new(BoolBox::new(b)),
|
||||
crate::backend::vm::VMValue::String(s) => Box::new(StringBox::new(&s)),
|
||||
crate::backend::vm::VMValue::BoxRef(b) => b.share_box(),
|
||||
crate::backend::vm::VMValue::Future(fu) => Box::new(fu),
|
||||
crate::backend::vm::VMValue::Void => Box::new(VoidBox::new()),
|
||||
};
|
||||
return Ok(boxed);
|
||||
}
|
||||
}
|
||||
// 失敗した場合はミニマルJITへフォールバック
|
||||
if let Ok(i) = crate::backend::cranelift::jit::compile_and_execute_minimal(main) {
|
||||
return Ok(Box::new(IntegerBox::new(i)));
|
||||
}
|
||||
}
|
||||
let mut regs: HashMap<ValueId, crate::backend::vm::VMValue> = HashMap::new();
|
||||
let mut cur = main.entry_block;
|
||||
let mut last_pred: Option<crate::mir::BasicBlockId> = None;
|
||||
loop {
|
||||
let bb = main
|
||||
.blocks
|
||||
.get(&cur)
|
||||
.ok_or_else(|| format!("invalid bb {:?}", cur))?;
|
||||
// PHI (very minimal): choose first input or predecessor match
|
||||
for inst in &bb.instructions {
|
||||
if let MirInstruction::Phi { dst, inputs } = inst {
|
||||
if let Some(pred) = last_pred {
|
||||
if let Some((_, v)) = inputs.iter().find(|(b, _)| *b == pred) {
|
||||
if let Some(val) = regs.get(v).cloned() {
|
||||
regs.insert(*dst, val);
|
||||
}
|
||||
}
|
||||
} else if let Some((_, v)) = inputs.first() {
|
||||
if let Some(val) = regs.get(v).cloned() {
|
||||
regs.insert(*dst, val);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
let mut sem = ClifSemanticsSkeleton::new();
|
||||
for inst in &bb.instructions {
|
||||
match inst {
|
||||
MirInstruction::Const { dst, value } => {
|
||||
let vv = match value {
|
||||
ConstValue::Integer(i) => sem.const_i64(*i),
|
||||
ConstValue::Float(f) => sem.const_f64(*f),
|
||||
ConstValue::Bool(b) => sem.const_bool(*b),
|
||||
ConstValue::String(s) => sem.const_str(s),
|
||||
ConstValue::Null | ConstValue::Void => sem.const_null(),
|
||||
};
|
||||
regs.insert(*dst, vv);
|
||||
}
|
||||
MirInstruction::BinOp { dst, op, lhs, rhs } if matches!(op, BinaryOp::Add) => {
|
||||
use crate::backend::vm::VMValue as V;
|
||||
let a = regs
|
||||
.get(lhs)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("undef {:?}", lhs))?;
|
||||
let b = regs
|
||||
.get(rhs)
|
||||
.cloned()
|
||||
.ok_or_else(|| format!("undef {:?}", rhs))?;
|
||||
let out = sem.add(a, b);
|
||||
regs.insert(*dst, out);
|
||||
}
|
||||
MirInstruction::Copy { dst, src } => {
|
||||
if let Some(v) = regs.get(src).cloned() {
|
||||
regs.insert(*dst, v);
|
||||
}
|
||||
}
|
||||
MirInstruction::Debug { .. }
|
||||
| MirInstruction::Print { .. }
|
||||
| MirInstruction::Barrier { .. }
|
||||
| MirInstruction::BarrierRead { .. }
|
||||
| MirInstruction::BarrierWrite { .. }
|
||||
| MirInstruction::Safepoint
|
||||
| MirInstruction::Load { .. }
|
||||
| MirInstruction::Store { .. }
|
||||
| MirInstruction::TypeOp { .. }
|
||||
| MirInstruction::Compare { .. }
|
||||
| MirInstruction::NewBox { .. }
|
||||
| MirInstruction::PluginInvoke { .. }
|
||||
| MirInstruction::BoxCall { .. }
|
||||
| MirInstruction::RefGet { .. }
|
||||
| MirInstruction::RefSet { .. }
|
||||
| MirInstruction::WeakRef { .. }
|
||||
| MirInstruction::FutureNew { .. }
|
||||
| MirInstruction::FutureSet { .. }
|
||||
| MirInstruction::Await { .. }
|
||||
| MirInstruction::Throw { .. }
|
||||
| MirInstruction::Catch { .. } => {
|
||||
// ignore for minimal path
|
||||
}
|
||||
MirInstruction::ExternCall {
|
||||
dst,
|
||||
iface_name,
|
||||
method_name,
|
||||
args,
|
||||
..
|
||||
} => {
|
||||
use crate::backend::vm::VMValue as V;
|
||||
match (iface_name.as_str(), method_name.as_str()) {
|
||||
("env.local", "get") => {
|
||||
if let Some(d) = dst {
|
||||
if let Some(a0) = args.get(0) {
|
||||
if let Some(v) = regs.get(a0).cloned() {
|
||||
regs.insert(*d, v);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
("env.local", "set") => {
|
||||
if args.len() >= 2 {
|
||||
if let Some(v) = regs.get(&args[1]).cloned() {
|
||||
regs.insert(args[0], v);
|
||||
}
|
||||
}
|
||||
// dst ignored
|
||||
}
|
||||
("env.box", "new") => {
|
||||
if let Some(d) = dst {
|
||||
if let Some(a0) = args.get(0) {
|
||||
if let Some(V::String(ty)) = regs.get(a0).cloned() {
|
||||
let reg =
|
||||
crate::runtime::box_registry::get_global_registry();
|
||||
// Collect args as NyashBox
|
||||
let mut ny_args: Vec<Box<dyn crate::box_trait::NyashBox>> =
|
||||
Vec::new();
|
||||
for vid in args.iter().skip(1) {
|
||||
if let Some(v) = regs.get(vid).cloned() {
|
||||
ny_args.push(v.to_nyash_box());
|
||||
}
|
||||
}
|
||||
if let Ok(b) = reg.create_box(&ty, &ny_args) {
|
||||
regs.insert(*d, V::from_nyash_box(b));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
_ => { /* ignore other externs in skeleton */ }
|
||||
}
|
||||
}
|
||||
MirInstruction::Phi { .. } => { /* handled above */ }
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
match &bb.terminator {
|
||||
Some(MirInstruction::Return { value }) => {
|
||||
use crate::backend::vm::VMValue as V;
|
||||
let vb = match value {
|
||||
Some(v) => regs.get(v).cloned().unwrap_or(V::Void),
|
||||
None => V::Void,
|
||||
};
|
||||
// Box to NyashBox
|
||||
let out: Box<dyn NyashBox> = match vb {
|
||||
V::Integer(i) => Box::new(IntegerBox::new(i)),
|
||||
V::Bool(b) => Box::new(BoolBox::new(b)),
|
||||
V::String(s) => Box::new(StringBox::new(&s)),
|
||||
V::Float(f) => Box::new(crate::boxes::FloatBox::new(f)),
|
||||
V::Void => Box::new(VoidBox::new()),
|
||||
V::Future(fu) => Box::new(fu),
|
||||
V::BoxRef(b) => b.share_box(),
|
||||
};
|
||||
return Ok(out);
|
||||
}
|
||||
Some(MirInstruction::Jump { target }) => {
|
||||
last_pred = Some(bb.id);
|
||||
cur = *target;
|
||||
}
|
||||
Some(MirInstruction::Branch {
|
||||
condition,
|
||||
then_bb,
|
||||
else_bb,
|
||||
}) => {
|
||||
// Minimal: integer/bool truthiness
|
||||
let c = regs
|
||||
.get(condition)
|
||||
.cloned()
|
||||
.unwrap_or(crate::backend::vm::VMValue::Void);
|
||||
let t = match c {
|
||||
crate::backend::vm::VMValue::Bool(b) => b,
|
||||
crate::backend::vm::VMValue::Integer(i) => i != 0,
|
||||
_ => false,
|
||||
};
|
||||
last_pred = Some(bb.id);
|
||||
cur = if t { *then_bb } else { *else_bb };
|
||||
}
|
||||
Some(other) => return Err(format!("unsupported terminator {:?}", other)),
|
||||
None => return Err(format!("unterminated block {:?}", bb.id)),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// AOT: compile to object file (not yet implemented in skeleton)
|
||||
pub fn compile_to_object(_mir_module: &MirModule, _out_path: &str) -> Result<(), String> {
|
||||
Err("Cranelift AOT emit not implemented (skeleton)".to_string())
|
||||
}
|
||||
Reference in New Issue
Block a user