Skip to content

Commit 2ff7e12

Browse files
committed
feat: Add ZRTL value conversion intrinsics and closure support
- Add HIR intrinsics for value conversion: - ClosureToZrtl: Convert compiler closure to ZrtlClosure - BoxToZrtl: Convert value pointer to DynamicBox - PrimitiveToBox: Convert primitives to DynamicBox - TypeTagOf: Get TypeTag for HIR types - Add C ABI conversion functions in compiler/zrtl.rs: - zyntax_closure_to_zrtl for raw closure wrapping - zyntax_box_i32/i64/f32/f64/bool for typed boxing - zyntax_primitive_to_box for generic boxing - type_tag_for_hir_type helper - Implement intrinsics in Cranelift backend - Add ZrtlClosure support to SDK (sdk/zrtl/src/closure.rs): - ZrtlClosure: Thread-safe type-erased closure wrapper - ZrtlOnceClosure: FnOnce semantics - RawClosureFn type for compiler-generated closures - C ABI functions for closure creation/calling - Add closure-based thread spawning to zrtl_thread plugin: - thread_spawn_closure: Spawn with owned closure - thread_spawn_closure_noarg: For closures with captures - thread_spawn_closure_cloned: Non-consuming spawn - thread_spawn_boxed: DynamicBox-based spawn
1 parent d7e7968 commit 2ff7e12

6 files changed

Lines changed: 1677 additions & 1 deletion

File tree

