1#[cfg(feature = "jit")]
12pub mod jit {
13 use cranelift_codegen::ir::condcodes::IntCC;
14 use cranelift_codegen::ir::{types, AbiParam, InstBuilder, UserFuncName};
15 use cranelift_codegen::settings::{self, Configurable};
16 use cranelift_codegen::Context;
17 use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext, Variable};
18 use cranelift_jit::{JITBuilder, JITModule};
19 use cranelift_module::{FuncId, Linkage, Module};
20
21 use std::collections::HashMap;
22 use std::mem;
23
24 use crate::ast::{
25 self, BinOp, Expr, ExternBlock, ExternFunction, ExternItem, Item, Literal, PipeOp,
26 TypeExpr, UnaryOp,
27 };
28 use crate::ffi::ctypes::CType;
29 use crate::optimize::{OptLevel, Optimizer};
30 use crate::parser::Parser;
31
32 #[repr(C)]
44 #[derive(Clone, Copy, Debug)]
45 pub struct SigilValue(pub u64);
46
47 impl SigilValue {
48 pub const TAG_INT: u64 = 0;
50 pub const TAG_FLOAT: u64 = 1;
51 pub const TAG_BOOL: u64 = 2;
52 pub const TAG_NULL: u64 = 3;
53 pub const TAG_PTR: u64 = 4; #[inline]
56 pub fn from_int(v: i64) -> Self {
57 SigilValue(v as u64)
58 }
59
60 #[inline]
61 pub fn from_float(v: f64) -> Self {
62 SigilValue(v.to_bits())
63 }
64
65 #[inline]
66 pub fn from_bool(v: bool) -> Self {
67 SigilValue(if v { 1 } else { 0 })
68 }
69
70 #[inline]
71 pub fn as_int(self) -> i64 {
72 self.0 as i64
73 }
74
75 #[inline]
76 pub fn as_float(self) -> f64 {
77 f64::from_bits(self.0)
78 }
79
80 #[inline]
81 pub fn as_bool(self) -> bool {
82 self.0 != 0
83 }
84 }
85
86 type CompiledFn = unsafe extern "C" fn() -> i64;
88 #[allow(dead_code)]
89 type CompiledFnWithArgs = unsafe extern "C" fn(i64) -> i64;
90
91 #[derive(Clone, Debug)]
93 pub struct ExternFnSig {
94 pub name: String,
95 pub params: Vec<types::Type>,
96 pub returns: Option<types::Type>,
97 pub variadic: bool,
98 pub func_id: FuncId,
99 }
100
101 pub struct JitCompiler {
103 module: JITModule,
105 builder_ctx: FunctionBuilderContext,
107 ctx: Context,
109 functions: HashMap<String, FuncId>,
111 extern_functions: HashMap<String, ExternFnSig>,
113 #[allow(dead_code)]
115 var_counter: usize,
116 #[allow(dead_code)]
118 builtins: HashMap<String, *const u8>,
119 }
120
121 impl JitCompiler {
122 pub fn new() -> Result<Self, String> {
124 let mut flag_builder = settings::builder();
125 flag_builder.set("use_colocated_libcalls", "false").unwrap();
127 flag_builder.set("is_pic", "false").unwrap();
128 flag_builder.set("opt_level", "speed").unwrap();
130 flag_builder.set("enable_verifier", "false").unwrap(); flag_builder.set("enable_alias_analysis", "true").unwrap();
133
134 let isa_builder = cranelift_native::builder().map_err(|e| e.to_string())?;
136 let isa = isa_builder
137 .finish(settings::Flags::new(flag_builder))
138 .map_err(|e| e.to_string())?;
139
140 let mut builder = JITBuilder::with_isa(isa, cranelift_module::default_libcall_names());
141
142 let builtins = Self::register_builtins(&mut builder);
144
145 let module = JITModule::new(builder);
146
147 Ok(Self {
148 module,
149 builder_ctx: FunctionBuilderContext::new(),
150 ctx: Context::new(),
151 functions: HashMap::new(),
152 extern_functions: HashMap::new(),
153 var_counter: 0,
154 builtins,
155 })
156 }
157
158 fn register_builtins(builder: &mut JITBuilder) -> HashMap<String, *const u8> {
160 let mut builtins = HashMap::new();
161
162 builder.symbol("sigil_sqrt", sigil_sqrt as *const u8);
164 builder.symbol("sigil_sin", sigil_sin as *const u8);
165 builder.symbol("sigil_cos", sigil_cos as *const u8);
166 builder.symbol("sigil_pow", sigil_pow as *const u8);
167 builder.symbol("sigil_exp", sigil_exp as *const u8);
168 builder.symbol("sigil_ln", sigil_ln as *const u8);
169 builder.symbol("sigil_floor", sigil_floor as *const u8);
170 builder.symbol("sigil_ceil", sigil_ceil as *const u8);
171 builder.symbol("sigil_abs", sigil_abs as *const u8);
172
173 builder.symbol("sigil_print", sigil_print as *const u8);
175 builder.symbol("sigil_print_int", sigil_print_int as *const u8);
176 builder.symbol("sigil_print_float", sigil_print_float as *const u8);
177 builder.symbol("sigil_print_str", sigil_print_str as *const u8);
178
179 builder.symbol("sigil_now", sigil_now as *const u8);
181
182 builder.symbol("sigil_add", sigil_add as *const u8);
184 builder.symbol("sigil_sub", sigil_sub as *const u8);
185 builder.symbol("sigil_mul", sigil_mul as *const u8);
186 builder.symbol("sigil_div", sigil_div as *const u8);
187 builder.symbol("sigil_lt", sigil_lt as *const u8);
188 builder.symbol("sigil_le", sigil_le as *const u8);
189 builder.symbol("sigil_gt", sigil_gt as *const u8);
190 builder.symbol("sigil_ge", sigil_ge as *const u8);
191
192 builder.symbol("sigil_simd_new", sigil_simd_new as *const u8);
194 builder.symbol("sigil_simd_splat", sigil_simd_splat as *const u8);
195 builder.symbol("sigil_simd_add", sigil_simd_add as *const u8);
196 builder.symbol("sigil_simd_sub", sigil_simd_sub as *const u8);
197 builder.symbol("sigil_simd_mul", sigil_simd_mul as *const u8);
198 builder.symbol("sigil_simd_div", sigil_simd_div as *const u8);
199 builder.symbol("sigil_simd_dot", sigil_simd_dot as *const u8);
200 builder.symbol("sigil_simd_hadd", sigil_simd_hadd as *const u8);
201 builder.symbol("sigil_simd_length_sq", sigil_simd_length_sq as *const u8);
202 builder.symbol("sigil_simd_length", sigil_simd_length as *const u8);
203 builder.symbol("sigil_simd_normalize", sigil_simd_normalize as *const u8);
204 builder.symbol("sigil_simd_cross", sigil_simd_cross as *const u8);
205 builder.symbol("sigil_simd_min", sigil_simd_min as *const u8);
206 builder.symbol("sigil_simd_max", sigil_simd_max as *const u8);
207 builder.symbol("sigil_simd_extract", sigil_simd_extract as *const u8);
208 builder.symbol("sigil_simd_free", sigil_simd_free as *const u8);
209
210 builder.symbol("sigil_array_new", sigil_array_new as *const u8);
212 builder.symbol("sigil_array_push", sigil_array_push as *const u8);
213 builder.symbol("sigil_array_get", sigil_array_get as *const u8);
214 builder.symbol("sigil_array_set", sigil_array_set as *const u8);
215 builder.symbol("sigil_array_len", sigil_array_len as *const u8);
216
217 builder.symbol("sigil_array_sum", sigil_array_sum as *const u8);
219 builder.symbol("sigil_array_scale", sigil_array_scale as *const u8);
220 builder.symbol("sigil_array_offset", sigil_array_offset as *const u8);
221 builder.symbol("sigil_array_dot", sigil_array_dot as *const u8);
222 builder.symbol("sigil_array_add", sigil_array_add as *const u8);
223 builder.symbol("sigil_array_mul", sigil_array_mul as *const u8);
224 builder.symbol("sigil_array_min", sigil_array_min as *const u8);
225 builder.symbol("sigil_array_max", sigil_array_max as *const u8);
226 builder.symbol("sigil_array_fill", sigil_array_fill as *const u8);
227
228 builder.symbol("sigil_array_first", sigil_array_first as *const u8);
230 builder.symbol("sigil_array_last", sigil_array_last as *const u8);
231 builder.symbol("sigil_array_middle", sigil_array_middle as *const u8);
232 builder.symbol("sigil_array_choice", sigil_array_choice as *const u8);
233 builder.symbol("sigil_array_nth", sigil_array_nth as *const u8);
234 builder.symbol("sigil_array_next", sigil_array_next as *const u8);
235 builder.symbol("sigil_array_product", sigil_array_product as *const u8);
236 builder.symbol("sigil_array_sort", sigil_array_sort as *const u8);
237
238 builder.symbol("sigil_parallel_map", sigil_parallel_map as *const u8);
240 builder.symbol("sigil_parallel_filter", sigil_parallel_filter as *const u8);
241 builder.symbol("sigil_parallel_reduce", sigil_parallel_reduce as *const u8);
242
243 builder.symbol("sigil_gpu_map", sigil_gpu_map as *const u8);
245 builder.symbol("sigil_gpu_filter", sigil_gpu_filter as *const u8);
246 builder.symbol("sigil_gpu_reduce", sigil_gpu_reduce as *const u8);
247
248 builder.symbol("sigil_memo_new", sigil_memo_new as *const u8);
250 builder.symbol("sigil_memo_get_1", sigil_memo_get_1 as *const u8);
251 builder.symbol("sigil_memo_set_1", sigil_memo_set_1 as *const u8);
252 builder.symbol("sigil_memo_get_2", sigil_memo_get_2 as *const u8);
253 builder.symbol("sigil_memo_set_2", sigil_memo_set_2 as *const u8);
254 builder.symbol("sigil_memo_free", sigil_memo_free as *const u8);
255
256 builder.symbol("sigil_ackermann", sigil_ackermann as *const u8);
258 builder.symbol("sigil_tak", sigil_tak as *const u8);
259
260 use crate::ffi::helpers::*;
262 builder.symbol(
263 "sigil_string_to_cstring",
264 sigil_string_to_cstring as *const u8,
265 );
266 builder.symbol("sigil_cstring_free", sigil_cstring_free as *const u8);
267 builder.symbol("sigil_cstring_len", sigil_cstring_len as *const u8);
268 builder.symbol("sigil_cstring_copy", sigil_cstring_copy as *const u8);
269 builder.symbol("sigil_ptr_from_int", sigil_ptr_from_int as *const u8);
270 builder.symbol("sigil_ptr_to_int", sigil_ptr_to_int as *const u8);
271 builder.symbol("sigil_ptr_read_u8", sigil_ptr_read_u8 as *const u8);
272 builder.symbol("sigil_ptr_write_u8", sigil_ptr_write_u8 as *const u8);
273 builder.symbol("sigil_ptr_read_i32", sigil_ptr_read_i32 as *const u8);
274 builder.symbol("sigil_ptr_write_i32", sigil_ptr_write_i32 as *const u8);
275 builder.symbol("sigil_ptr_read_i64", sigil_ptr_read_i64 as *const u8);
276 builder.symbol("sigil_ptr_write_i64", sigil_ptr_write_i64 as *const u8);
277 builder.symbol("sigil_ptr_read_f64", sigil_ptr_read_f64 as *const u8);
278 builder.symbol("sigil_ptr_write_f64", sigil_ptr_write_f64 as *const u8);
279 builder.symbol("sigil_ptr_add", sigil_ptr_add as *const u8);
280 builder.symbol("sigil_ptr_is_null", sigil_ptr_is_null as *const u8);
281 builder.symbol("sigil_alloc", sigil_alloc as *const u8);
282 builder.symbol("sigil_free", sigil_free as *const u8);
283 builder.symbol("sigil_realloc", sigil_realloc as *const u8);
284 builder.symbol("sigil_memcpy", sigil_memcpy as *const u8);
285 builder.symbol("sigil_memset", sigil_memset as *const u8);
286
287 builtins.insert("sqrt".into(), sigil_sqrt as *const u8);
288 builtins.insert("sin".into(), sigil_sin as *const u8);
289 builtins.insert("cos".into(), sigil_cos as *const u8);
290 builtins.insert("pow".into(), sigil_pow as *const u8);
291 builtins.insert("exp".into(), sigil_exp as *const u8);
292 builtins.insert("ln".into(), sigil_ln as *const u8);
293 builtins.insert("floor".into(), sigil_floor as *const u8);
294 builtins.insert("ceil".into(), sigil_ceil as *const u8);
295 builtins.insert("abs".into(), sigil_abs as *const u8);
296 builtins.insert("print".into(), sigil_print as *const u8);
297 builtins.insert("now".into(), sigil_now as *const u8);
298
299 builtins
300 }
301
302 pub fn compile(&mut self, source: &str) -> Result<(), String> {
304 self.compile_with_opt(source, OptLevel::Aggressive)
305 }
306
307 pub fn compile_with_opt(
309 &mut self,
310 source: &str,
311 opt_level: OptLevel,
312 ) -> Result<(), String> {
313 let mut parser = Parser::new(source);
314 let source_file = parser.parse_file().map_err(|e| format!("{:?}", e))?;
315
316 let mut optimizer = Optimizer::new(opt_level);
318 let optimized = optimizer.optimize_file(&source_file);
319
320 for spanned_item in &optimized.items {
322 match &spanned_item.node {
323 Item::ExternBlock(extern_block) => {
324 self.declare_extern_block(extern_block)?;
325 }
326 Item::Function(func) => {
327 self.declare_function(func)?;
328 }
329 _ => {}
330 }
331 }
332
333 for spanned_item in &optimized.items {
335 if let Item::Function(func) = &spanned_item.node {
336 self.compile_function(func)?;
337 }
338 }
339
340 self.module
342 .finalize_definitions()
343 .map_err(|e| e.to_string())?;
344
345 Ok(())
346 }
347
348 fn declare_function(&mut self, func: &ast::Function) -> Result<FuncId, String> {
350 let name = &func.name.name;
351
352 let mut sig = self.module.make_signature();
354
355 for _param in &func.params {
357 sig.params.push(AbiParam::new(types::I64));
358 }
359
360 sig.returns.push(AbiParam::new(types::I64));
362
363 let func_id = self
364 .module
365 .declare_function(name, Linkage::Local, &sig)
366 .map_err(|e| e.to_string())?;
367
368 self.functions.insert(name.clone(), func_id);
369 Ok(func_id)
370 }
371
372 fn declare_extern_block(&mut self, extern_block: &ExternBlock) -> Result<(), String> {
374 if extern_block.abi != "C" && extern_block.abi != "c" {
376 return Err(format!(
377 "Unsupported ABI: {}. Only \"C\" is supported.",
378 extern_block.abi
379 ));
380 }
381
382 for item in &extern_block.items {
383 match item {
384 ExternItem::Function(func) => {
385 self.declare_extern_function(func)?;
386 }
387 ExternItem::Static(stat) => {
388 eprintln!(
390 "Warning: extern static '{}' not yet implemented",
391 stat.name.name
392 );
393 }
394 }
395 }
396
397 Ok(())
398 }
399
400 fn declare_extern_function(&mut self, func: &ExternFunction) -> Result<(), String> {
402 let name = &func.name.name;
403
404 let mut sig = self.module.make_signature();
406 let mut param_types = Vec::new();
407
408 for param in &func.params {
410 let ty = self.type_expr_to_cranelift(¶m.ty)?;
411 sig.params.push(AbiParam::new(ty));
412 param_types.push(ty);
413 }
414
415 let return_type = if let Some(ret_ty) = &func.return_type {
417 let ty = self.type_expr_to_cranelift(ret_ty)?;
418 sig.returns.push(AbiParam::new(ty));
419 Some(ty)
420 } else {
421 None
422 };
423
424 let func_id = self
428 .module
429 .declare_function(name, Linkage::Import, &sig)
430 .map_err(|e| e.to_string())?;
431
432 self.extern_functions.insert(
433 name.clone(),
434 ExternFnSig {
435 name: name.clone(),
436 params: param_types,
437 returns: return_type,
438 variadic: func.variadic,
439 func_id,
440 },
441 );
442
443 Ok(())
444 }
445
446 fn type_expr_to_cranelift(&self, ty: &TypeExpr) -> Result<types::Type, String> {
448 match ty {
449 TypeExpr::Path(path) => {
450 let name = path
451 .segments
452 .last()
453 .map(|s| s.ident.name.as_str())
454 .unwrap_or("");
455
456 if let Some(ctype) = CType::from_name(name) {
458 return Ok(match ctype {
459 CType::Void => types::I64, CType::Char
461 | CType::SChar
462 | CType::UChar
463 | CType::Int8
464 | CType::UInt8 => types::I8,
465 CType::Short | CType::UShort | CType::Int16 | CType::UInt16 => {
466 types::I16
467 }
468 CType::Int | CType::UInt | CType::Int32 | CType::UInt32 => types::I32,
469 CType::Long
470 | CType::ULong
471 | CType::LongLong
472 | CType::ULongLong
473 | CType::Size
474 | CType::SSize
475 | CType::PtrDiff
476 | CType::Int64
477 | CType::UInt64 => types::I64,
478 CType::Float => types::F32,
479 CType::Double => types::F64,
480 });
481 }
482
483 match name {
485 "i8" => Ok(types::I8),
486 "i16" => Ok(types::I16),
487 "i32" | "int" => Ok(types::I32),
488 "i64" => Ok(types::I64),
489 "u8" => Ok(types::I8),
490 "u16" => Ok(types::I16),
491 "u32" => Ok(types::I32),
492 "u64" => Ok(types::I64),
493 "f32" => Ok(types::F32),
494 "f64" | "float" => Ok(types::F64),
495 "bool" => Ok(types::I8),
496 "isize" | "usize" => Ok(types::I64),
497 "()" => Ok(types::I64), _ => Ok(types::I64), }
500 }
501 TypeExpr::Pointer { .. } | TypeExpr::Reference { .. } => {
502 Ok(types::I64)
504 }
505 _ => Ok(types::I64), }
507 }
508
509 fn compile_function(&mut self, func: &ast::Function) -> Result<(), String> {
511 let name = &func.name.name;
512 let func_id = *self.functions.get(name).ok_or("Function not declared")?;
513
514 for _param in &func.params {
516 self.ctx
517 .func
518 .signature
519 .params
520 .push(AbiParam::new(types::I64));
521 }
522 self.ctx
523 .func
524 .signature
525 .returns
526 .push(AbiParam::new(types::I64));
527 self.ctx.func.name = UserFuncName::user(0, func_id.as_u32());
528
529 let functions = self.functions.clone();
531 let extern_fns = self.extern_functions.clone();
532
533 {
534 let mut builder = FunctionBuilder::new(&mut self.ctx.func, &mut self.builder_ctx);
535
536 let entry_block = builder.create_block();
537 builder.append_block_params_for_function_params(entry_block);
538 builder.switch_to_block(entry_block);
539 builder.seal_block(entry_block);
540
541 let mut scope = CompileScope::new();
543
544 for (i, param) in func.params.iter().enumerate() {
546 let var = Variable::from_u32(scope.next_var() as u32);
547 builder.declare_var(var, types::I64);
548 let param_val = builder.block_params(entry_block)[i];
549 builder.def_var(var, param_val);
550
551 if let ast::Pattern::Ident { name, .. } = ¶m.pattern {
553 let param_type = match ¶m.ty {
555 TypeExpr::Path(path) => {
556 let type_name = path
557 .segments
558 .last()
559 .map(|s| s.ident.name.as_str())
560 .unwrap_or("");
561 match type_name {
562 "f32" | "f64" | "float" => ValueType::Float,
563 "i8" | "i16" | "i32" | "i64" | "int" | "isize" | "u8"
564 | "u16" | "u32" | "u64" | "usize" | "bool" => ValueType::Int,
565 _ => ValueType::Int, }
567 }
568 TypeExpr::Infer => ValueType::Int, _ => ValueType::Int, };
571 scope.define_typed(&name.name, var, param_type);
572 }
573 }
574
575 if let Some(body) = &func.body {
577 let (result, has_return) = compile_block_tracked(
578 &mut self.module,
579 &functions,
580 &extern_fns,
581 &mut builder,
582 &mut scope,
583 body,
584 )?;
585 if !has_return {
587 builder.ins().return_(&[result]);
588 }
589 } else {
590 let zero = builder.ins().iconst(types::I64, 0);
592 builder.ins().return_(&[zero]);
593 }
594
595 builder.finalize();
596 }
597
598 self.module
603 .define_function(func_id, &mut self.ctx)
604 .map_err(|e| format!("Compilation error for '{}': {}", name, e))?;
605
606 self.module.clear_context(&mut self.ctx);
607 Ok(())
608 }
609
610 pub fn run(&mut self) -> Result<i64, String> {
612 let main_id = *self.functions.get("main").ok_or("No main function")?;
613 let main_ptr = self.module.get_finalized_function(main_id);
614
615 unsafe {
616 let main_fn: CompiledFn = mem::transmute(main_ptr);
617 Ok(main_fn())
618 }
619 }
620
621 pub fn get_function(&self, name: &str) -> Option<*const u8> {
623 self.functions
624 .get(name)
625 .map(|id| self.module.get_finalized_function(*id))
626 }
627 }
628
629 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
632 enum ValueType {
633 Int, Float, Unknown, }
637
638 struct CompileScope {
643 variables: HashMap<String, Variable>,
644 var_types: HashMap<String, ValueType>,
646 var_counter: std::rc::Rc<std::cell::Cell<usize>>,
648 }
649
650 impl CompileScope {
651 fn new() -> Self {
652 Self {
653 variables: HashMap::new(),
654 var_types: HashMap::new(),
655 var_counter: std::rc::Rc::new(std::cell::Cell::new(0)),
656 }
657 }
658
659 fn child(&self) -> Self {
660 Self {
663 variables: self.variables.clone(),
664 var_types: self.var_types.clone(),
665 var_counter: std::rc::Rc::clone(&self.var_counter),
666 }
667 }
668
669 fn next_var(&mut self) -> usize {
670 let v = self.var_counter.get();
671 self.var_counter.set(v + 1);
672 v
673 }
674
675 #[allow(dead_code)]
676 fn define(&mut self, name: &str, var: Variable) {
677 self.variables.insert(name.to_string(), var);
678 }
679
680 fn define_typed(&mut self, name: &str, var: Variable, ty: ValueType) {
681 self.variables.insert(name.to_string(), var);
682 self.var_types.insert(name.to_string(), ty);
683 }
684
685 fn lookup(&self, name: &str) -> Option<Variable> {
686 self.variables.get(name).copied()
687 }
688
689 fn get_type(&self, name: &str) -> ValueType {
690 self.var_types
691 .get(name)
692 .copied()
693 .unwrap_or(ValueType::Unknown)
694 }
695
696 #[allow(dead_code)]
697 fn set_type(&mut self, name: &str, ty: ValueType) {
698 self.var_types.insert(name.to_string(), ty);
699 }
700 }
701
702 fn infer_type(expr: &Expr, scope: &CompileScope) -> ValueType {
710 match expr {
711 Expr::Literal(Literal::Int { .. }) => ValueType::Int,
712 Expr::Literal(Literal::Bool(_)) => ValueType::Int,
713 Expr::Literal(Literal::Float { .. }) => ValueType::Float,
714
715 Expr::Path(path) => {
716 let name = path
717 .segments
718 .last()
719 .map(|s| s.ident.name.as_str())
720 .unwrap_or("");
721 scope.get_type(name)
722 }
723
724 Expr::Binary { op, left, right } => {
725 let left_ty = infer_type(left, scope);
726 let right_ty = infer_type(right, scope);
727
728 if matches!(
730 op,
731 BinOp::Eq
732 | BinOp::Ne
733 | BinOp::Lt
734 | BinOp::Le
735 | BinOp::Gt
736 | BinOp::Ge
737 | BinOp::And
738 | BinOp::Or
739 ) {
740 return ValueType::Int;
741 }
742
743 if left_ty == ValueType::Float || right_ty == ValueType::Float {
745 return ValueType::Float;
746 }
747
748 if left_ty == ValueType::Int && right_ty == ValueType::Int {
750 return ValueType::Int;
751 }
752
753 ValueType::Unknown
755 }
756
757 Expr::Unary { op, expr } => {
758 match op {
759 UnaryOp::Not => ValueType::Int, UnaryOp::Neg => infer_type(expr, scope),
761 _ => infer_type(expr, scope),
762 }
763 }
764
765 Expr::Call { func, args } => {
766 if let Expr::Path(path) = func.as_ref() {
768 let name = path
769 .segments
770 .last()
771 .map(|s| s.ident.name.as_str())
772 .unwrap_or("");
773 match name {
774 "sqrt" | "sin" | "cos" | "pow" | "exp" | "ln" | "floor" | "ceil"
776 | "abs" => ValueType::Float,
777 "now" => ValueType::Int,
779 "len" | "sigil_array_len" => ValueType::Int,
781 "print" | "sigil_print" => ValueType::Int,
783 _ => {
784 let all_args_int = args
788 .iter()
789 .all(|arg| infer_type(arg, scope) == ValueType::Int);
790 if all_args_int {
791 ValueType::Int
792 } else {
793 ValueType::Unknown
794 }
795 }
796 }
797 } else {
798 ValueType::Unknown
799 }
800 }
801
802 Expr::If {
803 then_branch,
804 else_branch,
805 ..
806 } => {
807 let then_ty = if let Some(expr) = &then_branch.expr {
809 infer_type(expr, scope)
810 } else {
811 ValueType::Int };
813
814 if let Some(else_expr) = else_branch {
815 let else_ty = infer_type(else_expr, scope);
816 if then_ty == else_ty {
817 then_ty
818 } else {
819 ValueType::Unknown
820 }
821 } else {
822 then_ty
823 }
824 }
825
826 _ => ValueType::Unknown,
827 }
828 }
829
830 fn try_const_fold(expr: &Expr) -> Option<i64> {
836 match expr {
837 Expr::Literal(Literal::Int { value, .. }) => value.parse().ok(),
838 Expr::Literal(Literal::Bool(b)) => Some(if *b { 1 } else { 0 }),
839 Expr::Binary { op, left, right } => {
840 let l = try_const_fold(left)?;
841 let r = try_const_fold(right)?;
842 match op {
843 BinOp::Add => Some(l.wrapping_add(r)),
844 BinOp::Sub => Some(l.wrapping_sub(r)),
845 BinOp::Mul => Some(l.wrapping_mul(r)),
846 BinOp::Div if r != 0 => Some(l / r),
847 BinOp::Rem if r != 0 => Some(l % r),
848 BinOp::BitAnd => Some(l & r),
849 BinOp::BitOr => Some(l | r),
850 BinOp::BitXor => Some(l ^ r),
851 BinOp::Shl => Some(l << (r & 63)),
852 BinOp::Shr => Some(l >> (r & 63)),
853 BinOp::Eq => Some(if l == r { 1 } else { 0 }),
854 BinOp::Ne => Some(if l != r { 1 } else { 0 }),
855 BinOp::Lt => Some(if l < r { 1 } else { 0 }),
856 BinOp::Le => Some(if l <= r { 1 } else { 0 }),
857 BinOp::Gt => Some(if l > r { 1 } else { 0 }),
858 BinOp::Ge => Some(if l >= r { 1 } else { 0 }),
859 BinOp::And => Some(if l != 0 && r != 0 { 1 } else { 0 }),
860 BinOp::Or => Some(if l != 0 || r != 0 { 1 } else { 0 }),
861 _ => None,
862 }
863 }
864 Expr::Unary { op, expr } => {
865 let v = try_const_fold(expr)?;
866 match op {
867 UnaryOp::Neg => Some(-v),
868 UnaryOp::Not => Some(if v == 0 { 1 } else { 0 }),
869 _ => None,
870 }
871 }
872 _ => None,
873 }
874 }
875
876 fn compile_condition(
883 module: &mut JITModule,
884 functions: &HashMap<String, FuncId>,
885 extern_fns: &HashMap<String, ExternFnSig>,
886 builder: &mut FunctionBuilder,
887 scope: &mut CompileScope,
888 condition: &Expr,
889 ) -> Result<cranelift_codegen::ir::Value, String> {
890 if let Expr::Binary { op, left, right } = condition {
892 let cc = match op {
893 BinOp::Eq => Some(IntCC::Equal),
894 BinOp::Ne => Some(IntCC::NotEqual),
895 BinOp::Lt => Some(IntCC::SignedLessThan),
896 BinOp::Le => Some(IntCC::SignedLessThanOrEqual),
897 BinOp::Gt => Some(IntCC::SignedGreaterThan),
898 BinOp::Ge => Some(IntCC::SignedGreaterThanOrEqual),
899 _ => None,
900 };
901
902 if let Some(cc) = cc {
903 let lhs = compile_expr(module, functions, extern_fns, builder, scope, left)?;
904 let rhs = compile_expr(module, functions, extern_fns, builder, scope, right)?;
905 return Ok(builder.ins().icmp(cc, lhs, rhs));
907 }
908
909 if matches!(op, BinOp::And | BinOp::Or) {
911 }
914 }
915
916 if let Expr::Unary {
918 op: UnaryOp::Not,
919 expr,
920 } = condition
921 {
922 let inner = compile_condition(module, functions, extern_fns, builder, scope, expr)?;
923 let true_val = builder.ins().iconst(types::I8, 1);
925 return Ok(builder.ins().bxor(inner, true_val));
926 }
927
928 if let Expr::Literal(Literal::Bool(b)) = condition {
930 return Ok(builder.ins().iconst(types::I8, if *b { 1 } else { 0 }));
931 }
932
933 let val = compile_expr(module, functions, extern_fns, builder, scope, condition)?;
935 let zero = builder.ins().iconst(types::I64, 0);
936 Ok(builder.ins().icmp(IntCC::NotEqual, val, zero))
937 }
938
939 #[allow(dead_code)]
945 fn is_tail_call_to<'a>(expr: &'a Expr, func_name: &str) -> Option<&'a Vec<Expr>> {
946 if let Expr::Return(Some(inner)) = expr {
947 if let Expr::Call { func, args } = inner.as_ref() {
948 if let Expr::Path(path) = func.as_ref() {
949 let name = path
950 .segments
951 .last()
952 .map(|s| s.ident.name.as_str())
953 .unwrap_or("");
954 if name == func_name {
955 return Some(args);
956 }
957 }
958 }
959 }
960 None
961 }
962
963 fn compile_block_tracked(
969 module: &mut JITModule,
970 functions: &HashMap<String, FuncId>,
971 extern_fns: &HashMap<String, ExternFnSig>,
972 builder: &mut FunctionBuilder,
973 scope: &mut CompileScope,
974 block: &ast::Block,
975 ) -> Result<(cranelift_codegen::ir::Value, bool), String> {
976 let mut last_val: Option<cranelift_codegen::ir::Value> = None;
978 let mut has_return = false;
979
980 for stmt in &block.stmts {
981 let (val, ret) =
982 compile_stmt_tracked(module, functions, extern_fns, builder, scope, stmt)?;
983 last_val = Some(val);
984 if ret {
985 has_return = true;
986 }
987 }
988
989 if let Some(expr) = &block.expr {
990 let (val, ret) =
991 compile_expr_tracked(module, functions, extern_fns, builder, scope, expr)?;
992 last_val = Some(val);
993 if ret {
994 has_return = true;
995 }
996 }
997
998 let result = last_val.unwrap_or_else(|| builder.ins().iconst(types::I64, 0));
1000 Ok((result, has_return))
1001 }
1002
1003 fn compile_block(
1005 module: &mut JITModule,
1006 functions: &HashMap<String, FuncId>,
1007 extern_fns: &HashMap<String, ExternFnSig>,
1008 builder: &mut FunctionBuilder,
1009 scope: &mut CompileScope,
1010 block: &ast::Block,
1011 ) -> Result<cranelift_codegen::ir::Value, String> {
1012 compile_block_tracked(module, functions, extern_fns, builder, scope, block).map(|(v, _)| v)
1013 }
1014
1015 fn compile_stmt_tracked(
1017 module: &mut JITModule,
1018 functions: &HashMap<String, FuncId>,
1019 extern_fns: &HashMap<String, ExternFnSig>,
1020 builder: &mut FunctionBuilder,
1021 scope: &mut CompileScope,
1022 stmt: &ast::Stmt,
1023 ) -> Result<(cranelift_codegen::ir::Value, bool), String> {
1024 match stmt {
1025 ast::Stmt::Let { pattern, init, .. } => {
1026 let ty = if let Some(expr) = init {
1028 infer_type(expr, scope)
1029 } else {
1030 ValueType::Int };
1032
1033 let val = if let Some(expr) = init {
1034 compile_expr(module, functions, extern_fns, builder, scope, expr)?
1035 } else {
1036 builder.ins().iconst(types::I64, 0)
1037 };
1038
1039 if let ast::Pattern::Ident { name, .. } = pattern {
1040 let var = Variable::from_u32(scope.next_var() as u32);
1041 builder.declare_var(var, types::I64);
1042 builder.def_var(var, val);
1043 scope.define_typed(&name.name, var, ty);
1045 }
1046
1047 Ok((val, false))
1048 }
1049 ast::Stmt::LetElse {
1050 pattern,
1051 init,
1052 else_branch,
1053 ..
1054 } => {
1055 let val = compile_expr(module, functions, extern_fns, builder, scope, init)?;
1058 let ty = infer_type(init, scope);
1059
1060 if let ast::Pattern::Ident { name, .. } = pattern {
1061 let var = Variable::from_u32(scope.next_var() as u32);
1062 builder.declare_var(var, types::I64);
1063 builder.def_var(var, val);
1064 scope.define_typed(&name.name, var, ty);
1065 }
1066
1067 let _ = else_branch;
1071
1072 Ok((val, false))
1073 }
1074 ast::Stmt::Expr(expr) | ast::Stmt::Semi(expr) => {
1075 compile_expr_tracked(module, functions, extern_fns, builder, scope, expr)
1076 }
1077 ast::Stmt::Item(_) => Ok((builder.ins().iconst(types::I64, 0), false)),
1078 }
1079 }
1080
1081 #[allow(dead_code)]
1083 fn compile_stmt(
1084 module: &mut JITModule,
1085 functions: &HashMap<String, FuncId>,
1086 extern_fns: &HashMap<String, ExternFnSig>,
1087 builder: &mut FunctionBuilder,
1088 scope: &mut CompileScope,
1089 stmt: &ast::Stmt,
1090 ) -> Result<cranelift_codegen::ir::Value, String> {
1091 compile_stmt_tracked(module, functions, extern_fns, builder, scope, stmt).map(|(v, _)| v)
1092 }
1093
1094 fn compile_expr_tracked(
1096 module: &mut JITModule,
1097 functions: &HashMap<String, FuncId>,
1098 extern_fns: &HashMap<String, ExternFnSig>,
1099 builder: &mut FunctionBuilder,
1100 scope: &mut CompileScope,
1101 expr: &Expr,
1102 ) -> Result<(cranelift_codegen::ir::Value, bool), String> {
1103 match expr {
1104 Expr::Return(value) => {
1105 let ret_val = if let Some(v) = value {
1117 compile_expr(module, functions, extern_fns, builder, scope, v)?
1118 } else {
1119 builder.ins().iconst(types::I64, 0)
1120 };
1121 builder.ins().return_(&[ret_val]);
1122 Ok((ret_val, true)) }
1124 Expr::If {
1125 condition,
1126 then_branch,
1127 else_branch,
1128 } => {
1129 compile_if_tracked(
1131 module,
1132 functions,
1133 extern_fns,
1134 builder,
1135 scope,
1136 condition,
1137 then_branch,
1138 else_branch.as_deref(),
1139 )
1140 }
1141 Expr::Block(block) => {
1142 let mut inner_scope = scope.child();
1143 compile_block_tracked(
1144 module,
1145 functions,
1146 extern_fns,
1147 builder,
1148 &mut inner_scope,
1149 block,
1150 )
1151 }
1152 _ => {
1153 let val = compile_expr(module, functions, extern_fns, builder, scope, expr)?;
1155 Ok((val, false))
1156 }
1157 }
1158 }
1159
1160 fn compile_expr(
1162 module: &mut JITModule,
1163 functions: &HashMap<String, FuncId>,
1164 extern_fns: &HashMap<String, ExternFnSig>,
1165 builder: &mut FunctionBuilder,
1166 scope: &mut CompileScope,
1167 expr: &Expr,
1168 ) -> Result<cranelift_codegen::ir::Value, String> {
1169 if let Some(val) = try_const_fold(expr) {
1171 return Ok(builder.ins().iconst(types::I64, val));
1172 }
1173
1174 match expr {
1175 Expr::Literal(lit) => compile_literal(builder, lit),
1176
1177 Expr::Path(path) => {
1178 let name = path
1179 .segments
1180 .last()
1181 .map(|s| s.ident.name.clone())
1182 .unwrap_or_default();
1183 if let Some(var) = scope.lookup(&name) {
1184 Ok(builder.use_var(var))
1185 } else {
1186 Err(format!("Undefined variable: {}", name))
1187 }
1188 }
1189
1190 Expr::Binary { op, left, right } => {
1191 let left_ty = infer_type(left, scope);
1193 let right_ty = infer_type(right, scope);
1194
1195 let lhs = compile_expr(module, functions, extern_fns, builder, scope, left)?;
1196 let rhs = compile_expr(module, functions, extern_fns, builder, scope, right)?;
1197
1198 if left_ty == ValueType::Int && right_ty == ValueType::Int {
1201 return compile_binary_op(builder, op.clone(), lhs, rhs);
1203 }
1204
1205 if left_ty == ValueType::Float && right_ty == ValueType::Float {
1207 return compile_float_binary_op(builder, op, lhs, rhs);
1208 }
1209
1210 match op {
1213 BinOp::Add => compile_call(
1214 module,
1215 functions,
1216 extern_fns,
1217 builder,
1218 "sigil_add",
1219 &[lhs, rhs],
1220 ),
1221 BinOp::Sub => compile_call(
1222 module,
1223 functions,
1224 extern_fns,
1225 builder,
1226 "sigil_sub",
1227 &[lhs, rhs],
1228 ),
1229 BinOp::Mul => compile_call(
1230 module,
1231 functions,
1232 extern_fns,
1233 builder,
1234 "sigil_mul",
1235 &[lhs, rhs],
1236 ),
1237 BinOp::Div => compile_call(
1238 module,
1239 functions,
1240 extern_fns,
1241 builder,
1242 "sigil_div",
1243 &[lhs, rhs],
1244 ),
1245 BinOp::Lt => compile_call(
1246 module,
1247 functions,
1248 extern_fns,
1249 builder,
1250 "sigil_lt",
1251 &[lhs, rhs],
1252 ),
1253 BinOp::Le => compile_call(
1254 module,
1255 functions,
1256 extern_fns,
1257 builder,
1258 "sigil_le",
1259 &[lhs, rhs],
1260 ),
1261 BinOp::Gt => compile_call(
1262 module,
1263 functions,
1264 extern_fns,
1265 builder,
1266 "sigil_gt",
1267 &[lhs, rhs],
1268 ),
1269 BinOp::Ge => compile_call(
1270 module,
1271 functions,
1272 extern_fns,
1273 builder,
1274 "sigil_ge",
1275 &[lhs, rhs],
1276 ),
1277 _ => compile_binary_op(builder, op.clone(), lhs, rhs),
1278 }
1279 }
1280
1281 Expr::Unary { op, expr: inner } => {
1282 let val = compile_expr(module, functions, extern_fns, builder, scope, inner)?;
1283 compile_unary_op(builder, *op, val)
1284 }
1285
1286 Expr::Call { func, args } => {
1287 let func_name = match func.as_ref() {
1288 Expr::Path(path) => path
1289 .segments
1290 .last()
1291 .map(|s| s.ident.name.clone())
1292 .unwrap_or_default(),
1293 _ => return Err("Only direct function calls supported".into()),
1294 };
1295
1296 let mut arg_vals = Vec::new();
1297 for arg in args {
1298 arg_vals.push(compile_expr(
1299 module, functions, extern_fns, builder, scope, arg,
1300 )?);
1301 }
1302
1303 compile_call(
1304 module, functions, extern_fns, builder, &func_name, &arg_vals,
1305 )
1306 }
1307
1308 Expr::If {
1309 condition,
1310 then_branch,
1311 else_branch,
1312 } => compile_if(
1313 module,
1314 functions,
1315 extern_fns,
1316 builder,
1317 scope,
1318 condition,
1319 then_branch,
1320 else_branch.as_deref(),
1321 ),
1322
1323 Expr::While {
1324 condition, body, ..
1325 } => compile_while(
1326 module, functions, extern_fns, builder, scope, condition, body,
1327 ),
1328
1329 Expr::Block(block) => {
1330 let mut inner_scope = scope.child();
1331 compile_block(
1332 module,
1333 functions,
1334 extern_fns,
1335 builder,
1336 &mut inner_scope,
1337 block,
1338 )
1339 }
1340
1341 Expr::Return(value) => {
1342 let ret_val = if let Some(v) = value {
1345 compile_expr(module, functions, extern_fns, builder, scope, v)?
1346 } else {
1347 builder.ins().iconst(types::I64, 0)
1348 };
1349 builder.ins().return_(&[ret_val]);
1350 Ok(ret_val)
1351 }
1352
1353 Expr::Assign { target, value } => {
1354 let val = compile_expr(module, functions, extern_fns, builder, scope, value)?;
1355 match target.as_ref() {
1356 Expr::Path(path) => {
1357 let name = path
1358 .segments
1359 .last()
1360 .map(|s| s.ident.name.clone())
1361 .unwrap_or_default();
1362 if let Some(var) = scope.lookup(&name) {
1363 builder.def_var(var, val);
1364 Ok(val)
1365 } else {
1366 Err(format!("Undefined variable: {}", name))
1367 }
1368 }
1369 Expr::Index { expr: arr, index } => {
1370 let arr_val =
1371 compile_expr(module, functions, extern_fns, builder, scope, arr)?;
1372 let idx_val =
1373 compile_expr(module, functions, extern_fns, builder, scope, index)?;
1374 compile_call(
1375 module,
1376 functions,
1377 extern_fns,
1378 builder,
1379 "sigil_array_set",
1380 &[arr_val, idx_val, val],
1381 )
1382 }
1383 _ => Err("Invalid assignment target".into()),
1384 }
1385 }
1386
1387 Expr::Index { expr: arr, index } => {
1388 let arr_val = compile_expr(module, functions, extern_fns, builder, scope, arr)?;
1389 let idx_val = compile_expr(module, functions, extern_fns, builder, scope, index)?;
1390 compile_call(
1391 module,
1392 functions,
1393 extern_fns,
1394 builder,
1395 "sigil_array_get",
1396 &[arr_val, idx_val],
1397 )
1398 }
1399
1400 Expr::Array(elements) => {
1401 let len = builder.ins().iconst(types::I64, elements.len() as i64);
1402 let arr = compile_call(
1403 module,
1404 functions,
1405 extern_fns,
1406 builder,
1407 "sigil_array_new",
1408 &[len],
1409 )?;
1410
1411 for (i, elem) in elements.iter().enumerate() {
1412 let val = compile_expr(module, functions, extern_fns, builder, scope, elem)?;
1413 let idx = builder.ins().iconst(types::I64, i as i64);
1414 compile_call(
1415 module,
1416 functions,
1417 extern_fns,
1418 builder,
1419 "sigil_array_set",
1420 &[arr, idx, val],
1421 )?;
1422 }
1423
1424 Ok(arr)
1425 }
1426
1427 Expr::Pipe { expr, operations } => {
1428 let mut result = compile_expr(module, functions, extern_fns, builder, scope, expr)?;
1430
1431 for op in operations {
1433 result = match op {
1434 PipeOp::First => compile_call(
1436 module,
1437 functions,
1438 extern_fns,
1439 builder,
1440 "sigil_array_first",
1441 &[result],
1442 )?,
1443 PipeOp::Last => compile_call(
1444 module,
1445 functions,
1446 extern_fns,
1447 builder,
1448 "sigil_array_last",
1449 &[result],
1450 )?,
1451 PipeOp::Middle => compile_call(
1452 module,
1453 functions,
1454 extern_fns,
1455 builder,
1456 "sigil_array_middle",
1457 &[result],
1458 )?,
1459 PipeOp::Choice => compile_call(
1460 module,
1461 functions,
1462 extern_fns,
1463 builder,
1464 "sigil_array_choice",
1465 &[result],
1466 )?,
1467 PipeOp::Next => compile_call(
1468 module,
1469 functions,
1470 extern_fns,
1471 builder,
1472 "sigil_array_next",
1473 &[result],
1474 )?,
1475 PipeOp::Nth(index_expr) => {
1476 let index = compile_expr(
1477 module, functions, extern_fns, builder, scope, index_expr,
1478 )?;
1479 compile_call(
1480 module,
1481 functions,
1482 extern_fns,
1483 builder,
1484 "sigil_array_nth",
1485 &[result, index],
1486 )?
1487 }
1488 PipeOp::Reduce(_) => {
1490 compile_call(
1492 module,
1493 functions,
1494 extern_fns,
1495 builder,
1496 "sigil_array_sum",
1497 &[result],
1498 )?
1499 }
1500 PipeOp::ReduceSum => compile_call(
1502 module,
1503 functions,
1504 extern_fns,
1505 builder,
1506 "sigil_array_sum",
1507 &[result],
1508 )?,
1509 PipeOp::ReduceProd => compile_call(
1511 module,
1512 functions,
1513 extern_fns,
1514 builder,
1515 "sigil_array_product",
1516 &[result],
1517 )?,
1518 PipeOp::ReduceMin => compile_call(
1520 module,
1521 functions,
1522 extern_fns,
1523 builder,
1524 "sigil_array_min",
1525 &[result],
1526 )?,
1527 PipeOp::ReduceMax => compile_call(
1529 module,
1530 functions,
1531 extern_fns,
1532 builder,
1533 "sigil_array_max",
1534 &[result],
1535 )?,
1536 PipeOp::ReduceConcat => compile_call(
1538 module,
1539 functions,
1540 extern_fns,
1541 builder,
1542 "sigil_array_concat",
1543 &[result],
1544 )?,
1545 PipeOp::ReduceAll => compile_call(
1547 module,
1548 functions,
1549 extern_fns,
1550 builder,
1551 "sigil_array_all",
1552 &[result],
1553 )?,
1554 PipeOp::ReduceAny => compile_call(
1556 module,
1557 functions,
1558 extern_fns,
1559 builder,
1560 "sigil_array_any",
1561 &[result],
1562 )?,
1563 PipeOp::Sort(_) => compile_call(
1565 module,
1566 functions,
1567 extern_fns,
1568 builder,
1569 "sigil_array_sort",
1570 &[result],
1571 )?,
1572 PipeOp::Transform(_) | PipeOp::Filter(_) => {
1574 result
1577 }
1578 PipeOp::Method {
1580 name,
1581 type_args: _,
1582 args,
1583 } => {
1584 let mut call_args = vec![result];
1586 for arg in args {
1587 call_args.push(compile_expr(
1588 module, functions, extern_fns, builder, scope, arg,
1589 )?);
1590 }
1591 compile_call(
1592 module, functions, extern_fns, builder, &name.name, &call_args,
1593 )?
1594 }
1595 PipeOp::Await => {
1596 result
1598 }
1599 PipeOp::Match(_) => {
1600 result
1603 }
1604 PipeOp::TryMap(_) => {
1605 result
1607 }
1608 PipeOp::Call(callee) => {
1609 let callee_val = compile_expr(
1612 module, functions, extern_fns, builder, scope, callee,
1613 )?;
1614 compile_call(
1616 module,
1617 functions,
1618 extern_fns,
1619 builder,
1620 "sigil_call",
1621 &[callee_val, result],
1622 )?
1623 }
1624 PipeOp::Named { prefix, body } => {
1625 if !prefix.is_empty() {
1627 let fn_name = &prefix[0].name;
1628 if let Some(body_expr) = body {
1629 let body_val = compile_expr(
1630 module, functions, extern_fns, builder, scope, body_expr,
1631 )?;
1632 compile_call(
1633 module,
1634 functions,
1635 extern_fns,
1636 builder,
1637 fn_name,
1638 &[result, body_val],
1639 )?
1640 } else {
1641 compile_call(
1642 module,
1643 functions,
1644 extern_fns,
1645 builder,
1646 fn_name,
1647 &[result],
1648 )?
1649 }
1650 } else {
1651 result
1652 }
1653 }
1654 PipeOp::Parallel(inner_op) => {
1656 match inner_op.as_ref() {
1659 PipeOp::Transform(_) => {
1660 compile_call(
1662 module,
1663 functions,
1664 extern_fns,
1665 builder,
1666 "sigil_parallel_map",
1667 &[result],
1668 )?
1669 }
1670 PipeOp::Filter(_) => {
1671 compile_call(
1673 module,
1674 functions,
1675 extern_fns,
1676 builder,
1677 "sigil_parallel_filter",
1678 &[result],
1679 )?
1680 }
1681 PipeOp::Reduce(_) => {
1682 compile_call(
1684 module,
1685 functions,
1686 extern_fns,
1687 builder,
1688 "sigil_parallel_reduce",
1689 &[result],
1690 )?
1691 }
1692 _ => result,
1694 }
1695 }
1696 PipeOp::Gpu(inner_op) => {
1698 match inner_op.as_ref() {
1701 PipeOp::Transform(_) => {
1702 compile_call(
1704 module,
1705 functions,
1706 extern_fns,
1707 builder,
1708 "sigil_gpu_map",
1709 &[result],
1710 )?
1711 }
1712 PipeOp::Filter(_) => {
1713 compile_call(
1715 module,
1716 functions,
1717 extern_fns,
1718 builder,
1719 "sigil_gpu_filter",
1720 &[result],
1721 )?
1722 }
1723 PipeOp::Reduce(_) => {
1724 compile_call(
1726 module,
1727 functions,
1728 extern_fns,
1729 builder,
1730 "sigil_gpu_reduce",
1731 &[result],
1732 )?
1733 }
1734 _ => result,
1735 }
1736 }
1737
1738 PipeOp::Send(data_expr) => {
1745 let data = compile_expr(
1746 module, functions, extern_fns, builder, scope, data_expr,
1747 )?;
1748 compile_call(
1749 module,
1750 functions,
1751 extern_fns,
1752 builder,
1753 "sigil_protocol_send",
1754 &[result, data],
1755 )?
1756 }
1757
1758 PipeOp::Recv => compile_call(
1760 module,
1761 functions,
1762 extern_fns,
1763 builder,
1764 "sigil_protocol_recv",
1765 &[result],
1766 )?,
1767
1768 PipeOp::Stream(handler_expr) => {
1770 let handler = compile_expr(
1771 module,
1772 functions,
1773 extern_fns,
1774 builder,
1775 scope,
1776 handler_expr,
1777 )?;
1778 compile_call(
1779 module,
1780 functions,
1781 extern_fns,
1782 builder,
1783 "sigil_protocol_stream",
1784 &[result, handler],
1785 )?
1786 }
1787
1788 PipeOp::Connect(config_expr) => {
1790 if let Some(config) = config_expr {
1791 let config_val = compile_expr(
1792 module, functions, extern_fns, builder, scope, config,
1793 )?;
1794 compile_call(
1795 module,
1796 functions,
1797 extern_fns,
1798 builder,
1799 "sigil_protocol_connect",
1800 &[result, config_val],
1801 )?
1802 } else {
1803 compile_call(
1804 module,
1805 functions,
1806 extern_fns,
1807 builder,
1808 "sigil_protocol_connect_default",
1809 &[result],
1810 )?
1811 }
1812 }
1813
1814 PipeOp::Close => compile_call(
1816 module,
1817 functions,
1818 extern_fns,
1819 builder,
1820 "sigil_protocol_close",
1821 &[result],
1822 )?,
1823
1824 PipeOp::Header { name, value } => {
1826 let name_val =
1827 compile_expr(module, functions, extern_fns, builder, scope, name)?;
1828 let value_val =
1829 compile_expr(module, functions, extern_fns, builder, scope, value)?;
1830 compile_call(
1831 module,
1832 functions,
1833 extern_fns,
1834 builder,
1835 "sigil_protocol_header",
1836 &[result, name_val, value_val],
1837 )?
1838 }
1839
1840 PipeOp::Body(data_expr) => {
1842 let data = compile_expr(
1843 module, functions, extern_fns, builder, scope, data_expr,
1844 )?;
1845 compile_call(
1846 module,
1847 functions,
1848 extern_fns,
1849 builder,
1850 "sigil_protocol_body",
1851 &[result, data],
1852 )?
1853 }
1854
1855 PipeOp::Timeout(ms_expr) => {
1857 let ms = compile_expr(
1858 module, functions, extern_fns, builder, scope, ms_expr,
1859 )?;
1860 compile_call(
1861 module,
1862 functions,
1863 extern_fns,
1864 builder,
1865 "sigil_protocol_timeout",
1866 &[result, ms],
1867 )?
1868 }
1869
1870 PipeOp::Retry { count, strategy } => {
1872 let count_val =
1873 compile_expr(module, functions, extern_fns, builder, scope, count)?;
1874 if let Some(strat) = strategy {
1875 let strat_val = compile_expr(
1876 module, functions, extern_fns, builder, scope, strat,
1877 )?;
1878 compile_call(
1879 module,
1880 functions,
1881 extern_fns,
1882 builder,
1883 "sigil_protocol_retry",
1884 &[result, count_val, strat_val],
1885 )?
1886 } else {
1887 compile_call(
1888 module,
1889 functions,
1890 extern_fns,
1891 builder,
1892 "sigil_protocol_retry_default",
1893 &[result, count_val],
1894 )?
1895 }
1896 }
1897
1898 PipeOp::Validate {
1900 predicate,
1901 target_evidence: _,
1902 } => {
1903 let pred_val = compile_expr(
1904 module, functions, extern_fns, builder, scope, predicate,
1905 )?;
1906 compile_call(
1907 module,
1908 functions,
1909 extern_fns,
1910 builder,
1911 "sigil_validate",
1912 &[result, pred_val],
1913 )?
1914 }
1915
1916 PipeOp::Assume {
1917 reason,
1918 target_evidence: _,
1919 } => {
1920 let reason_val = if let Some(r) = reason {
1921 compile_expr(module, functions, extern_fns, builder, scope, r)?
1922 } else {
1923 builder.ins().iconst(types::I64, 0)
1924 };
1925 compile_call(
1926 module,
1927 functions,
1928 extern_fns,
1929 builder,
1930 "sigil_assume",
1931 &[result, reason_val],
1932 )?
1933 }
1934
1935 PipeOp::AssertEvidence(_) => {
1936 result
1939 }
1940
1941 PipeOp::Also(func) => {
1943 let _ =
1945 compile_expr(module, functions, extern_fns, builder, scope, func)?;
1946 result
1947 }
1948
1949 PipeOp::Apply(func) => {
1950 let _ =
1952 compile_expr(module, functions, extern_fns, builder, scope, func)?;
1953 result
1954 }
1955
1956 PipeOp::TakeIf(pred) => {
1957 let pred_val =
1959 compile_expr(module, functions, extern_fns, builder, scope, pred)?;
1960 compile_call(
1961 module,
1962 functions,
1963 extern_fns,
1964 builder,
1965 "sigil_take_if",
1966 &[result, pred_val],
1967 )?
1968 }
1969
1970 PipeOp::TakeUnless(pred) => {
1971 let pred_val =
1973 compile_expr(module, functions, extern_fns, builder, scope, pred)?;
1974 compile_call(
1975 module,
1976 functions,
1977 extern_fns,
1978 builder,
1979 "sigil_take_unless",
1980 &[result, pred_val],
1981 )?
1982 }
1983
1984 PipeOp::Let(func) => {
1985 compile_expr(module, functions, extern_fns, builder, scope, func)?
1987 }
1988
1989 PipeOp::All(_)
1992 | PipeOp::Any(_)
1993 | PipeOp::Compose(_)
1994 | PipeOp::Zip(_)
1995 | PipeOp::Scan(_)
1996 | PipeOp::Diff
1997 | PipeOp::Gradient(_)
1998 | PipeOp::SortAsc
1999 | PipeOp::SortDesc
2000 | PipeOp::Reverse
2001 | PipeOp::Cycle(_)
2002 | PipeOp::Windows(_)
2003 | PipeOp::Chunks(_)
2004 | PipeOp::Flatten
2005 | PipeOp::Unique
2006 | PipeOp::Enumerate
2007 | PipeOp::Universal
2009 | PipeOp::Possibility
2010 | PipeOp::Necessity
2011 | PipeOp::PossibilityMethod { .. }
2012 | PipeOp::NecessityMethod { .. } => {
2013 result
2015 }
2016 };
2017 }
2018
2019 Ok(result)
2020 }
2021
2022 Expr::Unsafe(block) => {
2024 let mut inner_scope = scope.child();
2025 compile_block(
2026 module,
2027 functions,
2028 extern_fns,
2029 builder,
2030 &mut inner_scope,
2031 block,
2032 )
2033 }
2034
2035 Expr::Async { block, .. } => {
2037 let mut inner_scope = scope.child();
2038 compile_block(
2039 module,
2040 functions,
2041 extern_fns,
2042 builder,
2043 &mut inner_scope,
2044 block,
2045 )
2046 }
2047
2048 Expr::Deref(inner) => {
2050 let ptr = compile_expr(module, functions, extern_fns, builder, scope, inner)?;
2051 Ok(builder
2053 .ins()
2054 .load(types::I64, cranelift_codegen::ir::MemFlags::new(), ptr, 0))
2055 }
2056
2057 Expr::AddrOf { expr: inner, .. } => {
2059 compile_expr(module, functions, extern_fns, builder, scope, inner)
2060 }
2061
2062 Expr::Cast { expr: inner, ty } => {
2064 let val = compile_expr(module, functions, extern_fns, builder, scope, inner)?;
2065 let _ = ty; Ok(val)
2068 }
2069
2070 _ => Ok(builder.ins().iconst(types::I64, 0)),
2071 }
2072 }
2073
2074 fn compile_literal(
2076 builder: &mut FunctionBuilder,
2077 lit: &Literal,
2078 ) -> Result<cranelift_codegen::ir::Value, String> {
2079 match lit {
2080 Literal::Int { value, .. } => {
2081 let val: i64 = value.parse().map_err(|_| "Invalid integer")?;
2082 Ok(builder.ins().iconst(types::I64, val))
2083 }
2084 Literal::Float { value, .. } => {
2085 let val: f64 = value.parse().map_err(|_| "Invalid float")?;
2086 Ok(builder.ins().iconst(types::I64, val.to_bits() as i64))
2089 }
2090 Literal::Bool(b) => Ok(builder.ins().iconst(types::I64, if *b { 1 } else { 0 })),
2091 Literal::String(_) => Ok(builder.ins().iconst(types::I64, 0)),
2092 _ => Ok(builder.ins().iconst(types::I64, 0)),
2093 }
2094 }
2095
2096 fn compile_binary_op(
2098 builder: &mut FunctionBuilder,
2099 op: BinOp,
2100 lhs: cranelift_codegen::ir::Value,
2101 rhs: cranelift_codegen::ir::Value,
2102 ) -> Result<cranelift_codegen::ir::Value, String> {
2103 let result = match op {
2104 BinOp::Add => builder.ins().iadd(lhs, rhs),
2105 BinOp::Sub => builder.ins().isub(lhs, rhs),
2106 BinOp::Mul => builder.ins().imul(lhs, rhs),
2107 BinOp::Div => builder.ins().sdiv(lhs, rhs),
2108 BinOp::Rem => builder.ins().srem(lhs, rhs),
2109 BinOp::Pow => return Err("Power not supported".into()),
2110 BinOp::BitAnd => builder.ins().band(lhs, rhs),
2111 BinOp::BitOr => builder.ins().bor(lhs, rhs),
2112 BinOp::BitXor => builder.ins().bxor(lhs, rhs),
2113 BinOp::Shl => builder.ins().ishl(lhs, rhs),
2114 BinOp::Shr => builder.ins().sshr(lhs, rhs),
2115 BinOp::Eq => {
2116 let cmp = builder.ins().icmp(IntCC::Equal, lhs, rhs);
2117 builder.ins().uextend(types::I64, cmp)
2118 }
2119 BinOp::Ne => {
2120 let cmp = builder.ins().icmp(IntCC::NotEqual, lhs, rhs);
2121 builder.ins().uextend(types::I64, cmp)
2122 }
2123 BinOp::Lt => {
2124 let cmp = builder.ins().icmp(IntCC::SignedLessThan, lhs, rhs);
2125 builder.ins().uextend(types::I64, cmp)
2126 }
2127 BinOp::Le => {
2128 let cmp = builder.ins().icmp(IntCC::SignedLessThanOrEqual, lhs, rhs);
2129 builder.ins().uextend(types::I64, cmp)
2130 }
2131 BinOp::Gt => {
2132 let cmp = builder.ins().icmp(IntCC::SignedGreaterThan, lhs, rhs);
2133 builder.ins().uextend(types::I64, cmp)
2134 }
2135 BinOp::Ge => {
2136 let cmp = builder
2137 .ins()
2138 .icmp(IntCC::SignedGreaterThanOrEqual, lhs, rhs);
2139 builder.ins().uextend(types::I64, cmp)
2140 }
2141 BinOp::And => builder.ins().band(lhs, rhs),
2142 BinOp::Or => builder.ins().bor(lhs, rhs),
2143 BinOp::Concat => return Err("Concat not supported".into()),
2144 BinOp::MatMul => return Err("MatMul not supported in JIT (use runtime)".into()),
2145 BinOp::Hadamard => return Err("Hadamard not supported in JIT (use runtime)".into()),
2146 BinOp::TensorProd => return Err("TensorProd not supported in JIT (use runtime)".into()),
2147 BinOp::Convolve => return Err("Convolve not supported in JIT (use runtime)".into()),
2148 };
2149 Ok(result)
2150 }
2151
2152 fn compile_float_binary_op(
2154 builder: &mut FunctionBuilder,
2155 op: &BinOp,
2156 lhs: cranelift_codegen::ir::Value,
2157 rhs: cranelift_codegen::ir::Value,
2158 ) -> Result<cranelift_codegen::ir::Value, String> {
2159 use cranelift_codegen::ir::condcodes::FloatCC;
2160
2161 let lhs_f = builder
2163 .ins()
2164 .bitcast(types::F64, cranelift_codegen::ir::MemFlags::new(), lhs);
2165 let rhs_f = builder
2166 .ins()
2167 .bitcast(types::F64, cranelift_codegen::ir::MemFlags::new(), rhs);
2168
2169 let result_f = match op {
2170 BinOp::Add => builder.ins().fadd(lhs_f, rhs_f),
2171 BinOp::Sub => builder.ins().fsub(lhs_f, rhs_f),
2172 BinOp::Mul => builder.ins().fmul(lhs_f, rhs_f),
2173 BinOp::Div => builder.ins().fdiv(lhs_f, rhs_f),
2174 BinOp::Lt => {
2175 let cmp = builder.ins().fcmp(FloatCC::LessThan, lhs_f, rhs_f);
2176 return Ok(builder.ins().uextend(types::I64, cmp));
2177 }
2178 BinOp::Le => {
2179 let cmp = builder.ins().fcmp(FloatCC::LessThanOrEqual, lhs_f, rhs_f);
2180 return Ok(builder.ins().uextend(types::I64, cmp));
2181 }
2182 BinOp::Gt => {
2183 let cmp = builder.ins().fcmp(FloatCC::GreaterThan, lhs_f, rhs_f);
2184 return Ok(builder.ins().uextend(types::I64, cmp));
2185 }
2186 BinOp::Ge => {
2187 let cmp = builder
2188 .ins()
2189 .fcmp(FloatCC::GreaterThanOrEqual, lhs_f, rhs_f);
2190 return Ok(builder.ins().uextend(types::I64, cmp));
2191 }
2192 BinOp::Eq => {
2193 let cmp = builder.ins().fcmp(FloatCC::Equal, lhs_f, rhs_f);
2194 return Ok(builder.ins().uextend(types::I64, cmp));
2195 }
2196 BinOp::Ne => {
2197 let cmp = builder.ins().fcmp(FloatCC::NotEqual, lhs_f, rhs_f);
2198 return Ok(builder.ins().uextend(types::I64, cmp));
2199 }
2200 _ => return Err(format!("Float operation {:?} not supported", op)),
2201 };
2202
2203 Ok(builder
2205 .ins()
2206 .bitcast(types::I64, cranelift_codegen::ir::MemFlags::new(), result_f))
2207 }
2208
2209 fn compile_unary_op(
2211 builder: &mut FunctionBuilder,
2212 op: UnaryOp,
2213 val: cranelift_codegen::ir::Value,
2214 ) -> Result<cranelift_codegen::ir::Value, String> {
2215 let result = match op {
2216 UnaryOp::Neg => builder.ins().ineg(val),
2217 UnaryOp::Not => {
2218 let zero = builder.ins().iconst(types::I64, 0);
2219 let cmp = builder.ins().icmp(IntCC::Equal, val, zero);
2220 builder.ins().uextend(types::I64, cmp)
2221 }
2222 UnaryOp::Deref | UnaryOp::Ref | UnaryOp::RefMut => val,
2223 };
2224 Ok(result)
2225 }
2226
2227 fn compile_call(
2229 module: &mut JITModule,
2230 functions: &HashMap<String, FuncId>,
2231 extern_fns: &HashMap<String, ExternFnSig>,
2232 builder: &mut FunctionBuilder,
2233 name: &str,
2234 args: &[cranelift_codegen::ir::Value],
2235 ) -> Result<cranelift_codegen::ir::Value, String> {
2236 let builtin_name = match name {
2237 "sqrt" => Some("sigil_sqrt"),
2238 "sin" => Some("sigil_sin"),
2239 "cos" => Some("sigil_cos"),
2240 "pow" => Some("sigil_pow"),
2241 "exp" => Some("sigil_exp"),
2242 "ln" => Some("sigil_ln"),
2243 "floor" => Some("sigil_floor"),
2244 "ceil" => Some("sigil_ceil"),
2245 "abs" => Some("sigil_abs"),
2246 "print" => Some("sigil_print"),
2247 "now" => Some("sigil_now"),
2248 "ackermann" => Some("sigil_ackermann"),
2250 "tak" => Some("sigil_tak"),
2251 n if n.starts_with("sigil_") => Some(n),
2252 _ => None,
2253 };
2254
2255 if let Some(builtin) = builtin_name {
2256 let mut sig = module.make_signature();
2257
2258 match builtin {
2259 "sigil_sqrt" | "sigil_sin" | "sigil_cos" | "sigil_exp" | "sigil_ln"
2260 | "sigil_floor" | "sigil_ceil" | "sigil_abs" => {
2261 sig.params.push(AbiParam::new(types::F64));
2262 sig.returns.push(AbiParam::new(types::F64));
2263 }
2264 "sigil_pow" => {
2265 sig.params.push(AbiParam::new(types::F64));
2266 sig.params.push(AbiParam::new(types::F64));
2267 sig.returns.push(AbiParam::new(types::F64));
2268 }
2269 "sigil_print_int" => {
2270 sig.params.push(AbiParam::new(types::I64));
2271 sig.returns.push(AbiParam::new(types::I64));
2272 }
2273 "sigil_now" => {
2274 sig.returns.push(AbiParam::new(types::I64));
2275 }
2276 "sigil_array_new" => {
2277 sig.params.push(AbiParam::new(types::I64));
2278 sig.returns.push(AbiParam::new(types::I64));
2279 }
2280 "sigil_array_get" | "sigil_array_set" => {
2281 sig.params.push(AbiParam::new(types::I64));
2282 sig.params.push(AbiParam::new(types::I64));
2283 if builtin == "sigil_array_set" {
2284 sig.params.push(AbiParam::new(types::I64));
2285 }
2286 sig.returns.push(AbiParam::new(types::I64));
2287 }
2288 "sigil_array_len" => {
2289 sig.params.push(AbiParam::new(types::I64));
2290 sig.returns.push(AbiParam::new(types::I64));
2291 }
2292 "sigil_array_first"
2294 | "sigil_array_last"
2295 | "sigil_array_middle"
2296 | "sigil_array_choice"
2297 | "sigil_array_next"
2298 | "sigil_array_sum"
2299 | "sigil_array_product" => {
2300 sig.params.push(AbiParam::new(types::I64));
2301 sig.returns.push(AbiParam::new(types::I64));
2302 }
2303 "sigil_array_sort" => {
2305 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2308 "sigil_parallel_map" | "sigil_parallel_filter" => {
2310 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2313 "sigil_parallel_reduce" => {
2314 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2317 "sigil_gpu_map" | "sigil_gpu_filter" => {
2319 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2322 "sigil_gpu_reduce" => {
2323 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2326 "sigil_array_nth" => {
2328 sig.params.push(AbiParam::new(types::I64)); sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64));
2331 }
2332 _ => {
2333 for _ in args {
2334 sig.params.push(AbiParam::new(types::I64));
2335 }
2336 sig.returns.push(AbiParam::new(types::I64));
2337 }
2338 }
2339
2340 let callee = module
2341 .declare_function(builtin, Linkage::Import, &sig)
2342 .map_err(|e| e.to_string())?;
2343
2344 let local_callee = module.declare_func_in_func(callee, builder.func);
2345
2346 let call_args: Vec<_> = if matches!(
2347 builtin,
2348 "sigil_sqrt"
2349 | "sigil_sin"
2350 | "sigil_cos"
2351 | "sigil_exp"
2352 | "sigil_ln"
2353 | "sigil_floor"
2354 | "sigil_ceil"
2355 | "sigil_abs"
2356 | "sigil_pow"
2357 ) {
2358 args.iter()
2359 .map(|&v| {
2360 if builder.func.dfg.value_type(v) == types::F64 {
2361 v
2362 } else {
2363 builder.ins().fcvt_from_sint(types::F64, v)
2364 }
2365 })
2366 .collect()
2367 } else {
2368 args.to_vec()
2369 };
2370
2371 let call = builder.ins().call(local_callee, &call_args);
2372 Ok(builder.inst_results(call)[0])
2373 } else if let Some(&func_id) = functions.get(name) {
2374 let local_callee = module.declare_func_in_func(func_id, builder.func);
2376 let call = builder.ins().call(local_callee, args);
2377 Ok(builder.inst_results(call)[0])
2378 } else if let Some(extern_fn) = extern_fns.get(name) {
2379 let local_callee = module.declare_func_in_func(extern_fn.func_id, builder.func);
2381
2382 let mut call_args = Vec::new();
2384 for (i, &arg) in args.iter().enumerate() {
2385 let arg_type = builder.func.dfg.value_type(arg);
2386 let expected_type = extern_fn.params.get(i).copied().unwrap_or(types::I64);
2387
2388 let converted = if arg_type == expected_type {
2389 arg
2390 } else if arg_type == types::I64 && expected_type == types::I32 {
2391 builder.ins().ireduce(types::I32, arg)
2392 } else if arg_type == types::I32 && expected_type == types::I64 {
2393 builder.ins().sextend(types::I64, arg)
2394 } else if arg_type == types::I64 && expected_type == types::F64 {
2395 builder.ins().fcvt_from_sint(types::F64, arg)
2396 } else if arg_type == types::F64 && expected_type == types::I64 {
2397 builder.ins().fcvt_to_sint(types::I64, arg)
2398 } else {
2399 arg };
2401 call_args.push(converted);
2402 }
2403
2404 let call = builder.ins().call(local_callee, &call_args);
2405
2406 if extern_fn.returns.is_some() {
2408 let result = builder.inst_results(call)[0];
2409 let result_type = builder.func.dfg.value_type(result);
2410 if result_type == types::I32
2412 || result_type == types::I16
2413 || result_type == types::I8
2414 {
2415 Ok(builder.ins().sextend(types::I64, result))
2416 } else {
2417 Ok(result)
2418 }
2419 } else {
2420 Ok(builder.ins().iconst(types::I64, 0))
2422 }
2423 } else {
2424 Err(format!("Unknown function: {}", name))
2425 }
2426 }
2427
2428 fn compile_if_tracked(
2430 module: &mut JITModule,
2431 functions: &HashMap<String, FuncId>,
2432 extern_fns: &HashMap<String, ExternFnSig>,
2433 builder: &mut FunctionBuilder,
2434 scope: &mut CompileScope,
2435 condition: &Expr,
2436 then_branch: &ast::Block,
2437 else_branch: Option<&Expr>,
2438 ) -> Result<(cranelift_codegen::ir::Value, bool), String> {
2439 let cond_bool =
2441 compile_condition(module, functions, extern_fns, builder, scope, condition)?;
2442
2443 let then_block = builder.create_block();
2444 let else_block = builder.create_block();
2445 let merge_block = builder.create_block();
2446
2447 builder.append_block_param(merge_block, types::I64);
2448
2449 builder
2451 .ins()
2452 .brif(cond_bool, then_block, &[], else_block, &[]);
2453
2454 builder.switch_to_block(then_block);
2456 builder.seal_block(then_block);
2457 let mut then_scope = scope.child();
2458 let (then_val, then_returns) = compile_block_tracked(
2459 module,
2460 functions,
2461 extern_fns,
2462 builder,
2463 &mut then_scope,
2464 then_branch,
2465 )?;
2466 if !then_returns {
2468 builder.ins().jump(merge_block, &[then_val]);
2469 }
2470
2471 builder.switch_to_block(else_block);
2473 builder.seal_block(else_block);
2474 let (else_val, else_returns) = if let Some(else_expr) = else_branch {
2475 match else_expr {
2476 Expr::Block(block) => {
2477 let mut else_scope = scope.child();
2478 compile_block_tracked(
2479 module,
2480 functions,
2481 extern_fns,
2482 builder,
2483 &mut else_scope,
2484 block,
2485 )?
2486 }
2487 Expr::If {
2488 condition,
2489 then_branch,
2490 else_branch,
2491 } => compile_if_tracked(
2492 module,
2493 functions,
2494 extern_fns,
2495 builder,
2496 scope,
2497 condition,
2498 then_branch,
2499 else_branch.as_deref(),
2500 )?,
2501 _ => {
2502 let val =
2503 compile_expr(module, functions, extern_fns, builder, scope, else_expr)?;
2504 (val, false)
2505 }
2506 }
2507 } else {
2508 (builder.ins().iconst(types::I64, 0), false)
2509 };
2510 if !else_returns {
2512 builder.ins().jump(merge_block, &[else_val]);
2513 }
2514
2515 let both_return = then_returns && else_returns;
2518
2519 builder.switch_to_block(merge_block);
2520 builder.seal_block(merge_block);
2521
2522 if both_return {
2523 let dummy = builder.ins().iconst(types::I64, 0);
2526 Ok((dummy, true))
2527 } else {
2528 Ok((builder.block_params(merge_block)[0], false))
2529 }
2530 }
2531
2532 fn compile_if(
2534 module: &mut JITModule,
2535 functions: &HashMap<String, FuncId>,
2536 extern_fns: &HashMap<String, ExternFnSig>,
2537 builder: &mut FunctionBuilder,
2538 scope: &mut CompileScope,
2539 condition: &Expr,
2540 then_branch: &ast::Block,
2541 else_branch: Option<&Expr>,
2542 ) -> Result<cranelift_codegen::ir::Value, String> {
2543 compile_if_tracked(
2544 module,
2545 functions,
2546 extern_fns,
2547 builder,
2548 scope,
2549 condition,
2550 then_branch,
2551 else_branch,
2552 )
2553 .map(|(v, _)| v)
2554 }
2555
2556 fn compile_while(
2558 module: &mut JITModule,
2559 functions: &HashMap<String, FuncId>,
2560 extern_fns: &HashMap<String, ExternFnSig>,
2561 builder: &mut FunctionBuilder,
2562 scope: &mut CompileScope,
2563 condition: &Expr,
2564 body: &ast::Block,
2565 ) -> Result<cranelift_codegen::ir::Value, String> {
2566 let header_block = builder.create_block();
2567 let body_block = builder.create_block();
2568 let exit_block = builder.create_block();
2569
2570 builder.ins().jump(header_block, &[]);
2571
2572 builder.switch_to_block(header_block);
2573 let cond_bool =
2575 compile_condition(module, functions, extern_fns, builder, scope, condition)?;
2576 builder
2578 .ins()
2579 .brif(cond_bool, body_block, &[], exit_block, &[]);
2580
2581 builder.switch_to_block(body_block);
2582 builder.seal_block(body_block);
2583 let mut body_scope = scope.child();
2584 compile_block(
2585 module,
2586 functions,
2587 extern_fns,
2588 builder,
2589 &mut body_scope,
2590 body,
2591 )?;
2592 builder.ins().jump(header_block, &[]);
2593
2594 builder.seal_block(header_block);
2595
2596 builder.switch_to_block(exit_block);
2597 builder.seal_block(exit_block);
2598
2599 Ok(builder.ins().iconst(types::I64, 0))
2600 }
2601
2602 #[inline]
2610 fn is_float_pattern(v: i64) -> bool {
2611 let exp = (v >> 52) & 0x7FF;
2612 exp > 0 && exp < 0x7FF && v != 0
2615 }
2616
2617 #[no_mangle]
2618 pub extern "C" fn sigil_add(a: i64, b: i64) -> i64 {
2619 if is_float_pattern(a) || is_float_pattern(b) {
2620 let fa = f64::from_bits(a as u64);
2621 let fb = f64::from_bits(b as u64);
2622 (fa + fb).to_bits() as i64
2623 } else {
2624 a.wrapping_add(b)
2625 }
2626 }
2627
2628 #[no_mangle]
2629 pub extern "C" fn sigil_sub(a: i64, b: i64) -> i64 {
2630 if is_float_pattern(a) || is_float_pattern(b) {
2631 let fa = f64::from_bits(a as u64);
2632 let fb = f64::from_bits(b as u64);
2633 (fa - fb).to_bits() as i64
2634 } else {
2635 a.wrapping_sub(b)
2636 }
2637 }
2638
2639 #[no_mangle]
2640 pub extern "C" fn sigil_mul(a: i64, b: i64) -> i64 {
2641 if is_float_pattern(a) || is_float_pattern(b) {
2642 let fa = f64::from_bits(a as u64);
2643 let fb = f64::from_bits(b as u64);
2644 (fa * fb).to_bits() as i64
2645 } else {
2646 a.wrapping_mul(b)
2647 }
2648 }
2649
2650 #[no_mangle]
2651 pub extern "C" fn sigil_div(a: i64, b: i64) -> i64 {
2652 if is_float_pattern(a) || is_float_pattern(b) {
2653 let fa = f64::from_bits(a as u64);
2654 let fb = f64::from_bits(b as u64);
2655 (fa / fb).to_bits() as i64
2656 } else if b != 0 {
2657 a / b
2658 } else {
2659 0 }
2661 }
2662
2663 #[no_mangle]
2664 pub extern "C" fn sigil_lt(a: i64, b: i64) -> i64 {
2665 if is_float_pattern(a) || is_float_pattern(b) {
2666 let fa = f64::from_bits(a as u64);
2667 let fb = f64::from_bits(b as u64);
2668 if fa < fb {
2669 1
2670 } else {
2671 0
2672 }
2673 } else {
2674 if a < b {
2675 1
2676 } else {
2677 0
2678 }
2679 }
2680 }
2681
2682 #[no_mangle]
2683 pub extern "C" fn sigil_le(a: i64, b: i64) -> i64 {
2684 if is_float_pattern(a) || is_float_pattern(b) {
2685 let fa = f64::from_bits(a as u64);
2686 let fb = f64::from_bits(b as u64);
2687 if fa <= fb {
2688 1
2689 } else {
2690 0
2691 }
2692 } else {
2693 if a <= b {
2694 1
2695 } else {
2696 0
2697 }
2698 }
2699 }
2700
2701 #[no_mangle]
2702 pub extern "C" fn sigil_gt(a: i64, b: i64) -> i64 {
2703 if is_float_pattern(a) || is_float_pattern(b) {
2704 let fa = f64::from_bits(a as u64);
2705 let fb = f64::from_bits(b as u64);
2706 if fa > fb {
2707 1
2708 } else {
2709 0
2710 }
2711 } else {
2712 if a > b {
2713 1
2714 } else {
2715 0
2716 }
2717 }
2718 }
2719
2720 #[no_mangle]
2721 pub extern "C" fn sigil_ge(a: i64, b: i64) -> i64 {
2722 if is_float_pattern(a) || is_float_pattern(b) {
2723 let fa = f64::from_bits(a as u64);
2724 let fb = f64::from_bits(b as u64);
2725 if fa >= fb {
2726 1
2727 } else {
2728 0
2729 }
2730 } else {
2731 if a >= b {
2732 1
2733 } else {
2734 0
2735 }
2736 }
2737 }
2738
2739 #[no_mangle]
2741 pub extern "C" fn sigil_print(v: i64) -> i64 {
2742 if is_float_pattern(v) {
2743 println!("{}", f64::from_bits(v as u64));
2744 } else {
2745 println!("{}", v);
2746 }
2747 0
2748 }
2749
2750 #[repr(C, align(32))]
2762 struct SimdVec4 {
2763 data: [f64; 4],
2764 }
2765
2766 impl SimdVec4 {
2767 #[inline(always)]
2768 fn new(x: f64, y: f64, z: f64, w: f64) -> Box<Self> {
2769 Box::new(SimdVec4 { data: [x, y, z, w] })
2770 }
2771
2772 #[inline(always)]
2773 fn splat(v: f64) -> Box<Self> {
2774 Box::new(SimdVec4 { data: [v, v, v, v] })
2775 }
2776 }
2777
2778 #[no_mangle]
2780 pub extern "C" fn sigil_simd_new(x: i64, y: i64, z: i64, w: i64) -> i64 {
2781 let v = SimdVec4::new(
2782 f64::from_bits(x as u64),
2783 f64::from_bits(y as u64),
2784 f64::from_bits(z as u64),
2785 f64::from_bits(w as u64),
2786 );
2787 Box::into_raw(v) as i64
2788 }
2789
2790 #[no_mangle]
2792 pub extern "C" fn sigil_simd_splat(v: i64) -> i64 {
2793 let f = f64::from_bits(v as u64);
2794 let v = SimdVec4::splat(f);
2795 Box::into_raw(v) as i64
2796 }
2797
2798 #[no_mangle]
2803 #[inline(never)]
2804 pub extern "C" fn sigil_simd_add(a: i64, b: i64) -> i64 {
2805 unsafe {
2806 let a = &*(a as *const SimdVec4);
2807 let b = &*(b as *const SimdVec4);
2808 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2810 r.data[0] = a.data[0] + b.data[0];
2811 r.data[1] = a.data[1] + b.data[1];
2812 r.data[2] = a.data[2] + b.data[2];
2813 r.data[3] = a.data[3] + b.data[3];
2814 Box::into_raw(r) as i64
2815 }
2816 }
2817
2818 #[no_mangle]
2820 #[inline(never)]
2821 pub extern "C" fn sigil_simd_sub(a: i64, b: i64) -> i64 {
2822 unsafe {
2823 let a = &*(a as *const SimdVec4);
2824 let b = &*(b as *const SimdVec4);
2825 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2826 r.data[0] = a.data[0] - b.data[0];
2827 r.data[1] = a.data[1] - b.data[1];
2828 r.data[2] = a.data[2] - b.data[2];
2829 r.data[3] = a.data[3] - b.data[3];
2830 Box::into_raw(r) as i64
2831 }
2832 }
2833
2834 #[no_mangle]
2836 #[inline(never)]
2837 pub extern "C" fn sigil_simd_mul(a: i64, b: i64) -> i64 {
2838 unsafe {
2839 let a = &*(a as *const SimdVec4);
2840 let b = &*(b as *const SimdVec4);
2841 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2842 r.data[0] = a.data[0] * b.data[0];
2843 r.data[1] = a.data[1] * b.data[1];
2844 r.data[2] = a.data[2] * b.data[2];
2845 r.data[3] = a.data[3] * b.data[3];
2846 Box::into_raw(r) as i64
2847 }
2848 }
2849
2850 #[no_mangle]
2852 #[inline(never)]
2853 pub extern "C" fn sigil_simd_div(a: i64, b: i64) -> i64 {
2854 unsafe {
2855 let a = &*(a as *const SimdVec4);
2856 let b = &*(b as *const SimdVec4);
2857 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2858 r.data[0] = a.data[0] / b.data[0];
2859 r.data[1] = a.data[1] / b.data[1];
2860 r.data[2] = a.data[2] / b.data[2];
2861 r.data[3] = a.data[3] / b.data[3];
2862 Box::into_raw(r) as i64
2863 }
2864 }
2865
2866 #[no_mangle]
2868 #[inline(never)]
2869 pub extern "C" fn sigil_simd_dot(a: i64, b: i64) -> i64 {
2870 unsafe {
2871 let a = &*(a as *const SimdVec4);
2872 let b = &*(b as *const SimdVec4);
2873 let r = a.data[0].mul_add(
2875 b.data[0],
2876 a.data[1].mul_add(
2877 b.data[1],
2878 a.data[2].mul_add(b.data[2], a.data[3] * b.data[3]),
2879 ),
2880 );
2881 r.to_bits() as i64
2882 }
2883 }
2884
2885 #[no_mangle]
2887 #[inline(never)]
2888 pub extern "C" fn sigil_simd_hadd(a: i64) -> i64 {
2889 unsafe {
2890 let a = &*(a as *const SimdVec4);
2891 let sum01 = a.data[0] + a.data[1];
2893 let sum23 = a.data[2] + a.data[3];
2894 let r = sum01 + sum23;
2895 r.to_bits() as i64
2896 }
2897 }
2898
2899 #[no_mangle]
2901 #[inline(never)]
2902 pub extern "C" fn sigil_simd_length_sq(a: i64) -> i64 {
2903 unsafe {
2904 let a = &*(a as *const SimdVec4);
2905 let r = a.data[0].mul_add(
2906 a.data[0],
2907 a.data[1].mul_add(
2908 a.data[1],
2909 a.data[2].mul_add(a.data[2], a.data[3] * a.data[3]),
2910 ),
2911 );
2912 r.to_bits() as i64
2913 }
2914 }
2915
2916 #[no_mangle]
2918 #[inline(never)]
2919 pub extern "C" fn sigil_simd_length(a: i64) -> i64 {
2920 unsafe {
2921 let a = &*(a as *const SimdVec4);
2922 let len_sq = a.data[0].mul_add(
2923 a.data[0],
2924 a.data[1].mul_add(
2925 a.data[1],
2926 a.data[2].mul_add(a.data[2], a.data[3] * a.data[3]),
2927 ),
2928 );
2929 let r = len_sq.sqrt();
2930 r.to_bits() as i64
2931 }
2932 }
2933
2934 #[no_mangle]
2936 #[inline(never)]
2937 pub extern "C" fn sigil_simd_normalize(a: i64) -> i64 {
2938 unsafe {
2939 let a = &*(a as *const SimdVec4);
2940 let len_sq = a.data[0].mul_add(
2941 a.data[0],
2942 a.data[1].mul_add(
2943 a.data[1],
2944 a.data[2].mul_add(a.data[2], a.data[3] * a.data[3]),
2945 ),
2946 );
2947 let inv = if len_sq > 1e-20 {
2948 1.0 / len_sq.sqrt()
2949 } else {
2950 0.0
2951 };
2952 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2953 r.data[0] = a.data[0] * inv;
2954 r.data[1] = a.data[1] * inv;
2955 r.data[2] = a.data[2] * inv;
2956 r.data[3] = a.data[3] * inv;
2957 Box::into_raw(r) as i64
2958 }
2959 }
2960
2961 #[no_mangle]
2963 #[inline(never)]
2964 pub extern "C" fn sigil_simd_cross(a: i64, b: i64) -> i64 {
2965 unsafe {
2966 let a = &*(a as *const SimdVec4);
2967 let b = &*(b as *const SimdVec4);
2968 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2970 r.data[0] = a.data[1].mul_add(b.data[2], -(a.data[2] * b.data[1]));
2971 r.data[1] = a.data[2].mul_add(b.data[0], -(a.data[0] * b.data[2]));
2972 r.data[2] = a.data[0].mul_add(b.data[1], -(a.data[1] * b.data[0]));
2973 r.data[3] = 0.0;
2974 Box::into_raw(r) as i64
2975 }
2976 }
2977
2978 #[no_mangle]
2980 #[inline(never)]
2981 pub extern "C" fn sigil_simd_min(a: i64, b: i64) -> i64 {
2982 unsafe {
2983 let a = &*(a as *const SimdVec4);
2984 let b = &*(b as *const SimdVec4);
2985 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2986 r.data[0] = a.data[0].min(b.data[0]);
2987 r.data[1] = a.data[1].min(b.data[1]);
2988 r.data[2] = a.data[2].min(b.data[2]);
2989 r.data[3] = a.data[3].min(b.data[3]);
2990 Box::into_raw(r) as i64
2991 }
2992 }
2993
2994 #[no_mangle]
2996 #[inline(never)]
2997 pub extern "C" fn sigil_simd_max(a: i64, b: i64) -> i64 {
2998 unsafe {
2999 let a = &*(a as *const SimdVec4);
3000 let b = &*(b as *const SimdVec4);
3001 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
3002 r.data[0] = a.data[0].max(b.data[0]);
3003 r.data[1] = a.data[1].max(b.data[1]);
3004 r.data[2] = a.data[2].max(b.data[2]);
3005 r.data[3] = a.data[3].max(b.data[3]);
3006 Box::into_raw(r) as i64
3007 }
3008 }
3009
3010 #[no_mangle]
3012 pub extern "C" fn sigil_simd_extract(v: i64, idx: i64) -> i64 {
3013 unsafe {
3014 let v = &*(v as *const SimdVec4);
3015 let r = v.data[(idx as usize) & 3];
3016 r.to_bits() as i64
3017 }
3018 }
3019
3020 #[no_mangle]
3022 pub extern "C" fn sigil_simd_free(v: i64) {
3023 if v != 0 {
3024 unsafe {
3025 let _ = Box::from_raw(v as *mut SimdVec4);
3026 }
3027 }
3028 }
3029
3030 #[no_mangle]
3031 pub extern "C" fn sigil_sqrt(x: f64) -> f64 {
3032 x.sqrt()
3033 }
3034
3035 #[no_mangle]
3036 pub extern "C" fn sigil_sin(x: f64) -> f64 {
3037 x.sin()
3038 }
3039
3040 #[no_mangle]
3041 pub extern "C" fn sigil_cos(x: f64) -> f64 {
3042 x.cos()
3043 }
3044
3045 #[no_mangle]
3046 pub extern "C" fn sigil_pow(base: f64, exp: f64) -> f64 {
3047 base.powf(exp)
3048 }
3049
3050 #[no_mangle]
3051 pub extern "C" fn sigil_exp(x: f64) -> f64 {
3052 x.exp()
3053 }
3054
3055 #[no_mangle]
3056 pub extern "C" fn sigil_ln(x: f64) -> f64 {
3057 x.ln()
3058 }
3059
3060 #[no_mangle]
3061 pub extern "C" fn sigil_floor(x: f64) -> f64 {
3062 x.floor()
3063 }
3064
3065 #[no_mangle]
3066 pub extern "C" fn sigil_ceil(x: f64) -> f64 {
3067 x.ceil()
3068 }
3069
3070 #[no_mangle]
3071 pub extern "C" fn sigil_abs(x: f64) -> f64 {
3072 x.abs()
3073 }
3074
3075 #[no_mangle]
3076 pub extern "C" fn sigil_print_int(x: i64) -> i64 {
3077 println!("{}", x);
3078 0
3079 }
3080
3081 #[no_mangle]
3082 pub extern "C" fn sigil_print_float(x: f64) -> i64 {
3083 println!("{}", x);
3084 0
3085 }
3086
3087 #[no_mangle]
3088 pub extern "C" fn sigil_print_str(ptr: *const u8, len: usize) -> i64 {
3089 unsafe {
3090 let slice = std::slice::from_raw_parts(ptr, len);
3091 if let Ok(s) = std::str::from_utf8(slice) {
3092 println!("{}", s);
3093 }
3094 }
3095 0
3096 }
3097
3098 #[no_mangle]
3099 pub extern "C" fn sigil_now() -> i64 {
3100 use std::time::{SystemTime, UNIX_EPOCH};
3101 SystemTime::now()
3102 .duration_since(UNIX_EPOCH)
3103 .map(|d| d.as_millis() as i64)
3104 .unwrap_or(0)
3105 }
3106
3107 #[repr(C)]
3109 struct SigilArray {
3110 data: *mut i64,
3111 len: usize,
3112 cap: usize,
3113 }
3114
3115 #[no_mangle]
3116 pub extern "C" fn sigil_array_new(capacity: i64) -> i64 {
3117 let cap = capacity.max(8) as usize;
3118 let layout = std::alloc::Layout::array::<i64>(cap).unwrap();
3119 let data = unsafe { std::alloc::alloc(layout) as *mut i64 };
3120
3121 let arr = Box::new(SigilArray { data, len: 0, cap });
3122 Box::into_raw(arr) as i64
3123 }
3124
3125 #[no_mangle]
3126 pub extern "C" fn sigil_array_push(arr_ptr: i64, value: i64) -> i64 {
3127 unsafe {
3128 let arr = &mut *(arr_ptr as *mut SigilArray);
3129 if arr.len >= arr.cap {
3130 let new_cap = arr.cap * 2;
3132 let old_layout = std::alloc::Layout::array::<i64>(arr.cap).unwrap();
3133 let new_layout = std::alloc::Layout::array::<i64>(new_cap).unwrap();
3134 arr.data = std::alloc::realloc(arr.data as *mut u8, old_layout, new_layout.size())
3135 as *mut i64;
3136 arr.cap = new_cap;
3137 }
3138 *arr.data.add(arr.len) = value;
3139 arr.len += 1;
3140 }
3141 0
3142 }
3143
3144 #[no_mangle]
3145 pub extern "C" fn sigil_array_get(arr_ptr: i64, index: i64) -> i64 {
3146 unsafe {
3147 let arr = &*(arr_ptr as *const SigilArray);
3148 let idx = index as usize;
3149 if idx < arr.len {
3150 *arr.data.add(idx)
3151 } else {
3152 0 }
3154 }
3155 }
3156
3157 #[no_mangle]
3158 pub extern "C" fn sigil_array_set(arr_ptr: i64, index: i64, value: i64) -> i64 {
3159 unsafe {
3160 let arr = &mut *(arr_ptr as *mut SigilArray);
3161 let idx = index as usize;
3162 while arr.len <= idx {
3164 sigil_array_push(arr_ptr, 0);
3165 }
3166 *arr.data.add(idx) = value;
3167 }
3168 value
3169 }
3170
3171 #[no_mangle]
3172 pub extern "C" fn sigil_array_len(arr_ptr: i64) -> i64 {
3173 unsafe {
3174 let arr = &*(arr_ptr as *const SigilArray);
3175 arr.len as i64
3176 }
3177 }
3178
3179 #[no_mangle]
3186 pub extern "C" fn sigil_array_sum(arr_ptr: i64) -> i64 {
3187 unsafe {
3188 let arr = &*(arr_ptr as *const SigilArray);
3189 let data = std::slice::from_raw_parts(arr.data, arr.len);
3190
3191 let chunks = data.chunks_exact(4);
3193 let remainder = chunks.remainder();
3194
3195 let mut sum0: i64 = 0;
3197 let mut sum1: i64 = 0;
3198 let mut sum2: i64 = 0;
3199 let mut sum3: i64 = 0;
3200
3201 for chunk in chunks {
3202 sum0 = sum0.wrapping_add(chunk[0]);
3203 sum1 = sum1.wrapping_add(chunk[1]);
3204 sum2 = sum2.wrapping_add(chunk[2]);
3205 sum3 = sum3.wrapping_add(chunk[3]);
3206 }
3207
3208 let mut sum = sum0
3210 .wrapping_add(sum1)
3211 .wrapping_add(sum2)
3212 .wrapping_add(sum3);
3213 for &v in remainder {
3214 sum = sum.wrapping_add(v);
3215 }
3216
3217 sum
3218 }
3219 }
3220
3221 #[no_mangle]
3223 pub extern "C" fn sigil_array_scale(arr_ptr: i64, scalar: i64) -> i64 {
3224 unsafe {
3225 let arr = &mut *(arr_ptr as *mut SigilArray);
3226 let data = std::slice::from_raw_parts_mut(arr.data, arr.len);
3227
3228 for chunk in data.chunks_exact_mut(4) {
3230 chunk[0] = chunk[0].wrapping_mul(scalar);
3231 chunk[1] = chunk[1].wrapping_mul(scalar);
3232 chunk[2] = chunk[2].wrapping_mul(scalar);
3233 chunk[3] = chunk[3].wrapping_mul(scalar);
3234 }
3235
3236 let remainder_start = (data.len() / 4) * 4;
3238 for v in &mut data[remainder_start..] {
3239 *v = v.wrapping_mul(scalar);
3240 }
3241
3242 arr_ptr
3243 }
3244 }
3245
3246 #[no_mangle]
3248 pub extern "C" fn sigil_array_offset(arr_ptr: i64, offset: i64) -> i64 {
3249 unsafe {
3250 let arr = &mut *(arr_ptr as *mut SigilArray);
3251 let data = std::slice::from_raw_parts_mut(arr.data, arr.len);
3252
3253 for chunk in data.chunks_exact_mut(4) {
3255 chunk[0] = chunk[0].wrapping_add(offset);
3256 chunk[1] = chunk[1].wrapping_add(offset);
3257 chunk[2] = chunk[2].wrapping_add(offset);
3258 chunk[3] = chunk[3].wrapping_add(offset);
3259 }
3260
3261 let remainder_start = (data.len() / 4) * 4;
3262 for v in &mut data[remainder_start..] {
3263 *v = v.wrapping_add(offset);
3264 }
3265
3266 arr_ptr
3267 }
3268 }
3269
3270 #[no_mangle]
3272 pub extern "C" fn sigil_array_dot(a_ptr: i64, b_ptr: i64) -> i64 {
3273 unsafe {
3274 let a_arr = &*(a_ptr as *const SigilArray);
3275 let b_arr = &*(b_ptr as *const SigilArray);
3276
3277 let len = a_arr.len.min(b_arr.len);
3278 let a_data = std::slice::from_raw_parts(a_arr.data, len);
3279 let b_data = std::slice::from_raw_parts(b_arr.data, len);
3280
3281 let mut sum0: i64 = 0;
3283 let mut sum1: i64 = 0;
3284 let mut sum2: i64 = 0;
3285 let mut sum3: i64 = 0;
3286
3287 let chunks = len / 4;
3288 for i in 0..chunks {
3289 let base = i * 4;
3290 sum0 = sum0.wrapping_add(a_data[base].wrapping_mul(b_data[base]));
3291 sum1 = sum1.wrapping_add(a_data[base + 1].wrapping_mul(b_data[base + 1]));
3292 sum2 = sum2.wrapping_add(a_data[base + 2].wrapping_mul(b_data[base + 2]));
3293 sum3 = sum3.wrapping_add(a_data[base + 3].wrapping_mul(b_data[base + 3]));
3294 }
3295
3296 let mut sum = sum0
3298 .wrapping_add(sum1)
3299 .wrapping_add(sum2)
3300 .wrapping_add(sum3);
3301 for i in (chunks * 4)..len {
3302 sum = sum.wrapping_add(a_data[i].wrapping_mul(b_data[i]));
3303 }
3304
3305 sum
3306 }
3307 }
3308
3309 #[no_mangle]
3311 pub extern "C" fn sigil_array_add(a_ptr: i64, b_ptr: i64) -> i64 {
3312 unsafe {
3313 let a_arr = &*(a_ptr as *const SigilArray);
3314 let b_arr = &*(b_ptr as *const SigilArray);
3315
3316 let len = a_arr.len.min(b_arr.len);
3317 let a_data = std::slice::from_raw_parts(a_arr.data, len);
3318 let b_data = std::slice::from_raw_parts(b_arr.data, len);
3319
3320 let result = sigil_array_new(len as i64);
3322 let r_arr = &mut *(result as *mut SigilArray);
3323 r_arr.len = len;
3324 let r_data = std::slice::from_raw_parts_mut(r_arr.data, len);
3325
3326 for i in 0..(len / 4) {
3328 let base = i * 4;
3329 r_data[base] = a_data[base].wrapping_add(b_data[base]);
3330 r_data[base + 1] = a_data[base + 1].wrapping_add(b_data[base + 1]);
3331 r_data[base + 2] = a_data[base + 2].wrapping_add(b_data[base + 2]);
3332 r_data[base + 3] = a_data[base + 3].wrapping_add(b_data[base + 3]);
3333 }
3334
3335 for i in ((len / 4) * 4)..len {
3337 r_data[i] = a_data[i].wrapping_add(b_data[i]);
3338 }
3339
3340 result
3341 }
3342 }
3343
3344 #[no_mangle]
3346 pub extern "C" fn sigil_array_mul(a_ptr: i64, b_ptr: i64) -> i64 {
3347 unsafe {
3348 let a_arr = &*(a_ptr as *const SigilArray);
3349 let b_arr = &*(b_ptr as *const SigilArray);
3350
3351 let len = a_arr.len.min(b_arr.len);
3352 let a_data = std::slice::from_raw_parts(a_arr.data, len);
3353 let b_data = std::slice::from_raw_parts(b_arr.data, len);
3354
3355 let result = sigil_array_new(len as i64);
3357 let r_arr = &mut *(result as *mut SigilArray);
3358 r_arr.len = len;
3359 let r_data = std::slice::from_raw_parts_mut(r_arr.data, len);
3360
3361 for i in 0..(len / 4) {
3363 let base = i * 4;
3364 r_data[base] = a_data[base].wrapping_mul(b_data[base]);
3365 r_data[base + 1] = a_data[base + 1].wrapping_mul(b_data[base + 1]);
3366 r_data[base + 2] = a_data[base + 2].wrapping_mul(b_data[base + 2]);
3367 r_data[base + 3] = a_data[base + 3].wrapping_mul(b_data[base + 3]);
3368 }
3369
3370 for i in ((len / 4) * 4)..len {
3372 r_data[i] = a_data[i].wrapping_mul(b_data[i]);
3373 }
3374
3375 result
3376 }
3377 }
3378
3379 #[no_mangle]
3381 pub extern "C" fn sigil_array_min(arr_ptr: i64) -> i64 {
3382 unsafe {
3383 let arr = &*(arr_ptr as *const SigilArray);
3384 if arr.len == 0 {
3385 return 0;
3386 }
3387
3388 let data = std::slice::from_raw_parts(arr.data, arr.len);
3389
3390 let mut min0 = i64::MAX;
3392 let mut min1 = i64::MAX;
3393 let mut min2 = i64::MAX;
3394 let mut min3 = i64::MAX;
3395
3396 for chunk in data.chunks_exact(4) {
3397 min0 = min0.min(chunk[0]);
3398 min1 = min1.min(chunk[1]);
3399 min2 = min2.min(chunk[2]);
3400 min3 = min3.min(chunk[3]);
3401 }
3402
3403 let mut min_val = min0.min(min1).min(min2).min(min3);
3404
3405 let remainder_start = (data.len() / 4) * 4;
3407 for &v in &data[remainder_start..] {
3408 min_val = min_val.min(v);
3409 }
3410
3411 min_val
3412 }
3413 }
3414
3415 #[no_mangle]
3417 pub extern "C" fn sigil_array_max(arr_ptr: i64) -> i64 {
3418 unsafe {
3419 let arr = &*(arr_ptr as *const SigilArray);
3420 if arr.len == 0 {
3421 return 0;
3422 }
3423
3424 let data = std::slice::from_raw_parts(arr.data, arr.len);
3425
3426 let mut max0 = i64::MIN;
3428 let mut max1 = i64::MIN;
3429 let mut max2 = i64::MIN;
3430 let mut max3 = i64::MIN;
3431
3432 for chunk in data.chunks_exact(4) {
3433 max0 = max0.max(chunk[0]);
3434 max1 = max1.max(chunk[1]);
3435 max2 = max2.max(chunk[2]);
3436 max3 = max3.max(chunk[3]);
3437 }
3438
3439 let mut max_val = max0.max(max1).max(max2).max(max3);
3440
3441 let remainder_start = (data.len() / 4) * 4;
3443 for &v in &data[remainder_start..] {
3444 max_val = max_val.max(v);
3445 }
3446
3447 max_val
3448 }
3449 }
3450
3451 #[no_mangle]
3453 pub extern "C" fn sigil_array_fill(arr_ptr: i64, value: i64, count: i64) -> i64 {
3454 unsafe {
3455 let arr = &mut *(arr_ptr as *mut SigilArray);
3456 let n = count as usize;
3457
3458 while arr.len < n {
3460 sigil_array_push(arr_ptr, 0);
3461 }
3462
3463 let data = std::slice::from_raw_parts_mut(arr.data, n);
3464
3465 for chunk in data.chunks_exact_mut(4) {
3467 chunk[0] = value;
3468 chunk[1] = value;
3469 chunk[2] = value;
3470 chunk[3] = value;
3471 }
3472
3473 let remainder_start = (n / 4) * 4;
3475 for v in &mut data[remainder_start..] {
3476 *v = value;
3477 }
3478
3479 arr_ptr
3480 }
3481 }
3482
3483 #[no_mangle]
3490 pub extern "C" fn sigil_array_first(arr_ptr: i64) -> i64 {
3491 unsafe {
3492 let arr = &*(arr_ptr as *const SigilArray);
3493 if arr.len == 0 {
3494 return 0; }
3496 *arr.data
3497 }
3498 }
3499
3500 #[no_mangle]
3502 pub extern "C" fn sigil_array_last(arr_ptr: i64) -> i64 {
3503 unsafe {
3504 let arr = &*(arr_ptr as *const SigilArray);
3505 if arr.len == 0 {
3506 return 0; }
3508 *arr.data.add(arr.len - 1)
3509 }
3510 }
3511
3512 #[no_mangle]
3514 pub extern "C" fn sigil_array_middle(arr_ptr: i64) -> i64 {
3515 unsafe {
3516 let arr = &*(arr_ptr as *const SigilArray);
3517 if arr.len == 0 {
3518 return 0; }
3520 let mid = arr.len / 2;
3521 *arr.data.add(mid)
3522 }
3523 }
3524
3525 #[no_mangle]
3527 pub extern "C" fn sigil_array_choice(arr_ptr: i64) -> i64 {
3528 unsafe {
3529 let arr = &*(arr_ptr as *const SigilArray);
3530 if arr.len == 0 {
3531 return 0; }
3533 use std::time::{SystemTime, UNIX_EPOCH};
3535 let seed = SystemTime::now()
3536 .duration_since(UNIX_EPOCH)
3537 .map(|d| d.as_nanos() as u64)
3538 .unwrap_or(12345);
3539 let idx =
3540 ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % arr.len;
3541 *arr.data.add(idx)
3542 }
3543 }
3544
3545 #[no_mangle]
3547 pub extern "C" fn sigil_array_nth(arr_ptr: i64, index: i64) -> i64 {
3548 sigil_array_get(arr_ptr, index)
3549 }
3550
3551 #[no_mangle]
3553 pub extern "C" fn sigil_array_next(arr_ptr: i64) -> i64 {
3554 sigil_array_first(arr_ptr)
3557 }
3558
3559 #[no_mangle]
3561 pub extern "C" fn sigil_array_product(arr_ptr: i64) -> i64 {
3562 unsafe {
3563 let arr = &*(arr_ptr as *const SigilArray);
3564 if arr.len == 0 {
3565 return 1; }
3567 let mut product: i64 = 1;
3568 for i in 0..arr.len {
3569 product = product.wrapping_mul(*arr.data.add(i));
3570 }
3571 product
3572 }
3573 }
3574
3575 #[no_mangle]
3577 pub extern "C" fn sigil_array_sort(arr_ptr: i64) -> i64 {
3578 unsafe {
3579 let arr = &*(arr_ptr as *const SigilArray);
3580 if arr.len == 0 {
3581 return sigil_array_new(0);
3582 }
3583
3584 let mut elements: Vec<i64> = Vec::with_capacity(arr.len);
3586 for i in 0..arr.len {
3587 elements.push(*arr.data.add(i));
3588 }
3589
3590 elements.sort();
3592
3593 let new_arr = sigil_array_new(arr.len as i64);
3595 for elem in elements {
3596 sigil_array_push(new_arr, elem);
3597 }
3598 new_arr
3599 }
3600 }
3601
3602 #[no_mangle]
3616 pub extern "C" fn sigil_parallel_map(arr_ptr: i64) -> i64 {
3617 arr_ptr
3620 }
3621
3622 #[no_mangle]
3625 pub extern "C" fn sigil_parallel_filter(arr_ptr: i64) -> i64 {
3626 arr_ptr
3632 }
3633
3634 #[no_mangle]
3637 pub extern "C" fn sigil_parallel_reduce(arr_ptr: i64) -> i64 {
3638 unsafe {
3641 let arr = &*(arr_ptr as *const SigilArray);
3642 if arr.len == 0 {
3643 return 0;
3644 }
3645
3646 let mut sum: i64 = 0;
3649 for i in 0..arr.len {
3650 sum += *arr.data.add(i);
3651 }
3652 sum
3653 }
3654 }
3655
3656 #[no_mangle]
3672 pub extern "C" fn sigil_gpu_map(arr_ptr: i64) -> i64 {
3673 arr_ptr
3680 }
3681
3682 #[no_mangle]
3685 pub extern "C" fn sigil_gpu_filter(arr_ptr: i64) -> i64 {
3686 arr_ptr
3689 }
3690
3691 #[no_mangle]
3694 pub extern "C" fn sigil_gpu_reduce(arr_ptr: i64) -> i64 {
3695 sigil_parallel_reduce(arr_ptr)
3697 }
3698
3699 #[repr(C)]
3706 struct MemoEntry {
3707 key1: i64, key2: i64, value: i64, occupied: bool, }
3712
3713 #[repr(C)]
3715 struct MemoCache {
3716 entries: *mut MemoEntry,
3717 capacity: usize,
3718 mask: usize, }
3720
3721 #[no_mangle]
3723 pub extern "C" fn sigil_memo_new(capacity: i64) -> i64 {
3724 let cap = (capacity as usize).next_power_of_two().max(1024);
3725 let layout = std::alloc::Layout::array::<MemoEntry>(cap).unwrap();
3726 let entries = unsafe {
3727 let ptr = std::alloc::alloc_zeroed(layout) as *mut MemoEntry;
3728 ptr
3729 };
3730
3731 let cache = Box::new(MemoCache {
3732 entries,
3733 capacity: cap,
3734 mask: cap - 1,
3735 });
3736 Box::into_raw(cache) as i64
3737 }
3738
3739 #[inline]
3741 fn memo_hash_1(key: i64) -> usize {
3742 let mut h = key as u64;
3744 h = h.wrapping_mul(0x517cc1b727220a95);
3745 h ^= h >> 32;
3746 h as usize
3747 }
3748
3749 #[inline]
3751 fn memo_hash_2(key1: i64, key2: i64) -> usize {
3752 let mut h = key1 as u64;
3753 h = h.wrapping_mul(0x517cc1b727220a95);
3754 h ^= key2 as u64;
3755 h = h.wrapping_mul(0x517cc1b727220a95);
3756 h ^= h >> 32;
3757 h as usize
3758 }
3759
3760 #[no_mangle]
3768 pub extern "C" fn sigil_ackermann(m: i64, n: i64) -> i64 {
3769 let mut stack: Vec<i64> = Vec::with_capacity(1024);
3771 stack.push(m);
3772 let mut n = n;
3773
3774 while let Some(m) = stack.pop() {
3775 if m == 0 {
3776 n = n + 1;
3777 } else if n == 0 {
3778 stack.push(m - 1);
3779 n = 1;
3780 } else {
3781 stack.push(m - 1);
3782 stack.push(m);
3783 n = n - 1;
3784 }
3785 }
3786 n
3787 }
3788
3789 #[no_mangle]
3791 pub extern "C" fn sigil_tak(x: i64, y: i64, z: i64) -> i64 {
3792 #[derive(Clone, Copy)]
3794 enum TakCont {
3795 Eval { x: i64, y: i64, z: i64 },
3796 Cont1 { y: i64, z: i64, x: i64 }, Cont2 { z: i64, x: i64, y: i64, r1: i64 }, Cont3 { r1: i64, r2: i64 }, }
3800
3801 let mut stack: Vec<TakCont> = Vec::with_capacity(256);
3802 stack.push(TakCont::Eval { x, y, z });
3803 let mut result: i64 = 0;
3804
3805 while let Some(cont) = stack.pop() {
3806 match cont {
3807 TakCont::Eval { x, y, z } => {
3808 if y >= x {
3809 result = z;
3810 } else {
3811 stack.push(TakCont::Cont1 { y, z, x });
3813 stack.push(TakCont::Eval { x: x - 1, y, z });
3814 }
3815 }
3816 TakCont::Cont1 { y, z, x } => {
3817 let r1 = result;
3818 stack.push(TakCont::Cont2 { z, x, y, r1 });
3819 stack.push(TakCont::Eval {
3820 x: y - 1,
3821 y: z,
3822 z: x,
3823 });
3824 }
3825 TakCont::Cont2 { z, x, y, r1 } => {
3826 let r2 = result;
3827 stack.push(TakCont::Cont3 { r1, r2 });
3828 stack.push(TakCont::Eval {
3829 x: z - 1,
3830 y: x,
3831 z: y,
3832 });
3833 }
3834 TakCont::Cont3 { r1, r2 } => {
3835 let r3 = result;
3836 stack.push(TakCont::Eval {
3838 x: r1,
3839 y: r2,
3840 z: r3,
3841 });
3842 }
3843 }
3844 }
3845 result
3846 }
3847
3848 const MEMO_NOT_FOUND: i64 = -9223372036854775807;
3851
3852 #[no_mangle]
3855 pub extern "C" fn sigil_memo_get_1(cache_ptr: i64, key: i64) -> i64 {
3856 unsafe {
3857 let cache = &*(cache_ptr as *const MemoCache);
3858 let mut idx = memo_hash_1(key) & cache.mask;
3859
3860 for _ in 0..32 {
3862 let entry = &*cache.entries.add(idx);
3863 if !entry.occupied {
3864 return MEMO_NOT_FOUND;
3865 }
3866 if entry.key1 == key {
3867 return entry.value;
3868 }
3869 idx = (idx + 1) & cache.mask;
3870 }
3871 MEMO_NOT_FOUND
3872 }
3873 }
3874
3875 #[no_mangle]
3877 pub extern "C" fn sigil_memo_set_1(cache_ptr: i64, key: i64, value: i64) {
3878 unsafe {
3879 let cache = &*(cache_ptr as *const MemoCache);
3880 let mut idx = memo_hash_1(key) & cache.mask;
3881
3882 for _ in 0..32 {
3884 let entry = &mut *cache.entries.add(idx);
3885 if !entry.occupied || entry.key1 == key {
3886 entry.key1 = key;
3887 entry.value = value;
3888 entry.occupied = true;
3889 return;
3890 }
3891 idx = (idx + 1) & cache.mask;
3892 }
3893 let entry = &mut *cache.entries.add(memo_hash_1(key) & cache.mask);
3895 entry.key1 = key;
3896 entry.value = value;
3897 entry.occupied = true;
3898 }
3899 }
3900
3901 #[no_mangle]
3903 pub extern "C" fn sigil_memo_get_2(cache_ptr: i64, key1: i64, key2: i64) -> i64 {
3904 unsafe {
3905 let cache = &*(cache_ptr as *const MemoCache);
3906 let mut idx = memo_hash_2(key1, key2) & cache.mask;
3907
3908 for _ in 0..32 {
3909 let entry = &*cache.entries.add(idx);
3910 if !entry.occupied {
3911 return MEMO_NOT_FOUND;
3912 }
3913 if entry.key1 == key1 && entry.key2 == key2 {
3914 return entry.value;
3915 }
3916 idx = (idx + 1) & cache.mask;
3917 }
3918 MEMO_NOT_FOUND
3919 }
3920 }
3921
3922 #[no_mangle]
3924 pub extern "C" fn sigil_memo_set_2(cache_ptr: i64, key1: i64, key2: i64, value: i64) {
3925 unsafe {
3926 let cache = &*(cache_ptr as *const MemoCache);
3927 let mut idx = memo_hash_2(key1, key2) & cache.mask;
3928
3929 for _ in 0..32 {
3930 let entry = &mut *cache.entries.add(idx);
3931 if !entry.occupied || (entry.key1 == key1 && entry.key2 == key2) {
3932 entry.key1 = key1;
3933 entry.key2 = key2;
3934 entry.value = value;
3935 entry.occupied = true;
3936 return;
3937 }
3938 idx = (idx + 1) & cache.mask;
3939 }
3940 let entry = &mut *cache.entries.add(memo_hash_2(key1, key2) & cache.mask);
3941 entry.key1 = key1;
3942 entry.key2 = key2;
3943 entry.value = value;
3944 entry.occupied = true;
3945 }
3946 }
3947
3948 #[no_mangle]
3950 pub extern "C" fn sigil_memo_free(cache_ptr: i64) {
3951 if cache_ptr != 0 {
3952 unsafe {
3953 let cache = Box::from_raw(cache_ptr as *mut MemoCache);
3954 let layout = std::alloc::Layout::array::<MemoEntry>(cache.capacity).unwrap();
3955 std::alloc::dealloc(cache.entries as *mut u8, layout);
3956 }
3957 }
3958 }
3959
3960 #[cfg(test)]
3965 mod tests {
3966 use super::*;
3967 use crate::parser::Parser;
3968
3969 #[test]
3970 fn test_extern_block_parsing_and_declaration() {
3971 let source = r#"
3972 extern "C" {
3973 fn abs(x: c_int) -> c_int;
3974 fn strlen(s: *const c_char) -> usize;
3975 }
3976
3977 fn main() -> i64 {
3978 42
3979 }
3980 "#;
3981
3982 let mut compiler = JitCompiler::new().unwrap();
3983 let result = compiler.compile(source);
3984 assert!(
3985 result.is_ok(),
3986 "Failed to compile FFI declarations: {:?}",
3987 result
3988 );
3989
3990 assert!(
3992 compiler.extern_functions.contains_key("abs"),
3993 "abs not declared"
3994 );
3995 assert!(
3996 compiler.extern_functions.contains_key("strlen"),
3997 "strlen not declared"
3998 );
3999
4000 let abs_sig = compiler.extern_functions.get("abs").unwrap();
4002 assert_eq!(abs_sig.params.len(), 1);
4003 assert_eq!(abs_sig.params[0], types::I32); assert_eq!(abs_sig.returns, Some(types::I32));
4005
4006 let strlen_sig = compiler.extern_functions.get("strlen").unwrap();
4008 assert_eq!(strlen_sig.params.len(), 1);
4009 assert_eq!(strlen_sig.params[0], types::I64); assert_eq!(strlen_sig.returns, Some(types::I64)); }
4012
4013 #[test]
4014 fn test_extern_variadic_function() {
4015 let source = r#"
4016 extern "C" {
4017 fn printf(fmt: *const c_char, ...) -> c_int;
4018 }
4019
4020 fn main() -> i64 {
4021 0
4022 }
4023 "#;
4024
4025 let mut compiler = JitCompiler::new().unwrap();
4026 let result = compiler.compile(source);
4027 assert!(
4028 result.is_ok(),
4029 "Failed to compile variadic FFI: {:?}",
4030 result
4031 );
4032
4033 let printf_sig = compiler.extern_functions.get("printf").unwrap();
4034 assert!(printf_sig.variadic, "printf should be variadic");
4035 }
4036
4037 #[test]
4038 fn test_extern_c_abi_only() {
4039 let source = r#"
4040 extern "Rust" {
4041 fn some_func(x: i32) -> i32;
4042 }
4043
4044 fn main() -> i64 {
4045 0
4046 }
4047 "#;
4048
4049 let mut compiler = JitCompiler::new().unwrap();
4050 let result = compiler.compile(source);
4051 assert!(result.is_err(), "Should reject non-C ABI");
4052 assert!(result.unwrap_err().contains("Unsupported ABI"));
4053 }
4054
4055 #[test]
4056 fn test_c_type_mapping() {
4057 let test_cases = vec![
4059 ("c_char", types::I8),
4060 ("c_int", types::I32),
4061 ("c_long", types::I64),
4062 ("c_float", types::F32),
4063 ("c_double", types::F64),
4064 ("size_t", types::I64),
4065 ("i32", types::I32),
4066 ("f64", types::F64),
4067 ];
4068
4069 for (type_name, expected_cl_type) in test_cases {
4070 let source = format!(
4071 r#"
4072 extern "C" {{
4073 fn test_func(x: {}) -> {};
4074 }}
4075
4076 fn main() -> i64 {{ 0 }}
4077 "#,
4078 type_name, type_name
4079 );
4080
4081 let mut compiler = JitCompiler::new().unwrap();
4082 let result = compiler.compile(&source);
4083 assert!(
4084 result.is_ok(),
4085 "Failed for type {}: {:?}",
4086 type_name,
4087 result
4088 );
4089
4090 let sig = compiler.extern_functions.get("test_func").unwrap();
4091 assert_eq!(
4092 sig.params[0], expected_cl_type,
4093 "Wrong param type for {}",
4094 type_name
4095 );
4096 assert_eq!(
4097 sig.returns,
4098 Some(expected_cl_type),
4099 "Wrong return type for {}",
4100 type_name
4101 );
4102 }
4103 }
4104 }
4105}
4106
4107#[cfg(feature = "jit")]
4109pub use jit::JitCompiler;