//! # VM Intermediate Representation (ir_vm) //! //! This module defines the Intermediate Representation for the Prometeu VM. //! //! ## Memory Model //! //! * Heap is never directly addressable. //! * All HIP (Heap) access is mediated via Gate Pool resolution. //! * `Gate(GateId)` is the only HIP pointer form in `ir_vm`. //! //! ## Reference Counting (RC) //! //! The VM uses Reference Counting to manage HIP memory. //! //! ### RC Rules: //! * **Retain**: Increment `strong_rc` when a gate handle is copied. //! * **Release**: Decrement `strong_rc` when a gate handle is overwritten or dropped. //! //! ### RC-Sensitive Instructions: //! The following instructions are RC-sensitive and must trigger RC updates: //! * `LocalStore`: Release old value, retain new value. //! * `GateStore`: Release old value, retain new value. //! * `Pop`: Release the popped value. //! * `Ret`: Release all live locals in the frame. //! * `FrameSync`: Safe point; reclamation occurs after this point. pub mod types; pub mod module; pub mod instr; pub mod validate; pub use instr::{Instruction, InstrKind, Label}; pub use module::{Module, Function, Global, Param}; pub use types::{Type, Value, GateId, ConstId, TypeId}; #[cfg(test)] mod tests { use super::*; use crate::ir_core::ids::{ConstId, FunctionId}; use crate::ir_core::const_pool::{ConstPool, ConstantValue}; use serde_json; #[test] fn test_vm_ir_serialization() { let mut const_pool = ConstPool::new(); const_pool.insert(ConstantValue::String("Hello VM".to_string())); let module = Module { name: "test_module".to_string(), const_pool, functions: vec![Function { id: FunctionId(1), name: "main".to_string(), params: vec![], return_type: Type::Null, body: vec![ Instruction::new(InstrKind::PushConst(crate::ir_vm::types::ConstId(0)), None), Instruction::new(InstrKind::Call { func_id: FunctionId(2), arg_count: 1 }, None), Instruction::new(InstrKind::Ret, None), ], }], globals: vec![], }; let json = serde_json::to_string_pretty(&module).unwrap(); let expected = r#"{ "name": "test_module", "const_pool": { "constants": [ { "String": "Hello VM" } ] }, "functions": [ { "id": 1, "name": "main", "params": [], "return_type": "Null", "body": [ { "kind": { "PushConst": 0 }, "span": null }, { "kind": { "Call": { "func_id": 2, "arg_count": 1 } }, "span": null }, { "kind": "Ret", "span": null } ] } ], "globals": [] }"#; assert_eq!(json, expected); } #[test] fn test_lowering_smoke() { use crate::ir_core; use crate::lowering::lower_program; let mut const_pool = ir_core::ConstPool::new(); const_pool.insert(ir_core::ConstantValue::Int(42)); let program = ir_core::Program { const_pool, modules: vec![ir_core::Module { name: "test_core".to_string(), functions: vec![ir_core::Function { id: FunctionId(10), name: "start".to_string(), params: vec![], return_type: ir_core::Type::Void, blocks: vec![ir_core::Block { id: 0, instrs: vec![ ir_core::Instr::PushConst(ConstId(0)), ], terminator: ir_core::Terminator::Return, }], }], }], }; let vm_module = lower_program(&program).expect("Lowering failed"); assert_eq!(vm_module.name, "test_core"); assert_eq!(vm_module.functions.len(), 1); let func = &vm_module.functions[0]; assert_eq!(func.name, "start"); assert_eq!(func.id, FunctionId(10)); assert_eq!(func.body.len(), 3); match &func.body[0].kind { InstrKind::Label(Label(l)) => assert!(l.contains("block_0")), _ => panic!("Expected label"), } match &func.body[1].kind { InstrKind::PushConst(id) => assert_eq!(id.0, 0), _ => panic!("Expected PushConst"), } match &func.body[2].kind { InstrKind::Ret => (), _ => panic!("Expected Ret"), } } }