crates/compiler/src/cranelift_backend.rs

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3198,6 +3198,117 @@ impl CraneliftBackend {
31983198
builder.ins().call(abort_func_ref, &[]);
31993199
builder.ins().trap(cranelift_codegen::ir::TrapCode::UnreachableCodeReached);
32003200
}
3201+
3202+
// ZRTL Value Conversion Intrinsics
3203+
crate::hir::Intrinsic::ClosureToZrtl => {
3204+
// Convert closure to ZrtlClosure
3205+
// Args: fn_ptr (pointer), env_ptr (pointer), env_size (i64)
3206+
// Returns: pointer to ZrtlClosure
3207+
if arg_vals.len() >= 3 {
3208+
let fn_ptr = arg_vals[0];
3209+
let env_ptr = arg_vals[1];
3210+
let env_size = arg_vals[2];
3211+
3212+
// Declare zyntax_closure_to_zrtl
3213+
let mut sig = self.module.make_signature();
3214+
sig.params.push(cranelift_codegen::ir::AbiParam::new(types::I64)); // fn_ptr
3215+
sig.params.push(cranelift_codegen::ir::AbiParam::new(types::I64)); // env_ptr
3216+
sig.params.push(cranelift_codegen::ir::AbiParam::new(types::I64)); // env_size
3217+
sig.returns.push(cranelift_codegen::ir::AbiParam::new(types::I64)); // result ptr
3218+
3219+
let func = self.module
3220+
.declare_function("zyntax_closure_to_zrtl", cranelift_module::Linkage::Import, &sig)
3221+
.map_err(|e| CompilerError::Backend(format!("Failed to declare zyntax_closure_to_zrtl: {}", e)))?;
3222+
let func_ref = self.module.declare_func_in_func(func, builder.func);
3223+
3224+
let call_inst = builder.ins().call(func_ref, &[fn_ptr, env_ptr, env_size]);
3225+
let result_val = builder.inst_results(call_inst)[0];
3226+
3227+
if let Some(result_id) = result {
3228+
self.value_map.insert(*result_id, result_val);
3229+
}
3230+
}
3231+
}
3232+
3233+
crate::hir::Intrinsic::BoxToZrtl => {
3234+
// Convert value to DynamicBox
3235+
// Args: value_ptr (pointer), type_tag (i32), size (i32)
3236+
// Returns: pointer to DynamicBox
3237+
if arg_vals.len() >= 3 {
3238+
let value_ptr = arg_vals[0];
3239+
let type_tag = arg_vals[1];
3240+
let size = arg_vals[2];
3241+
3242+
// Declare zyntax_primitive_to_box
3243+
let mut sig = self.module.make_signature();
3244+
sig.params.push(cranelift_codegen::ir::AbiParam::new(types::I64)); // value_ptr
3245+
sig.params.push(cranelift_codegen::ir::AbiParam::new(types::I32)); // type_tag
3246+
sig.params.push(cranelift_codegen::ir::AbiParam::new(types::I32)); // size
3247+
sig.returns.push(cranelift_codegen::ir::AbiParam::new(types::I64)); // result ptr
3248+
3249+
let func = self.module
3250+
.declare_function("zyntax_primitive_to_box", cranelift_module::Linkage::Import, &sig)
3251+
.map_err(|e| CompilerError::Backend(format!("Failed to declare zyntax_primitive_to_box: {}", e)))?;
3252+
let func_ref = self.module.declare_func_in_func(func, builder.func);
3253+
3254+
let call_inst = builder.ins().call(func_ref, &[value_ptr, type_tag, size]);
3255+
let result_val = builder.inst_results(call_inst)[0];
3256+
3257+
if let Some(result_id) = result {
3258+
self.value_map.insert(*result_id, result_val);
3259+
}
3260+
}
3261+
}
3262+
3263+
crate::hir::Intrinsic::PrimitiveToBox => {
3264+
// Convert primitive value to DynamicBox based on type
3265+
// Args: value (any), type_tag (i32)
3266+
// Returns: pointer to DynamicBox
3267+
if arg_vals.len() >= 2 {
3268+
let value = arg_vals[0];
3269+
let _type_tag = arg_vals[1];
3270+
let value_ty = builder.func.dfg.value_type(value);
3271+
3272+
// Determine which boxing function to call based on type
3273+
let func_name = if value_ty == types::I32 {
3274+
"zyntax_box_i32"
3275+
} else if value_ty == types::I64 {
3276+
"zyntax_box_i64"
3277+
} else if value_ty == types::F32 {
3278+
"zyntax_box_f32"
3279+
} else if value_ty == types::F64 {
3280+
"zyntax_box_f64"
3281+
} else {
3282+
"zyntax_box_i64" // fallback
3283+
};
3284+
3285+
let mut sig = self.module.make_signature();
3286+
sig.params.push(cranelift_codegen::ir::AbiParam::new(value_ty));
3287+
sig.returns.push(cranelift_codegen::ir::AbiParam::new(types::I64));
3288+
3289+
let func = self.module
3290+
.declare_function(func_name, cranelift_module::Linkage::Import, &sig)
3291+
.map_err(|e| CompilerError::Backend(format!("Failed to declare {}: {}", func_name, e)))?;
3292+
let func_ref = self.module.declare_func_in_func(func, builder.func);
3293+
3294+
let call_inst = builder.ins().call(func_ref, &[value]);
3295+
let result_val = builder.inst_results(call_inst)[0];
3296+
3297+
if let Some(result_id) = result {
3298+
self.value_map.insert(*result_id, result_val);
3299+
}
3300+
}
3301+
}
3302+
3303+
crate::hir::Intrinsic::TypeTagOf => {
3304+
// Get TypeTag constant for a type
3305+
// This is resolved at compile time based on the type argument
3306+
// For now, return 0 (void) as placeholder
3307+
let result_val = builder.ins().iconst(types::I32, 0);
3308+
if let Some(result_id) = result {
3309+
self.value_map.insert(*result_id, result_val);
3310+
}
3311+
}
32013312
}
32023313
}
32033314
HirCallable::Symbol(symbol_name) => {

crates/compiler/src/hir.rs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1177,6 +1177,20 @@ pub enum Intrinsic {
11771177
// Error handling (Gap 8)
11781178
Panic, // Panic with message (unrecoverable error)
11791179
Abort, // Abort execution immediately (no cleanup)
1180+
1181+
// ZRTL Value Conversion (for extern/plugin calls)
1182+
/// Convert closure to ZrtlClosure: (fn_ptr, env_ptr, env_size) -> *ZrtlClosure
1183+
/// Args: fn_ptr (raw function pointer), env_ptr (captured environment), env_size (i64)
1184+
ClosureToZrtl,
1185+
/// Convert DynamicBox to ZRTL DynamicBox: (tag, value_ptr) -> *DynamicBox
1186+
/// Args: type_tag (i32), value_ptr (pointer to value)
1187+
BoxToZrtl,
1188+
/// Convert primitive to DynamicBox: (value, type_tag) -> *DynamicBox
1189+
/// Args: value (any primitive), type_tag (i32)
1190+
PrimitiveToBox,
1191+
/// Get type tag for a type: () -> i32
1192+
/// Computes ZRTL TypeTag from HIR type
1193+
TypeTagOf,
11801194
}
11811195

11821196
/// Local variable

0 commit comments

Comments
 (0)