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 { pattern, init, else_branch, .. } => {
1050 let val = compile_expr(module, functions, extern_fns, builder, scope, init)?;
1053 let ty = infer_type(init, scope);
1054
1055 if let ast::Pattern::Ident { name, .. } = pattern {
1056 let var = Variable::from_u32(scope.next_var() as u32);
1057 builder.declare_var(var, types::I64);
1058 builder.def_var(var, val);
1059 scope.define_typed(&name.name, var, ty);
1060 }
1061
1062 let _ = else_branch;
1066
1067 Ok((val, false))
1068 }
1069 ast::Stmt::Expr(expr) | ast::Stmt::Semi(expr) => {
1070 compile_expr_tracked(module, functions, extern_fns, builder, scope, expr)
1071 }
1072 ast::Stmt::Item(_) => Ok((builder.ins().iconst(types::I64, 0), false)),
1073 }
1074 }
1075
1076 #[allow(dead_code)]
1078 fn compile_stmt(
1079 module: &mut JITModule,
1080 functions: &HashMap<String, FuncId>,
1081 extern_fns: &HashMap<String, ExternFnSig>,
1082 builder: &mut FunctionBuilder,
1083 scope: &mut CompileScope,
1084 stmt: &ast::Stmt,
1085 ) -> Result<cranelift_codegen::ir::Value, String> {
1086 compile_stmt_tracked(module, functions, extern_fns, builder, scope, stmt).map(|(v, _)| v)
1087 }
1088
1089 fn compile_expr_tracked(
1091 module: &mut JITModule,
1092 functions: &HashMap<String, FuncId>,
1093 extern_fns: &HashMap<String, ExternFnSig>,
1094 builder: &mut FunctionBuilder,
1095 scope: &mut CompileScope,
1096 expr: &Expr,
1097 ) -> Result<(cranelift_codegen::ir::Value, bool), String> {
1098 match expr {
1099 Expr::Return(value) => {
1100 let ret_val = if let Some(v) = value {
1112 compile_expr(module, functions, extern_fns, builder, scope, v)?
1113 } else {
1114 builder.ins().iconst(types::I64, 0)
1115 };
1116 builder.ins().return_(&[ret_val]);
1117 Ok((ret_val, true)) }
1119 Expr::If {
1120 condition,
1121 then_branch,
1122 else_branch,
1123 } => {
1124 compile_if_tracked(
1126 module,
1127 functions,
1128 extern_fns,
1129 builder,
1130 scope,
1131 condition,
1132 then_branch,
1133 else_branch.as_deref(),
1134 )
1135 }
1136 Expr::Block(block) => {
1137 let mut inner_scope = scope.child();
1138 compile_block_tracked(
1139 module,
1140 functions,
1141 extern_fns,
1142 builder,
1143 &mut inner_scope,
1144 block,
1145 )
1146 }
1147 _ => {
1148 let val = compile_expr(module, functions, extern_fns, builder, scope, expr)?;
1150 Ok((val, false))
1151 }
1152 }
1153 }
1154
1155 fn compile_expr(
1157 module: &mut JITModule,
1158 functions: &HashMap<String, FuncId>,
1159 extern_fns: &HashMap<String, ExternFnSig>,
1160 builder: &mut FunctionBuilder,
1161 scope: &mut CompileScope,
1162 expr: &Expr,
1163 ) -> Result<cranelift_codegen::ir::Value, String> {
1164 if let Some(val) = try_const_fold(expr) {
1166 return Ok(builder.ins().iconst(types::I64, val));
1167 }
1168
1169 match expr {
1170 Expr::Literal(lit) => compile_literal(builder, lit),
1171
1172 Expr::Path(path) => {
1173 let name = path
1174 .segments
1175 .last()
1176 .map(|s| s.ident.name.clone())
1177 .unwrap_or_default();
1178 if let Some(var) = scope.lookup(&name) {
1179 Ok(builder.use_var(var))
1180 } else {
1181 Err(format!("Undefined variable: {}", name))
1182 }
1183 }
1184
1185 Expr::Binary { op, left, right } => {
1186 let left_ty = infer_type(left, scope);
1188 let right_ty = infer_type(right, scope);
1189
1190 let lhs = compile_expr(module, functions, extern_fns, builder, scope, left)?;
1191 let rhs = compile_expr(module, functions, extern_fns, builder, scope, right)?;
1192
1193 if left_ty == ValueType::Int && right_ty == ValueType::Int {
1196 return compile_binary_op(builder, op.clone(), lhs, rhs);
1198 }
1199
1200 if left_ty == ValueType::Float && right_ty == ValueType::Float {
1202 return compile_float_binary_op(builder, op, lhs, rhs);
1203 }
1204
1205 match op {
1208 BinOp::Add => compile_call(
1209 module,
1210 functions,
1211 extern_fns,
1212 builder,
1213 "sigil_add",
1214 &[lhs, rhs],
1215 ),
1216 BinOp::Sub => compile_call(
1217 module,
1218 functions,
1219 extern_fns,
1220 builder,
1221 "sigil_sub",
1222 &[lhs, rhs],
1223 ),
1224 BinOp::Mul => compile_call(
1225 module,
1226 functions,
1227 extern_fns,
1228 builder,
1229 "sigil_mul",
1230 &[lhs, rhs],
1231 ),
1232 BinOp::Div => compile_call(
1233 module,
1234 functions,
1235 extern_fns,
1236 builder,
1237 "sigil_div",
1238 &[lhs, rhs],
1239 ),
1240 BinOp::Lt => compile_call(
1241 module,
1242 functions,
1243 extern_fns,
1244 builder,
1245 "sigil_lt",
1246 &[lhs, rhs],
1247 ),
1248 BinOp::Le => compile_call(
1249 module,
1250 functions,
1251 extern_fns,
1252 builder,
1253 "sigil_le",
1254 &[lhs, rhs],
1255 ),
1256 BinOp::Gt => compile_call(
1257 module,
1258 functions,
1259 extern_fns,
1260 builder,
1261 "sigil_gt",
1262 &[lhs, rhs],
1263 ),
1264 BinOp::Ge => compile_call(
1265 module,
1266 functions,
1267 extern_fns,
1268 builder,
1269 "sigil_ge",
1270 &[lhs, rhs],
1271 ),
1272 _ => compile_binary_op(builder, op.clone(), lhs, rhs),
1273 }
1274 }
1275
1276 Expr::Unary { op, expr: inner } => {
1277 let val = compile_expr(module, functions, extern_fns, builder, scope, inner)?;
1278 compile_unary_op(builder, *op, val)
1279 }
1280
1281 Expr::Call { func, args } => {
1282 let func_name = match func.as_ref() {
1283 Expr::Path(path) => path
1284 .segments
1285 .last()
1286 .map(|s| s.ident.name.clone())
1287 .unwrap_or_default(),
1288 _ => return Err("Only direct function calls supported".into()),
1289 };
1290
1291 let mut arg_vals = Vec::new();
1292 for arg in args {
1293 arg_vals.push(compile_expr(
1294 module, functions, extern_fns, builder, scope, arg,
1295 )?);
1296 }
1297
1298 compile_call(
1299 module, functions, extern_fns, builder, &func_name, &arg_vals,
1300 )
1301 }
1302
1303 Expr::If {
1304 condition,
1305 then_branch,
1306 else_branch,
1307 } => compile_if(
1308 module,
1309 functions,
1310 extern_fns,
1311 builder,
1312 scope,
1313 condition,
1314 then_branch,
1315 else_branch.as_deref(),
1316 ),
1317
1318 Expr::While { condition, body, .. } => compile_while(
1319 module, functions, extern_fns, builder, scope, condition, body,
1320 ),
1321
1322 Expr::Block(block) => {
1323 let mut inner_scope = scope.child();
1324 compile_block(
1325 module,
1326 functions,
1327 extern_fns,
1328 builder,
1329 &mut inner_scope,
1330 block,
1331 )
1332 }
1333
1334 Expr::Return(value) => {
1335 let ret_val = if let Some(v) = value {
1338 compile_expr(module, functions, extern_fns, builder, scope, v)?
1339 } else {
1340 builder.ins().iconst(types::I64, 0)
1341 };
1342 builder.ins().return_(&[ret_val]);
1343 Ok(ret_val)
1344 }
1345
1346 Expr::Assign { target, value } => {
1347 let val = compile_expr(module, functions, extern_fns, builder, scope, value)?;
1348 match target.as_ref() {
1349 Expr::Path(path) => {
1350 let name = path
1351 .segments
1352 .last()
1353 .map(|s| s.ident.name.clone())
1354 .unwrap_or_default();
1355 if let Some(var) = scope.lookup(&name) {
1356 builder.def_var(var, val);
1357 Ok(val)
1358 } else {
1359 Err(format!("Undefined variable: {}", name))
1360 }
1361 }
1362 Expr::Index { expr: arr, index } => {
1363 let arr_val =
1364 compile_expr(module, functions, extern_fns, builder, scope, arr)?;
1365 let idx_val =
1366 compile_expr(module, functions, extern_fns, builder, scope, index)?;
1367 compile_call(
1368 module,
1369 functions,
1370 extern_fns,
1371 builder,
1372 "sigil_array_set",
1373 &[arr_val, idx_val, val],
1374 )
1375 }
1376 _ => Err("Invalid assignment target".into()),
1377 }
1378 }
1379
1380 Expr::Index { expr: arr, index } => {
1381 let arr_val = compile_expr(module, functions, extern_fns, builder, scope, arr)?;
1382 let idx_val = compile_expr(module, functions, extern_fns, builder, scope, index)?;
1383 compile_call(
1384 module,
1385 functions,
1386 extern_fns,
1387 builder,
1388 "sigil_array_get",
1389 &[arr_val, idx_val],
1390 )
1391 }
1392
1393 Expr::Array(elements) => {
1394 let len = builder.ins().iconst(types::I64, elements.len() as i64);
1395 let arr = compile_call(
1396 module,
1397 functions,
1398 extern_fns,
1399 builder,
1400 "sigil_array_new",
1401 &[len],
1402 )?;
1403
1404 for (i, elem) in elements.iter().enumerate() {
1405 let val = compile_expr(module, functions, extern_fns, builder, scope, elem)?;
1406 let idx = builder.ins().iconst(types::I64, i as i64);
1407 compile_call(
1408 module,
1409 functions,
1410 extern_fns,
1411 builder,
1412 "sigil_array_set",
1413 &[arr, idx, val],
1414 )?;
1415 }
1416
1417 Ok(arr)
1418 }
1419
1420 Expr::Pipe { expr, operations } => {
1421 let mut result = compile_expr(module, functions, extern_fns, builder, scope, expr)?;
1423
1424 for op in operations {
1426 result = match op {
1427 PipeOp::First => compile_call(
1429 module,
1430 functions,
1431 extern_fns,
1432 builder,
1433 "sigil_array_first",
1434 &[result],
1435 )?,
1436 PipeOp::Last => compile_call(
1437 module,
1438 functions,
1439 extern_fns,
1440 builder,
1441 "sigil_array_last",
1442 &[result],
1443 )?,
1444 PipeOp::Middle => compile_call(
1445 module,
1446 functions,
1447 extern_fns,
1448 builder,
1449 "sigil_array_middle",
1450 &[result],
1451 )?,
1452 PipeOp::Choice => compile_call(
1453 module,
1454 functions,
1455 extern_fns,
1456 builder,
1457 "sigil_array_choice",
1458 &[result],
1459 )?,
1460 PipeOp::Next => compile_call(
1461 module,
1462 functions,
1463 extern_fns,
1464 builder,
1465 "sigil_array_next",
1466 &[result],
1467 )?,
1468 PipeOp::Nth(index_expr) => {
1469 let index = compile_expr(
1470 module, functions, extern_fns, builder, scope, index_expr,
1471 )?;
1472 compile_call(
1473 module,
1474 functions,
1475 extern_fns,
1476 builder,
1477 "sigil_array_nth",
1478 &[result, index],
1479 )?
1480 }
1481 PipeOp::Reduce(_) => {
1483 compile_call(
1485 module,
1486 functions,
1487 extern_fns,
1488 builder,
1489 "sigil_array_sum",
1490 &[result],
1491 )?
1492 }
1493 PipeOp::ReduceSum => compile_call(
1495 module,
1496 functions,
1497 extern_fns,
1498 builder,
1499 "sigil_array_sum",
1500 &[result],
1501 )?,
1502 PipeOp::ReduceProd => compile_call(
1504 module,
1505 functions,
1506 extern_fns,
1507 builder,
1508 "sigil_array_product",
1509 &[result],
1510 )?,
1511 PipeOp::ReduceMin => compile_call(
1513 module,
1514 functions,
1515 extern_fns,
1516 builder,
1517 "sigil_array_min",
1518 &[result],
1519 )?,
1520 PipeOp::ReduceMax => compile_call(
1522 module,
1523 functions,
1524 extern_fns,
1525 builder,
1526 "sigil_array_max",
1527 &[result],
1528 )?,
1529 PipeOp::ReduceConcat => compile_call(
1531 module,
1532 functions,
1533 extern_fns,
1534 builder,
1535 "sigil_array_concat",
1536 &[result],
1537 )?,
1538 PipeOp::ReduceAll => compile_call(
1540 module,
1541 functions,
1542 extern_fns,
1543 builder,
1544 "sigil_array_all",
1545 &[result],
1546 )?,
1547 PipeOp::ReduceAny => compile_call(
1549 module,
1550 functions,
1551 extern_fns,
1552 builder,
1553 "sigil_array_any",
1554 &[result],
1555 )?,
1556 PipeOp::Sort(_) => compile_call(
1558 module,
1559 functions,
1560 extern_fns,
1561 builder,
1562 "sigil_array_sort",
1563 &[result],
1564 )?,
1565 PipeOp::Transform(_) | PipeOp::Filter(_) => {
1567 result
1570 }
1571 PipeOp::Method { name, type_args: _, args } => {
1573 let mut call_args = vec![result];
1575 for arg in args {
1576 call_args.push(compile_expr(
1577 module, functions, extern_fns, builder, scope, arg,
1578 )?);
1579 }
1580 compile_call(
1581 module, functions, extern_fns, builder, &name.name, &call_args,
1582 )?
1583 }
1584 PipeOp::Await => {
1585 result
1587 }
1588 PipeOp::Match(_) => {
1589 result
1592 }
1593 PipeOp::TryMap(_) => {
1594 result
1596 }
1597 PipeOp::Call(callee) => {
1598 let callee_val = compile_expr(
1601 module, functions, extern_fns, builder, scope, callee,
1602 )?;
1603 compile_call(
1605 module, functions, extern_fns, builder,
1606 "sigil_call",
1607 &[callee_val, result],
1608 )?
1609 }
1610 PipeOp::Named { prefix, body } => {
1611 if !prefix.is_empty() {
1613 let fn_name = &prefix[0].name;
1614 if let Some(body_expr) = body {
1615 let body_val = compile_expr(
1616 module, functions, extern_fns, builder, scope, body_expr,
1617 )?;
1618 compile_call(
1619 module,
1620 functions,
1621 extern_fns,
1622 builder,
1623 fn_name,
1624 &[result, body_val],
1625 )?
1626 } else {
1627 compile_call(
1628 module,
1629 functions,
1630 extern_fns,
1631 builder,
1632 fn_name,
1633 &[result],
1634 )?
1635 }
1636 } else {
1637 result
1638 }
1639 }
1640 PipeOp::Parallel(inner_op) => {
1642 match inner_op.as_ref() {
1645 PipeOp::Transform(_) => {
1646 compile_call(
1648 module,
1649 functions,
1650 extern_fns,
1651 builder,
1652 "sigil_parallel_map",
1653 &[result],
1654 )?
1655 }
1656 PipeOp::Filter(_) => {
1657 compile_call(
1659 module,
1660 functions,
1661 extern_fns,
1662 builder,
1663 "sigil_parallel_filter",
1664 &[result],
1665 )?
1666 }
1667 PipeOp::Reduce(_) => {
1668 compile_call(
1670 module,
1671 functions,
1672 extern_fns,
1673 builder,
1674 "sigil_parallel_reduce",
1675 &[result],
1676 )?
1677 }
1678 _ => result,
1680 }
1681 }
1682 PipeOp::Gpu(inner_op) => {
1684 match inner_op.as_ref() {
1687 PipeOp::Transform(_) => {
1688 compile_call(
1690 module,
1691 functions,
1692 extern_fns,
1693 builder,
1694 "sigil_gpu_map",
1695 &[result],
1696 )?
1697 }
1698 PipeOp::Filter(_) => {
1699 compile_call(
1701 module,
1702 functions,
1703 extern_fns,
1704 builder,
1705 "sigil_gpu_filter",
1706 &[result],
1707 )?
1708 }
1709 PipeOp::Reduce(_) => {
1710 compile_call(
1712 module,
1713 functions,
1714 extern_fns,
1715 builder,
1716 "sigil_gpu_reduce",
1717 &[result],
1718 )?
1719 }
1720 _ => result,
1721 }
1722 }
1723
1724 PipeOp::Send(data_expr) => {
1731 let data = compile_expr(
1732 module, functions, extern_fns, builder, scope, data_expr,
1733 )?;
1734 compile_call(
1735 module,
1736 functions,
1737 extern_fns,
1738 builder,
1739 "sigil_protocol_send",
1740 &[result, data],
1741 )?
1742 }
1743
1744 PipeOp::Recv => compile_call(
1746 module,
1747 functions,
1748 extern_fns,
1749 builder,
1750 "sigil_protocol_recv",
1751 &[result],
1752 )?,
1753
1754 PipeOp::Stream(handler_expr) => {
1756 let handler = compile_expr(
1757 module,
1758 functions,
1759 extern_fns,
1760 builder,
1761 scope,
1762 handler_expr,
1763 )?;
1764 compile_call(
1765 module,
1766 functions,
1767 extern_fns,
1768 builder,
1769 "sigil_protocol_stream",
1770 &[result, handler],
1771 )?
1772 }
1773
1774 PipeOp::Connect(config_expr) => {
1776 if let Some(config) = config_expr {
1777 let config_val = compile_expr(
1778 module, functions, extern_fns, builder, scope, config,
1779 )?;
1780 compile_call(
1781 module,
1782 functions,
1783 extern_fns,
1784 builder,
1785 "sigil_protocol_connect",
1786 &[result, config_val],
1787 )?
1788 } else {
1789 compile_call(
1790 module,
1791 functions,
1792 extern_fns,
1793 builder,
1794 "sigil_protocol_connect_default",
1795 &[result],
1796 )?
1797 }
1798 }
1799
1800 PipeOp::Close => compile_call(
1802 module,
1803 functions,
1804 extern_fns,
1805 builder,
1806 "sigil_protocol_close",
1807 &[result],
1808 )?,
1809
1810 PipeOp::Header { name, value } => {
1812 let name_val =
1813 compile_expr(module, functions, extern_fns, builder, scope, name)?;
1814 let value_val =
1815 compile_expr(module, functions, extern_fns, builder, scope, value)?;
1816 compile_call(
1817 module,
1818 functions,
1819 extern_fns,
1820 builder,
1821 "sigil_protocol_header",
1822 &[result, name_val, value_val],
1823 )?
1824 }
1825
1826 PipeOp::Body(data_expr) => {
1828 let data = compile_expr(
1829 module, functions, extern_fns, builder, scope, data_expr,
1830 )?;
1831 compile_call(
1832 module,
1833 functions,
1834 extern_fns,
1835 builder,
1836 "sigil_protocol_body",
1837 &[result, data],
1838 )?
1839 }
1840
1841 PipeOp::Timeout(ms_expr) => {
1843 let ms = compile_expr(
1844 module, functions, extern_fns, builder, scope, ms_expr,
1845 )?;
1846 compile_call(
1847 module,
1848 functions,
1849 extern_fns,
1850 builder,
1851 "sigil_protocol_timeout",
1852 &[result, ms],
1853 )?
1854 }
1855
1856 PipeOp::Retry { count, strategy } => {
1858 let count_val =
1859 compile_expr(module, functions, extern_fns, builder, scope, count)?;
1860 if let Some(strat) = strategy {
1861 let strat_val = compile_expr(
1862 module, functions, extern_fns, builder, scope, strat,
1863 )?;
1864 compile_call(
1865 module,
1866 functions,
1867 extern_fns,
1868 builder,
1869 "sigil_protocol_retry",
1870 &[result, count_val, strat_val],
1871 )?
1872 } else {
1873 compile_call(
1874 module,
1875 functions,
1876 extern_fns,
1877 builder,
1878 "sigil_protocol_retry_default",
1879 &[result, count_val],
1880 )?
1881 }
1882 }
1883
1884 PipeOp::Validate {
1886 predicate,
1887 target_evidence: _,
1888 } => {
1889 let pred_val = compile_expr(
1890 module, functions, extern_fns, builder, scope, predicate,
1891 )?;
1892 compile_call(
1893 module,
1894 functions,
1895 extern_fns,
1896 builder,
1897 "sigil_validate",
1898 &[result, pred_val],
1899 )?
1900 }
1901
1902 PipeOp::Assume {
1903 reason,
1904 target_evidence: _,
1905 } => {
1906 let reason_val = if let Some(r) = reason {
1907 compile_expr(module, functions, extern_fns, builder, scope, r)?
1908 } else {
1909 builder.ins().iconst(types::I64, 0)
1910 };
1911 compile_call(
1912 module,
1913 functions,
1914 extern_fns,
1915 builder,
1916 "sigil_assume",
1917 &[result, reason_val],
1918 )?
1919 }
1920
1921 PipeOp::AssertEvidence(_) => {
1922 result
1925 }
1926
1927 PipeOp::Also(func) => {
1929 let _ =
1931 compile_expr(module, functions, extern_fns, builder, scope, func)?;
1932 result
1933 }
1934
1935 PipeOp::Apply(func) => {
1936 let _ =
1938 compile_expr(module, functions, extern_fns, builder, scope, func)?;
1939 result
1940 }
1941
1942 PipeOp::TakeIf(pred) => {
1943 let pred_val =
1945 compile_expr(module, functions, extern_fns, builder, scope, pred)?;
1946 compile_call(
1947 module,
1948 functions,
1949 extern_fns,
1950 builder,
1951 "sigil_take_if",
1952 &[result, pred_val],
1953 )?
1954 }
1955
1956 PipeOp::TakeUnless(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_unless",
1966 &[result, pred_val],
1967 )?
1968 }
1969
1970 PipeOp::Let(func) => {
1971 compile_expr(module, functions, extern_fns, builder, scope, func)?
1973 }
1974
1975 PipeOp::All(_)
1978 | PipeOp::Any(_)
1979 | PipeOp::Compose(_)
1980 | PipeOp::Zip(_)
1981 | PipeOp::Scan(_)
1982 | PipeOp::Diff
1983 | PipeOp::Gradient(_)
1984 | PipeOp::SortBy(_)
1985 | PipeOp::SortAsc
1986 | PipeOp::SortDesc
1987 | PipeOp::Reverse
1988 | PipeOp::Cycle(_)
1989 | PipeOp::Windows(_)
1990 | PipeOp::Chunks(_)
1991 | PipeOp::Flatten
1992 | PipeOp::Unique
1993 | PipeOp::Enumerate
1994 | PipeOp::ReduceWithInit(_, _)
1995 | PipeOp::Universal
1997 | PipeOp::Possibility { .. }
1998 | PipeOp::Necessity { .. }
1999 | PipeOp::PossibilityExtract
2000 | PipeOp::NecessityVerify => {
2001 result
2003 }
2004 };
2005 }
2006
2007 Ok(result)
2008 }
2009
2010 Expr::Unsafe(block) => {
2012 let mut inner_scope = scope.child();
2013 compile_block(
2014 module,
2015 functions,
2016 extern_fns,
2017 builder,
2018 &mut inner_scope,
2019 block,
2020 )
2021 }
2022
2023 Expr::Async { block, .. } => {
2025 let mut inner_scope = scope.child();
2026 compile_block(
2027 module,
2028 functions,
2029 extern_fns,
2030 builder,
2031 &mut inner_scope,
2032 block,
2033 )
2034 }
2035
2036 Expr::Deref(inner) => {
2038 let ptr = compile_expr(module, functions, extern_fns, builder, scope, inner)?;
2039 Ok(builder
2041 .ins()
2042 .load(types::I64, cranelift_codegen::ir::MemFlags::new(), ptr, 0))
2043 }
2044
2045 Expr::AddrOf { expr: inner, .. } => {
2047 compile_expr(module, functions, extern_fns, builder, scope, inner)
2048 }
2049
2050 Expr::Cast { expr: inner, ty } => {
2052 let val = compile_expr(module, functions, extern_fns, builder, scope, inner)?;
2053 let _ = ty; Ok(val)
2056 }
2057
2058 _ => Ok(builder.ins().iconst(types::I64, 0)),
2059 }
2060 }
2061
2062 fn compile_literal(
2064 builder: &mut FunctionBuilder,
2065 lit: &Literal,
2066 ) -> Result<cranelift_codegen::ir::Value, String> {
2067 match lit {
2068 Literal::Int { value, .. } => {
2069 let val: i64 = value.parse().map_err(|_| "Invalid integer")?;
2070 Ok(builder.ins().iconst(types::I64, val))
2071 }
2072 Literal::Float { value, .. } => {
2073 let val: f64 = value.parse().map_err(|_| "Invalid float")?;
2074 Ok(builder.ins().iconst(types::I64, val.to_bits() as i64))
2077 }
2078 Literal::Bool(b) => Ok(builder.ins().iconst(types::I64, if *b { 1 } else { 0 })),
2079 Literal::String(_) => Ok(builder.ins().iconst(types::I64, 0)),
2080 _ => Ok(builder.ins().iconst(types::I64, 0)),
2081 }
2082 }
2083
2084 fn compile_binary_op(
2086 builder: &mut FunctionBuilder,
2087 op: BinOp,
2088 lhs: cranelift_codegen::ir::Value,
2089 rhs: cranelift_codegen::ir::Value,
2090 ) -> Result<cranelift_codegen::ir::Value, String> {
2091 let result = match op {
2092 BinOp::Add => builder.ins().iadd(lhs, rhs),
2093 BinOp::Sub => builder.ins().isub(lhs, rhs),
2094 BinOp::Mul => builder.ins().imul(lhs, rhs),
2095 BinOp::Div => builder.ins().sdiv(lhs, rhs),
2096 BinOp::Rem => builder.ins().srem(lhs, rhs),
2097 BinOp::Pow => return Err("Power not supported".into()),
2098 BinOp::BitAnd => builder.ins().band(lhs, rhs),
2099 BinOp::BitOr => builder.ins().bor(lhs, rhs),
2100 BinOp::BitXor => builder.ins().bxor(lhs, rhs),
2101 BinOp::Shl => builder.ins().ishl(lhs, rhs),
2102 BinOp::Shr => builder.ins().sshr(lhs, rhs),
2103 BinOp::Eq => {
2104 let cmp = builder.ins().icmp(IntCC::Equal, lhs, rhs);
2105 builder.ins().uextend(types::I64, cmp)
2106 }
2107 BinOp::Ne => {
2108 let cmp = builder.ins().icmp(IntCC::NotEqual, lhs, rhs);
2109 builder.ins().uextend(types::I64, cmp)
2110 }
2111 BinOp::Lt => {
2112 let cmp = builder.ins().icmp(IntCC::SignedLessThan, lhs, rhs);
2113 builder.ins().uextend(types::I64, cmp)
2114 }
2115 BinOp::Le => {
2116 let cmp = builder.ins().icmp(IntCC::SignedLessThanOrEqual, lhs, rhs);
2117 builder.ins().uextend(types::I64, cmp)
2118 }
2119 BinOp::Gt => {
2120 let cmp = builder.ins().icmp(IntCC::SignedGreaterThan, lhs, rhs);
2121 builder.ins().uextend(types::I64, cmp)
2122 }
2123 BinOp::Ge => {
2124 let cmp = builder
2125 .ins()
2126 .icmp(IntCC::SignedGreaterThanOrEqual, lhs, rhs);
2127 builder.ins().uextend(types::I64, cmp)
2128 }
2129 BinOp::And => builder.ins().band(lhs, rhs),
2130 BinOp::Or => builder.ins().bor(lhs, rhs),
2131 BinOp::Concat => return Err("Concat not supported".into()),
2132 BinOp::MatMul => return Err("MatMul not supported in JIT (use runtime)".into()),
2133 BinOp::Hadamard => return Err("Hadamard not supported in JIT (use runtime)".into()),
2134 BinOp::TensorProd => return Err("TensorProd not supported in JIT (use runtime)".into()),
2135 BinOp::Convolve => return Err("Convolve not supported in JIT (use runtime)".into()),
2136 };
2137 Ok(result)
2138 }
2139
2140 fn compile_float_binary_op(
2142 builder: &mut FunctionBuilder,
2143 op: &BinOp,
2144 lhs: cranelift_codegen::ir::Value,
2145 rhs: cranelift_codegen::ir::Value,
2146 ) -> Result<cranelift_codegen::ir::Value, String> {
2147 use cranelift_codegen::ir::condcodes::FloatCC;
2148
2149 let lhs_f = builder
2151 .ins()
2152 .bitcast(types::F64, cranelift_codegen::ir::MemFlags::new(), lhs);
2153 let rhs_f = builder
2154 .ins()
2155 .bitcast(types::F64, cranelift_codegen::ir::MemFlags::new(), rhs);
2156
2157 let result_f = match op {
2158 BinOp::Add => builder.ins().fadd(lhs_f, rhs_f),
2159 BinOp::Sub => builder.ins().fsub(lhs_f, rhs_f),
2160 BinOp::Mul => builder.ins().fmul(lhs_f, rhs_f),
2161 BinOp::Div => builder.ins().fdiv(lhs_f, rhs_f),
2162 BinOp::Lt => {
2163 let cmp = builder.ins().fcmp(FloatCC::LessThan, lhs_f, rhs_f);
2164 return Ok(builder.ins().uextend(types::I64, cmp));
2165 }
2166 BinOp::Le => {
2167 let cmp = builder.ins().fcmp(FloatCC::LessThanOrEqual, lhs_f, rhs_f);
2168 return Ok(builder.ins().uextend(types::I64, cmp));
2169 }
2170 BinOp::Gt => {
2171 let cmp = builder.ins().fcmp(FloatCC::GreaterThan, lhs_f, rhs_f);
2172 return Ok(builder.ins().uextend(types::I64, cmp));
2173 }
2174 BinOp::Ge => {
2175 let cmp = builder
2176 .ins()
2177 .fcmp(FloatCC::GreaterThanOrEqual, lhs_f, rhs_f);
2178 return Ok(builder.ins().uextend(types::I64, cmp));
2179 }
2180 BinOp::Eq => {
2181 let cmp = builder.ins().fcmp(FloatCC::Equal, lhs_f, rhs_f);
2182 return Ok(builder.ins().uextend(types::I64, cmp));
2183 }
2184 BinOp::Ne => {
2185 let cmp = builder.ins().fcmp(FloatCC::NotEqual, lhs_f, rhs_f);
2186 return Ok(builder.ins().uextend(types::I64, cmp));
2187 }
2188 _ => return Err(format!("Float operation {:?} not supported", op)),
2189 };
2190
2191 Ok(builder
2193 .ins()
2194 .bitcast(types::I64, cranelift_codegen::ir::MemFlags::new(), result_f))
2195 }
2196
2197 fn compile_unary_op(
2199 builder: &mut FunctionBuilder,
2200 op: UnaryOp,
2201 val: cranelift_codegen::ir::Value,
2202 ) -> Result<cranelift_codegen::ir::Value, String> {
2203 let result = match op {
2204 UnaryOp::Neg => builder.ins().ineg(val),
2205 UnaryOp::Not => {
2206 let zero = builder.ins().iconst(types::I64, 0);
2207 let cmp = builder.ins().icmp(IntCC::Equal, val, zero);
2208 builder.ins().uextend(types::I64, cmp)
2209 }
2210 UnaryOp::Deref | UnaryOp::Ref | UnaryOp::RefMut => val,
2211 };
2212 Ok(result)
2213 }
2214
2215 fn compile_call(
2217 module: &mut JITModule,
2218 functions: &HashMap<String, FuncId>,
2219 extern_fns: &HashMap<String, ExternFnSig>,
2220 builder: &mut FunctionBuilder,
2221 name: &str,
2222 args: &[cranelift_codegen::ir::Value],
2223 ) -> Result<cranelift_codegen::ir::Value, String> {
2224 let builtin_name = match name {
2225 "sqrt" => Some("sigil_sqrt"),
2226 "sin" => Some("sigil_sin"),
2227 "cos" => Some("sigil_cos"),
2228 "pow" => Some("sigil_pow"),
2229 "exp" => Some("sigil_exp"),
2230 "ln" => Some("sigil_ln"),
2231 "floor" => Some("sigil_floor"),
2232 "ceil" => Some("sigil_ceil"),
2233 "abs" => Some("sigil_abs"),
2234 "print" => Some("sigil_print"),
2235 "now" => Some("sigil_now"),
2236 "ackermann" => Some("sigil_ackermann"),
2238 "tak" => Some("sigil_tak"),
2239 n if n.starts_with("sigil_") => Some(n),
2240 _ => None,
2241 };
2242
2243 if let Some(builtin) = builtin_name {
2244 let mut sig = module.make_signature();
2245
2246 match builtin {
2247 "sigil_sqrt" | "sigil_sin" | "sigil_cos" | "sigil_exp" | "sigil_ln"
2248 | "sigil_floor" | "sigil_ceil" | "sigil_abs" => {
2249 sig.params.push(AbiParam::new(types::F64));
2250 sig.returns.push(AbiParam::new(types::F64));
2251 }
2252 "sigil_pow" => {
2253 sig.params.push(AbiParam::new(types::F64));
2254 sig.params.push(AbiParam::new(types::F64));
2255 sig.returns.push(AbiParam::new(types::F64));
2256 }
2257 "sigil_print_int" => {
2258 sig.params.push(AbiParam::new(types::I64));
2259 sig.returns.push(AbiParam::new(types::I64));
2260 }
2261 "sigil_now" => {
2262 sig.returns.push(AbiParam::new(types::I64));
2263 }
2264 "sigil_array_new" => {
2265 sig.params.push(AbiParam::new(types::I64));
2266 sig.returns.push(AbiParam::new(types::I64));
2267 }
2268 "sigil_array_get" | "sigil_array_set" => {
2269 sig.params.push(AbiParam::new(types::I64));
2270 sig.params.push(AbiParam::new(types::I64));
2271 if builtin == "sigil_array_set" {
2272 sig.params.push(AbiParam::new(types::I64));
2273 }
2274 sig.returns.push(AbiParam::new(types::I64));
2275 }
2276 "sigil_array_len" => {
2277 sig.params.push(AbiParam::new(types::I64));
2278 sig.returns.push(AbiParam::new(types::I64));
2279 }
2280 "sigil_array_first"
2282 | "sigil_array_last"
2283 | "sigil_array_middle"
2284 | "sigil_array_choice"
2285 | "sigil_array_next"
2286 | "sigil_array_sum"
2287 | "sigil_array_product" => {
2288 sig.params.push(AbiParam::new(types::I64));
2289 sig.returns.push(AbiParam::new(types::I64));
2290 }
2291 "sigil_array_sort" => {
2293 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2296 "sigil_parallel_map" | "sigil_parallel_filter" => {
2298 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2301 "sigil_parallel_reduce" => {
2302 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2305 "sigil_gpu_map" | "sigil_gpu_filter" => {
2307 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2310 "sigil_gpu_reduce" => {
2311 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); }
2314 "sigil_array_nth" => {
2316 sig.params.push(AbiParam::new(types::I64)); sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64));
2319 }
2320 _ => {
2321 for _ in args {
2322 sig.params.push(AbiParam::new(types::I64));
2323 }
2324 sig.returns.push(AbiParam::new(types::I64));
2325 }
2326 }
2327
2328 let callee = module
2329 .declare_function(builtin, Linkage::Import, &sig)
2330 .map_err(|e| e.to_string())?;
2331
2332 let local_callee = module.declare_func_in_func(callee, builder.func);
2333
2334 let call_args: Vec<_> = if matches!(
2335 builtin,
2336 "sigil_sqrt"
2337 | "sigil_sin"
2338 | "sigil_cos"
2339 | "sigil_exp"
2340 | "sigil_ln"
2341 | "sigil_floor"
2342 | "sigil_ceil"
2343 | "sigil_abs"
2344 | "sigil_pow"
2345 ) {
2346 args.iter()
2347 .map(|&v| {
2348 if builder.func.dfg.value_type(v) == types::F64 {
2349 v
2350 } else {
2351 builder.ins().fcvt_from_sint(types::F64, v)
2352 }
2353 })
2354 .collect()
2355 } else {
2356 args.to_vec()
2357 };
2358
2359 let call = builder.ins().call(local_callee, &call_args);
2360 Ok(builder.inst_results(call)[0])
2361 } else if let Some(&func_id) = functions.get(name) {
2362 let local_callee = module.declare_func_in_func(func_id, builder.func);
2364 let call = builder.ins().call(local_callee, args);
2365 Ok(builder.inst_results(call)[0])
2366 } else if let Some(extern_fn) = extern_fns.get(name) {
2367 let local_callee = module.declare_func_in_func(extern_fn.func_id, builder.func);
2369
2370 let mut call_args = Vec::new();
2372 for (i, &arg) in args.iter().enumerate() {
2373 let arg_type = builder.func.dfg.value_type(arg);
2374 let expected_type = extern_fn.params.get(i).copied().unwrap_or(types::I64);
2375
2376 let converted = if arg_type == expected_type {
2377 arg
2378 } else if arg_type == types::I64 && expected_type == types::I32 {
2379 builder.ins().ireduce(types::I32, arg)
2380 } else if arg_type == types::I32 && expected_type == types::I64 {
2381 builder.ins().sextend(types::I64, arg)
2382 } else if arg_type == types::I64 && expected_type == types::F64 {
2383 builder.ins().fcvt_from_sint(types::F64, arg)
2384 } else if arg_type == types::F64 && expected_type == types::I64 {
2385 builder.ins().fcvt_to_sint(types::I64, arg)
2386 } else {
2387 arg };
2389 call_args.push(converted);
2390 }
2391
2392 let call = builder.ins().call(local_callee, &call_args);
2393
2394 if extern_fn.returns.is_some() {
2396 let result = builder.inst_results(call)[0];
2397 let result_type = builder.func.dfg.value_type(result);
2398 if result_type == types::I32
2400 || result_type == types::I16
2401 || result_type == types::I8
2402 {
2403 Ok(builder.ins().sextend(types::I64, result))
2404 } else {
2405 Ok(result)
2406 }
2407 } else {
2408 Ok(builder.ins().iconst(types::I64, 0))
2410 }
2411 } else {
2412 Err(format!("Unknown function: {}", name))
2413 }
2414 }
2415
2416 fn compile_if_tracked(
2418 module: &mut JITModule,
2419 functions: &HashMap<String, FuncId>,
2420 extern_fns: &HashMap<String, ExternFnSig>,
2421 builder: &mut FunctionBuilder,
2422 scope: &mut CompileScope,
2423 condition: &Expr,
2424 then_branch: &ast::Block,
2425 else_branch: Option<&Expr>,
2426 ) -> Result<(cranelift_codegen::ir::Value, bool), String> {
2427 let cond_bool =
2429 compile_condition(module, functions, extern_fns, builder, scope, condition)?;
2430
2431 let then_block = builder.create_block();
2432 let else_block = builder.create_block();
2433 let merge_block = builder.create_block();
2434
2435 builder.append_block_param(merge_block, types::I64);
2436
2437 builder
2439 .ins()
2440 .brif(cond_bool, then_block, &[], else_block, &[]);
2441
2442 builder.switch_to_block(then_block);
2444 builder.seal_block(then_block);
2445 let mut then_scope = scope.child();
2446 let (then_val, then_returns) = compile_block_tracked(
2447 module,
2448 functions,
2449 extern_fns,
2450 builder,
2451 &mut then_scope,
2452 then_branch,
2453 )?;
2454 if !then_returns {
2456 builder.ins().jump(merge_block, &[then_val]);
2457 }
2458
2459 builder.switch_to_block(else_block);
2461 builder.seal_block(else_block);
2462 let (else_val, else_returns) = if let Some(else_expr) = else_branch {
2463 match else_expr {
2464 Expr::Block(block) => {
2465 let mut else_scope = scope.child();
2466 compile_block_tracked(
2467 module,
2468 functions,
2469 extern_fns,
2470 builder,
2471 &mut else_scope,
2472 block,
2473 )?
2474 }
2475 Expr::If {
2476 condition,
2477 then_branch,
2478 else_branch,
2479 } => compile_if_tracked(
2480 module,
2481 functions,
2482 extern_fns,
2483 builder,
2484 scope,
2485 condition,
2486 then_branch,
2487 else_branch.as_deref(),
2488 )?,
2489 _ => {
2490 let val =
2491 compile_expr(module, functions, extern_fns, builder, scope, else_expr)?;
2492 (val, false)
2493 }
2494 }
2495 } else {
2496 (builder.ins().iconst(types::I64, 0), false)
2497 };
2498 if !else_returns {
2500 builder.ins().jump(merge_block, &[else_val]);
2501 }
2502
2503 let both_return = then_returns && else_returns;
2506
2507 builder.switch_to_block(merge_block);
2508 builder.seal_block(merge_block);
2509
2510 if both_return {
2511 let dummy = builder.ins().iconst(types::I64, 0);
2514 Ok((dummy, true))
2515 } else {
2516 Ok((builder.block_params(merge_block)[0], false))
2517 }
2518 }
2519
2520 fn compile_if(
2522 module: &mut JITModule,
2523 functions: &HashMap<String, FuncId>,
2524 extern_fns: &HashMap<String, ExternFnSig>,
2525 builder: &mut FunctionBuilder,
2526 scope: &mut CompileScope,
2527 condition: &Expr,
2528 then_branch: &ast::Block,
2529 else_branch: Option<&Expr>,
2530 ) -> Result<cranelift_codegen::ir::Value, String> {
2531 compile_if_tracked(
2532 module,
2533 functions,
2534 extern_fns,
2535 builder,
2536 scope,
2537 condition,
2538 then_branch,
2539 else_branch,
2540 )
2541 .map(|(v, _)| v)
2542 }
2543
2544 fn compile_while(
2546 module: &mut JITModule,
2547 functions: &HashMap<String, FuncId>,
2548 extern_fns: &HashMap<String, ExternFnSig>,
2549 builder: &mut FunctionBuilder,
2550 scope: &mut CompileScope,
2551 condition: &Expr,
2552 body: &ast::Block,
2553 ) -> Result<cranelift_codegen::ir::Value, String> {
2554 let header_block = builder.create_block();
2555 let body_block = builder.create_block();
2556 let exit_block = builder.create_block();
2557
2558 builder.ins().jump(header_block, &[]);
2559
2560 builder.switch_to_block(header_block);
2561 let cond_bool =
2563 compile_condition(module, functions, extern_fns, builder, scope, condition)?;
2564 builder
2566 .ins()
2567 .brif(cond_bool, body_block, &[], exit_block, &[]);
2568
2569 builder.switch_to_block(body_block);
2570 builder.seal_block(body_block);
2571 let mut body_scope = scope.child();
2572 compile_block(
2573 module,
2574 functions,
2575 extern_fns,
2576 builder,
2577 &mut body_scope,
2578 body,
2579 )?;
2580 builder.ins().jump(header_block, &[]);
2581
2582 builder.seal_block(header_block);
2583
2584 builder.switch_to_block(exit_block);
2585 builder.seal_block(exit_block);
2586
2587 Ok(builder.ins().iconst(types::I64, 0))
2588 }
2589
2590 #[inline]
2598 fn is_float_pattern(v: i64) -> bool {
2599 let exp = (v >> 52) & 0x7FF;
2600 exp > 0 && exp < 0x7FF && v != 0
2603 }
2604
2605 #[no_mangle]
2606 pub extern "C" fn sigil_add(a: i64, b: i64) -> i64 {
2607 if is_float_pattern(a) || is_float_pattern(b) {
2608 let fa = f64::from_bits(a as u64);
2609 let fb = f64::from_bits(b as u64);
2610 (fa + fb).to_bits() as i64
2611 } else {
2612 a.wrapping_add(b)
2613 }
2614 }
2615
2616 #[no_mangle]
2617 pub extern "C" fn sigil_sub(a: i64, b: i64) -> i64 {
2618 if is_float_pattern(a) || is_float_pattern(b) {
2619 let fa = f64::from_bits(a as u64);
2620 let fb = f64::from_bits(b as u64);
2621 (fa - fb).to_bits() as i64
2622 } else {
2623 a.wrapping_sub(b)
2624 }
2625 }
2626
2627 #[no_mangle]
2628 pub extern "C" fn sigil_mul(a: i64, b: i64) -> i64 {
2629 if is_float_pattern(a) || is_float_pattern(b) {
2630 let fa = f64::from_bits(a as u64);
2631 let fb = f64::from_bits(b as u64);
2632 (fa * fb).to_bits() as i64
2633 } else {
2634 a.wrapping_mul(b)
2635 }
2636 }
2637
2638 #[no_mangle]
2639 pub extern "C" fn sigil_div(a: i64, b: i64) -> i64 {
2640 if is_float_pattern(a) || is_float_pattern(b) {
2641 let fa = f64::from_bits(a as u64);
2642 let fb = f64::from_bits(b as u64);
2643 (fa / fb).to_bits() as i64
2644 } else if b != 0 {
2645 a / b
2646 } else {
2647 0 }
2649 }
2650
2651 #[no_mangle]
2652 pub extern "C" fn sigil_lt(a: i64, b: i64) -> i64 {
2653 if is_float_pattern(a) || is_float_pattern(b) {
2654 let fa = f64::from_bits(a as u64);
2655 let fb = f64::from_bits(b as u64);
2656 if fa < fb {
2657 1
2658 } else {
2659 0
2660 }
2661 } else {
2662 if a < b {
2663 1
2664 } else {
2665 0
2666 }
2667 }
2668 }
2669
2670 #[no_mangle]
2671 pub extern "C" fn sigil_le(a: i64, b: i64) -> i64 {
2672 if is_float_pattern(a) || is_float_pattern(b) {
2673 let fa = f64::from_bits(a as u64);
2674 let fb = f64::from_bits(b as u64);
2675 if fa <= fb {
2676 1
2677 } else {
2678 0
2679 }
2680 } else {
2681 if a <= b {
2682 1
2683 } else {
2684 0
2685 }
2686 }
2687 }
2688
2689 #[no_mangle]
2690 pub extern "C" fn sigil_gt(a: i64, b: i64) -> i64 {
2691 if is_float_pattern(a) || is_float_pattern(b) {
2692 let fa = f64::from_bits(a as u64);
2693 let fb = f64::from_bits(b as u64);
2694 if fa > fb {
2695 1
2696 } else {
2697 0
2698 }
2699 } else {
2700 if a > b {
2701 1
2702 } else {
2703 0
2704 }
2705 }
2706 }
2707
2708 #[no_mangle]
2709 pub extern "C" fn sigil_ge(a: i64, b: i64) -> i64 {
2710 if is_float_pattern(a) || is_float_pattern(b) {
2711 let fa = f64::from_bits(a as u64);
2712 let fb = f64::from_bits(b as u64);
2713 if fa >= fb {
2714 1
2715 } else {
2716 0
2717 }
2718 } else {
2719 if a >= b {
2720 1
2721 } else {
2722 0
2723 }
2724 }
2725 }
2726
2727 #[no_mangle]
2729 pub extern "C" fn sigil_print(v: i64) -> i64 {
2730 if is_float_pattern(v) {
2731 println!("{}", f64::from_bits(v as u64));
2732 } else {
2733 println!("{}", v);
2734 }
2735 0
2736 }
2737
2738 #[repr(C, align(32))]
2750 struct SimdVec4 {
2751 data: [f64; 4],
2752 }
2753
2754 impl SimdVec4 {
2755 #[inline(always)]
2756 fn new(x: f64, y: f64, z: f64, w: f64) -> Box<Self> {
2757 Box::new(SimdVec4 { data: [x, y, z, w] })
2758 }
2759
2760 #[inline(always)]
2761 fn splat(v: f64) -> Box<Self> {
2762 Box::new(SimdVec4 { data: [v, v, v, v] })
2763 }
2764 }
2765
2766 #[no_mangle]
2768 pub extern "C" fn sigil_simd_new(x: i64, y: i64, z: i64, w: i64) -> i64 {
2769 let v = SimdVec4::new(
2770 f64::from_bits(x as u64),
2771 f64::from_bits(y as u64),
2772 f64::from_bits(z as u64),
2773 f64::from_bits(w as u64),
2774 );
2775 Box::into_raw(v) as i64
2776 }
2777
2778 #[no_mangle]
2780 pub extern "C" fn sigil_simd_splat(v: i64) -> i64 {
2781 let f = f64::from_bits(v as u64);
2782 let v = SimdVec4::splat(f);
2783 Box::into_raw(v) as i64
2784 }
2785
2786 #[no_mangle]
2791 #[inline(never)]
2792 pub extern "C" fn sigil_simd_add(a: i64, b: i64) -> i64 {
2793 unsafe {
2794 let a = &*(a as *const SimdVec4);
2795 let b = &*(b as *const SimdVec4);
2796 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2798 r.data[0] = a.data[0] + b.data[0];
2799 r.data[1] = a.data[1] + b.data[1];
2800 r.data[2] = a.data[2] + b.data[2];
2801 r.data[3] = a.data[3] + b.data[3];
2802 Box::into_raw(r) as i64
2803 }
2804 }
2805
2806 #[no_mangle]
2808 #[inline(never)]
2809 pub extern "C" fn sigil_simd_sub(a: i64, b: i64) -> i64 {
2810 unsafe {
2811 let a = &*(a as *const SimdVec4);
2812 let b = &*(b as *const SimdVec4);
2813 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2814 r.data[0] = a.data[0] - b.data[0];
2815 r.data[1] = a.data[1] - b.data[1];
2816 r.data[2] = a.data[2] - b.data[2];
2817 r.data[3] = a.data[3] - b.data[3];
2818 Box::into_raw(r) as i64
2819 }
2820 }
2821
2822 #[no_mangle]
2824 #[inline(never)]
2825 pub extern "C" fn sigil_simd_mul(a: i64, b: i64) -> i64 {
2826 unsafe {
2827 let a = &*(a as *const SimdVec4);
2828 let b = &*(b as *const SimdVec4);
2829 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2830 r.data[0] = a.data[0] * b.data[0];
2831 r.data[1] = a.data[1] * b.data[1];
2832 r.data[2] = a.data[2] * b.data[2];
2833 r.data[3] = a.data[3] * b.data[3];
2834 Box::into_raw(r) as i64
2835 }
2836 }
2837
2838 #[no_mangle]
2840 #[inline(never)]
2841 pub extern "C" fn sigil_simd_div(a: i64, b: i64) -> i64 {
2842 unsafe {
2843 let a = &*(a as *const SimdVec4);
2844 let b = &*(b as *const SimdVec4);
2845 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2846 r.data[0] = a.data[0] / b.data[0];
2847 r.data[1] = a.data[1] / b.data[1];
2848 r.data[2] = a.data[2] / b.data[2];
2849 r.data[3] = a.data[3] / b.data[3];
2850 Box::into_raw(r) as i64
2851 }
2852 }
2853
2854 #[no_mangle]
2856 #[inline(never)]
2857 pub extern "C" fn sigil_simd_dot(a: i64, b: i64) -> i64 {
2858 unsafe {
2859 let a = &*(a as *const SimdVec4);
2860 let b = &*(b as *const SimdVec4);
2861 let r = a.data[0].mul_add(
2863 b.data[0],
2864 a.data[1].mul_add(
2865 b.data[1],
2866 a.data[2].mul_add(b.data[2], a.data[3] * b.data[3]),
2867 ),
2868 );
2869 r.to_bits() as i64
2870 }
2871 }
2872
2873 #[no_mangle]
2875 #[inline(never)]
2876 pub extern "C" fn sigil_simd_hadd(a: i64) -> i64 {
2877 unsafe {
2878 let a = &*(a as *const SimdVec4);
2879 let sum01 = a.data[0] + a.data[1];
2881 let sum23 = a.data[2] + a.data[3];
2882 let r = sum01 + sum23;
2883 r.to_bits() as i64
2884 }
2885 }
2886
2887 #[no_mangle]
2889 #[inline(never)]
2890 pub extern "C" fn sigil_simd_length_sq(a: i64) -> i64 {
2891 unsafe {
2892 let a = &*(a as *const SimdVec4);
2893 let r = a.data[0].mul_add(
2894 a.data[0],
2895 a.data[1].mul_add(
2896 a.data[1],
2897 a.data[2].mul_add(a.data[2], a.data[3] * a.data[3]),
2898 ),
2899 );
2900 r.to_bits() as i64
2901 }
2902 }
2903
2904 #[no_mangle]
2906 #[inline(never)]
2907 pub extern "C" fn sigil_simd_length(a: i64) -> i64 {
2908 unsafe {
2909 let a = &*(a as *const SimdVec4);
2910 let len_sq = a.data[0].mul_add(
2911 a.data[0],
2912 a.data[1].mul_add(
2913 a.data[1],
2914 a.data[2].mul_add(a.data[2], a.data[3] * a.data[3]),
2915 ),
2916 );
2917 let r = len_sq.sqrt();
2918 r.to_bits() as i64
2919 }
2920 }
2921
2922 #[no_mangle]
2924 #[inline(never)]
2925 pub extern "C" fn sigil_simd_normalize(a: i64) -> i64 {
2926 unsafe {
2927 let a = &*(a as *const SimdVec4);
2928 let len_sq = a.data[0].mul_add(
2929 a.data[0],
2930 a.data[1].mul_add(
2931 a.data[1],
2932 a.data[2].mul_add(a.data[2], a.data[3] * a.data[3]),
2933 ),
2934 );
2935 let inv = if len_sq > 1e-20 {
2936 1.0 / len_sq.sqrt()
2937 } else {
2938 0.0
2939 };
2940 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2941 r.data[0] = a.data[0] * inv;
2942 r.data[1] = a.data[1] * inv;
2943 r.data[2] = a.data[2] * inv;
2944 r.data[3] = a.data[3] * inv;
2945 Box::into_raw(r) as i64
2946 }
2947 }
2948
2949 #[no_mangle]
2951 #[inline(never)]
2952 pub extern "C" fn sigil_simd_cross(a: i64, b: i64) -> i64 {
2953 unsafe {
2954 let a = &*(a as *const SimdVec4);
2955 let b = &*(b as *const SimdVec4);
2956 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2958 r.data[0] = a.data[1].mul_add(b.data[2], -(a.data[2] * b.data[1]));
2959 r.data[1] = a.data[2].mul_add(b.data[0], -(a.data[0] * b.data[2]));
2960 r.data[2] = a.data[0].mul_add(b.data[1], -(a.data[1] * b.data[0]));
2961 r.data[3] = 0.0;
2962 Box::into_raw(r) as i64
2963 }
2964 }
2965
2966 #[no_mangle]
2968 #[inline(never)]
2969 pub extern "C" fn sigil_simd_min(a: i64, b: i64) -> i64 {
2970 unsafe {
2971 let a = &*(a as *const SimdVec4);
2972 let b = &*(b as *const SimdVec4);
2973 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2974 r.data[0] = a.data[0].min(b.data[0]);
2975 r.data[1] = a.data[1].min(b.data[1]);
2976 r.data[2] = a.data[2].min(b.data[2]);
2977 r.data[3] = a.data[3].min(b.data[3]);
2978 Box::into_raw(r) as i64
2979 }
2980 }
2981
2982 #[no_mangle]
2984 #[inline(never)]
2985 pub extern "C" fn sigil_simd_max(a: i64, b: i64) -> i64 {
2986 unsafe {
2987 let a = &*(a as *const SimdVec4);
2988 let b = &*(b as *const SimdVec4);
2989 let mut r = SimdVec4::new(0.0, 0.0, 0.0, 0.0);
2990 r.data[0] = a.data[0].max(b.data[0]);
2991 r.data[1] = a.data[1].max(b.data[1]);
2992 r.data[2] = a.data[2].max(b.data[2]);
2993 r.data[3] = a.data[3].max(b.data[3]);
2994 Box::into_raw(r) as i64
2995 }
2996 }
2997
2998 #[no_mangle]
3000 pub extern "C" fn sigil_simd_extract(v: i64, idx: i64) -> i64 {
3001 unsafe {
3002 let v = &*(v as *const SimdVec4);
3003 let r = v.data[(idx as usize) & 3];
3004 r.to_bits() as i64
3005 }
3006 }
3007
3008 #[no_mangle]
3010 pub extern "C" fn sigil_simd_free(v: i64) {
3011 if v != 0 {
3012 unsafe {
3013 let _ = Box::from_raw(v as *mut SimdVec4);
3014 }
3015 }
3016 }
3017
3018 #[no_mangle]
3019 pub extern "C" fn sigil_sqrt(x: f64) -> f64 {
3020 x.sqrt()
3021 }
3022
3023 #[no_mangle]
3024 pub extern "C" fn sigil_sin(x: f64) -> f64 {
3025 x.sin()
3026 }
3027
3028 #[no_mangle]
3029 pub extern "C" fn sigil_cos(x: f64) -> f64 {
3030 x.cos()
3031 }
3032
3033 #[no_mangle]
3034 pub extern "C" fn sigil_pow(base: f64, exp: f64) -> f64 {
3035 base.powf(exp)
3036 }
3037
3038 #[no_mangle]
3039 pub extern "C" fn sigil_exp(x: f64) -> f64 {
3040 x.exp()
3041 }
3042
3043 #[no_mangle]
3044 pub extern "C" fn sigil_ln(x: f64) -> f64 {
3045 x.ln()
3046 }
3047
3048 #[no_mangle]
3049 pub extern "C" fn sigil_floor(x: f64) -> f64 {
3050 x.floor()
3051 }
3052
3053 #[no_mangle]
3054 pub extern "C" fn sigil_ceil(x: f64) -> f64 {
3055 x.ceil()
3056 }
3057
3058 #[no_mangle]
3059 pub extern "C" fn sigil_abs(x: f64) -> f64 {
3060 x.abs()
3061 }
3062
3063 #[no_mangle]
3064 pub extern "C" fn sigil_print_int(x: i64) -> i64 {
3065 println!("{}", x);
3066 0
3067 }
3068
3069 #[no_mangle]
3070 pub extern "C" fn sigil_print_float(x: f64) -> i64 {
3071 println!("{}", x);
3072 0
3073 }
3074
3075 #[no_mangle]
3076 pub extern "C" fn sigil_print_str(ptr: *const u8, len: usize) -> i64 {
3077 unsafe {
3078 let slice = std::slice::from_raw_parts(ptr, len);
3079 if let Ok(s) = std::str::from_utf8(slice) {
3080 println!("{}", s);
3081 }
3082 }
3083 0
3084 }
3085
3086 #[no_mangle]
3087 pub extern "C" fn sigil_now() -> i64 {
3088 use std::time::{SystemTime, UNIX_EPOCH};
3089 SystemTime::now()
3090 .duration_since(UNIX_EPOCH)
3091 .map(|d| d.as_millis() as i64)
3092 .unwrap_or(0)
3093 }
3094
3095 #[repr(C)]
3097 struct SigilArray {
3098 data: *mut i64,
3099 len: usize,
3100 cap: usize,
3101 }
3102
3103 #[no_mangle]
3104 pub extern "C" fn sigil_array_new(capacity: i64) -> i64 {
3105 let cap = capacity.max(8) as usize;
3106 let layout = std::alloc::Layout::array::<i64>(cap).unwrap();
3107 let data = unsafe { std::alloc::alloc(layout) as *mut i64 };
3108
3109 let arr = Box::new(SigilArray { data, len: 0, cap });
3110 Box::into_raw(arr) as i64
3111 }
3112
3113 #[no_mangle]
3114 pub extern "C" fn sigil_array_push(arr_ptr: i64, value: i64) -> i64 {
3115 unsafe {
3116 let arr = &mut *(arr_ptr as *mut SigilArray);
3117 if arr.len >= arr.cap {
3118 let new_cap = arr.cap * 2;
3120 let old_layout = std::alloc::Layout::array::<i64>(arr.cap).unwrap();
3121 let new_layout = std::alloc::Layout::array::<i64>(new_cap).unwrap();
3122 arr.data = std::alloc::realloc(arr.data as *mut u8, old_layout, new_layout.size())
3123 as *mut i64;
3124 arr.cap = new_cap;
3125 }
3126 *arr.data.add(arr.len) = value;
3127 arr.len += 1;
3128 }
3129 0
3130 }
3131
3132 #[no_mangle]
3133 pub extern "C" fn sigil_array_get(arr_ptr: i64, index: i64) -> i64 {
3134 unsafe {
3135 let arr = &*(arr_ptr as *const SigilArray);
3136 let idx = index as usize;
3137 if idx < arr.len {
3138 *arr.data.add(idx)
3139 } else {
3140 0 }
3142 }
3143 }
3144
3145 #[no_mangle]
3146 pub extern "C" fn sigil_array_set(arr_ptr: i64, index: i64, value: i64) -> i64 {
3147 unsafe {
3148 let arr = &mut *(arr_ptr as *mut SigilArray);
3149 let idx = index as usize;
3150 while arr.len <= idx {
3152 sigil_array_push(arr_ptr, 0);
3153 }
3154 *arr.data.add(idx) = value;
3155 }
3156 value
3157 }
3158
3159 #[no_mangle]
3160 pub extern "C" fn sigil_array_len(arr_ptr: i64) -> i64 {
3161 unsafe {
3162 let arr = &*(arr_ptr as *const SigilArray);
3163 arr.len as i64
3164 }
3165 }
3166
3167 #[no_mangle]
3174 pub extern "C" fn sigil_array_sum(arr_ptr: i64) -> i64 {
3175 unsafe {
3176 let arr = &*(arr_ptr as *const SigilArray);
3177 let data = std::slice::from_raw_parts(arr.data, arr.len);
3178
3179 let chunks = data.chunks_exact(4);
3181 let remainder = chunks.remainder();
3182
3183 let mut sum0: i64 = 0;
3185 let mut sum1: i64 = 0;
3186 let mut sum2: i64 = 0;
3187 let mut sum3: i64 = 0;
3188
3189 for chunk in chunks {
3190 sum0 = sum0.wrapping_add(chunk[0]);
3191 sum1 = sum1.wrapping_add(chunk[1]);
3192 sum2 = sum2.wrapping_add(chunk[2]);
3193 sum3 = sum3.wrapping_add(chunk[3]);
3194 }
3195
3196 let mut sum = sum0
3198 .wrapping_add(sum1)
3199 .wrapping_add(sum2)
3200 .wrapping_add(sum3);
3201 for &v in remainder {
3202 sum = sum.wrapping_add(v);
3203 }
3204
3205 sum
3206 }
3207 }
3208
3209 #[no_mangle]
3211 pub extern "C" fn sigil_array_scale(arr_ptr: i64, scalar: i64) -> i64 {
3212 unsafe {
3213 let arr = &mut *(arr_ptr as *mut SigilArray);
3214 let data = std::slice::from_raw_parts_mut(arr.data, arr.len);
3215
3216 for chunk in data.chunks_exact_mut(4) {
3218 chunk[0] = chunk[0].wrapping_mul(scalar);
3219 chunk[1] = chunk[1].wrapping_mul(scalar);
3220 chunk[2] = chunk[2].wrapping_mul(scalar);
3221 chunk[3] = chunk[3].wrapping_mul(scalar);
3222 }
3223
3224 let remainder_start = (data.len() / 4) * 4;
3226 for v in &mut data[remainder_start..] {
3227 *v = v.wrapping_mul(scalar);
3228 }
3229
3230 arr_ptr
3231 }
3232 }
3233
3234 #[no_mangle]
3236 pub extern "C" fn sigil_array_offset(arr_ptr: i64, offset: i64) -> i64 {
3237 unsafe {
3238 let arr = &mut *(arr_ptr as *mut SigilArray);
3239 let data = std::slice::from_raw_parts_mut(arr.data, arr.len);
3240
3241 for chunk in data.chunks_exact_mut(4) {
3243 chunk[0] = chunk[0].wrapping_add(offset);
3244 chunk[1] = chunk[1].wrapping_add(offset);
3245 chunk[2] = chunk[2].wrapping_add(offset);
3246 chunk[3] = chunk[3].wrapping_add(offset);
3247 }
3248
3249 let remainder_start = (data.len() / 4) * 4;
3250 for v in &mut data[remainder_start..] {
3251 *v = v.wrapping_add(offset);
3252 }
3253
3254 arr_ptr
3255 }
3256 }
3257
3258 #[no_mangle]
3260 pub extern "C" fn sigil_array_dot(a_ptr: i64, b_ptr: i64) -> i64 {
3261 unsafe {
3262 let a_arr = &*(a_ptr as *const SigilArray);
3263 let b_arr = &*(b_ptr as *const SigilArray);
3264
3265 let len = a_arr.len.min(b_arr.len);
3266 let a_data = std::slice::from_raw_parts(a_arr.data, len);
3267 let b_data = std::slice::from_raw_parts(b_arr.data, len);
3268
3269 let mut sum0: i64 = 0;
3271 let mut sum1: i64 = 0;
3272 let mut sum2: i64 = 0;
3273 let mut sum3: i64 = 0;
3274
3275 let chunks = len / 4;
3276 for i in 0..chunks {
3277 let base = i * 4;
3278 sum0 = sum0.wrapping_add(a_data[base].wrapping_mul(b_data[base]));
3279 sum1 = sum1.wrapping_add(a_data[base + 1].wrapping_mul(b_data[base + 1]));
3280 sum2 = sum2.wrapping_add(a_data[base + 2].wrapping_mul(b_data[base + 2]));
3281 sum3 = sum3.wrapping_add(a_data[base + 3].wrapping_mul(b_data[base + 3]));
3282 }
3283
3284 let mut sum = sum0
3286 .wrapping_add(sum1)
3287 .wrapping_add(sum2)
3288 .wrapping_add(sum3);
3289 for i in (chunks * 4)..len {
3290 sum = sum.wrapping_add(a_data[i].wrapping_mul(b_data[i]));
3291 }
3292
3293 sum
3294 }
3295 }
3296
3297 #[no_mangle]
3299 pub extern "C" fn sigil_array_add(a_ptr: i64, b_ptr: i64) -> i64 {
3300 unsafe {
3301 let a_arr = &*(a_ptr as *const SigilArray);
3302 let b_arr = &*(b_ptr as *const SigilArray);
3303
3304 let len = a_arr.len.min(b_arr.len);
3305 let a_data = std::slice::from_raw_parts(a_arr.data, len);
3306 let b_data = std::slice::from_raw_parts(b_arr.data, len);
3307
3308 let result = sigil_array_new(len as i64);
3310 let r_arr = &mut *(result as *mut SigilArray);
3311 r_arr.len = len;
3312 let r_data = std::slice::from_raw_parts_mut(r_arr.data, len);
3313
3314 for i in 0..(len / 4) {
3316 let base = i * 4;
3317 r_data[base] = a_data[base].wrapping_add(b_data[base]);
3318 r_data[base + 1] = a_data[base + 1].wrapping_add(b_data[base + 1]);
3319 r_data[base + 2] = a_data[base + 2].wrapping_add(b_data[base + 2]);
3320 r_data[base + 3] = a_data[base + 3].wrapping_add(b_data[base + 3]);
3321 }
3322
3323 for i in ((len / 4) * 4)..len {
3325 r_data[i] = a_data[i].wrapping_add(b_data[i]);
3326 }
3327
3328 result
3329 }
3330 }
3331
3332 #[no_mangle]
3334 pub extern "C" fn sigil_array_mul(a_ptr: i64, b_ptr: i64) -> i64 {
3335 unsafe {
3336 let a_arr = &*(a_ptr as *const SigilArray);
3337 let b_arr = &*(b_ptr as *const SigilArray);
3338
3339 let len = a_arr.len.min(b_arr.len);
3340 let a_data = std::slice::from_raw_parts(a_arr.data, len);
3341 let b_data = std::slice::from_raw_parts(b_arr.data, len);
3342
3343 let result = sigil_array_new(len as i64);
3345 let r_arr = &mut *(result as *mut SigilArray);
3346 r_arr.len = len;
3347 let r_data = std::slice::from_raw_parts_mut(r_arr.data, len);
3348
3349 for i in 0..(len / 4) {
3351 let base = i * 4;
3352 r_data[base] = a_data[base].wrapping_mul(b_data[base]);
3353 r_data[base + 1] = a_data[base + 1].wrapping_mul(b_data[base + 1]);
3354 r_data[base + 2] = a_data[base + 2].wrapping_mul(b_data[base + 2]);
3355 r_data[base + 3] = a_data[base + 3].wrapping_mul(b_data[base + 3]);
3356 }
3357
3358 for i in ((len / 4) * 4)..len {
3360 r_data[i] = a_data[i].wrapping_mul(b_data[i]);
3361 }
3362
3363 result
3364 }
3365 }
3366
3367 #[no_mangle]
3369 pub extern "C" fn sigil_array_min(arr_ptr: i64) -> i64 {
3370 unsafe {
3371 let arr = &*(arr_ptr as *const SigilArray);
3372 if arr.len == 0 {
3373 return 0;
3374 }
3375
3376 let data = std::slice::from_raw_parts(arr.data, arr.len);
3377
3378 let mut min0 = i64::MAX;
3380 let mut min1 = i64::MAX;
3381 let mut min2 = i64::MAX;
3382 let mut min3 = i64::MAX;
3383
3384 for chunk in data.chunks_exact(4) {
3385 min0 = min0.min(chunk[0]);
3386 min1 = min1.min(chunk[1]);
3387 min2 = min2.min(chunk[2]);
3388 min3 = min3.min(chunk[3]);
3389 }
3390
3391 let mut min_val = min0.min(min1).min(min2).min(min3);
3392
3393 let remainder_start = (data.len() / 4) * 4;
3395 for &v in &data[remainder_start..] {
3396 min_val = min_val.min(v);
3397 }
3398
3399 min_val
3400 }
3401 }
3402
3403 #[no_mangle]
3405 pub extern "C" fn sigil_array_max(arr_ptr: i64) -> i64 {
3406 unsafe {
3407 let arr = &*(arr_ptr as *const SigilArray);
3408 if arr.len == 0 {
3409 return 0;
3410 }
3411
3412 let data = std::slice::from_raw_parts(arr.data, arr.len);
3413
3414 let mut max0 = i64::MIN;
3416 let mut max1 = i64::MIN;
3417 let mut max2 = i64::MIN;
3418 let mut max3 = i64::MIN;
3419
3420 for chunk in data.chunks_exact(4) {
3421 max0 = max0.max(chunk[0]);
3422 max1 = max1.max(chunk[1]);
3423 max2 = max2.max(chunk[2]);
3424 max3 = max3.max(chunk[3]);
3425 }
3426
3427 let mut max_val = max0.max(max1).max(max2).max(max3);
3428
3429 let remainder_start = (data.len() / 4) * 4;
3431 for &v in &data[remainder_start..] {
3432 max_val = max_val.max(v);
3433 }
3434
3435 max_val
3436 }
3437 }
3438
3439 #[no_mangle]
3441 pub extern "C" fn sigil_array_fill(arr_ptr: i64, value: i64, count: i64) -> i64 {
3442 unsafe {
3443 let arr = &mut *(arr_ptr as *mut SigilArray);
3444 let n = count as usize;
3445
3446 while arr.len < n {
3448 sigil_array_push(arr_ptr, 0);
3449 }
3450
3451 let data = std::slice::from_raw_parts_mut(arr.data, n);
3452
3453 for chunk in data.chunks_exact_mut(4) {
3455 chunk[0] = value;
3456 chunk[1] = value;
3457 chunk[2] = value;
3458 chunk[3] = value;
3459 }
3460
3461 let remainder_start = (n / 4) * 4;
3463 for v in &mut data[remainder_start..] {
3464 *v = value;
3465 }
3466
3467 arr_ptr
3468 }
3469 }
3470
3471 #[no_mangle]
3478 pub extern "C" fn sigil_array_first(arr_ptr: i64) -> i64 {
3479 unsafe {
3480 let arr = &*(arr_ptr as *const SigilArray);
3481 if arr.len == 0 {
3482 return 0; }
3484 *arr.data
3485 }
3486 }
3487
3488 #[no_mangle]
3490 pub extern "C" fn sigil_array_last(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.add(arr.len - 1)
3497 }
3498 }
3499
3500 #[no_mangle]
3502 pub extern "C" fn sigil_array_middle(arr_ptr: i64) -> i64 {
3503 unsafe {
3504 let arr = &*(arr_ptr as *const SigilArray);
3505 if arr.len == 0 {
3506 return 0; }
3508 let mid = arr.len / 2;
3509 *arr.data.add(mid)
3510 }
3511 }
3512
3513 #[no_mangle]
3515 pub extern "C" fn sigil_array_choice(arr_ptr: i64) -> i64 {
3516 unsafe {
3517 let arr = &*(arr_ptr as *const SigilArray);
3518 if arr.len == 0 {
3519 return 0; }
3521 use std::time::{SystemTime, UNIX_EPOCH};
3523 let seed = SystemTime::now()
3524 .duration_since(UNIX_EPOCH)
3525 .map(|d| d.as_nanos() as u64)
3526 .unwrap_or(12345);
3527 let idx =
3528 ((seed.wrapping_mul(1103515245).wrapping_add(12345)) >> 16) as usize % arr.len;
3529 *arr.data.add(idx)
3530 }
3531 }
3532
3533 #[no_mangle]
3535 pub extern "C" fn sigil_array_nth(arr_ptr: i64, index: i64) -> i64 {
3536 sigil_array_get(arr_ptr, index)
3537 }
3538
3539 #[no_mangle]
3541 pub extern "C" fn sigil_array_next(arr_ptr: i64) -> i64 {
3542 sigil_array_first(arr_ptr)
3545 }
3546
3547 #[no_mangle]
3549 pub extern "C" fn sigil_array_product(arr_ptr: i64) -> i64 {
3550 unsafe {
3551 let arr = &*(arr_ptr as *const SigilArray);
3552 if arr.len == 0 {
3553 return 1; }
3555 let mut product: i64 = 1;
3556 for i in 0..arr.len {
3557 product = product.wrapping_mul(*arr.data.add(i));
3558 }
3559 product
3560 }
3561 }
3562
3563 #[no_mangle]
3565 pub extern "C" fn sigil_array_sort(arr_ptr: i64) -> i64 {
3566 unsafe {
3567 let arr = &*(arr_ptr as *const SigilArray);
3568 if arr.len == 0 {
3569 return sigil_array_new(0);
3570 }
3571
3572 let mut elements: Vec<i64> = Vec::with_capacity(arr.len);
3574 for i in 0..arr.len {
3575 elements.push(*arr.data.add(i));
3576 }
3577
3578 elements.sort();
3580
3581 let new_arr = sigil_array_new(arr.len as i64);
3583 for elem in elements {
3584 sigil_array_push(new_arr, elem);
3585 }
3586 new_arr
3587 }
3588 }
3589
3590 #[no_mangle]
3604 pub extern "C" fn sigil_parallel_map(arr_ptr: i64) -> i64 {
3605 arr_ptr
3608 }
3609
3610 #[no_mangle]
3613 pub extern "C" fn sigil_parallel_filter(arr_ptr: i64) -> i64 {
3614 arr_ptr
3620 }
3621
3622 #[no_mangle]
3625 pub extern "C" fn sigil_parallel_reduce(arr_ptr: i64) -> i64 {
3626 unsafe {
3629 let arr = &*(arr_ptr as *const SigilArray);
3630 if arr.len == 0 {
3631 return 0;
3632 }
3633
3634 let mut sum: i64 = 0;
3637 for i in 0..arr.len {
3638 sum += *arr.data.add(i);
3639 }
3640 sum
3641 }
3642 }
3643
3644 #[no_mangle]
3660 pub extern "C" fn sigil_gpu_map(arr_ptr: i64) -> i64 {
3661 arr_ptr
3668 }
3669
3670 #[no_mangle]
3673 pub extern "C" fn sigil_gpu_filter(arr_ptr: i64) -> i64 {
3674 arr_ptr
3677 }
3678
3679 #[no_mangle]
3682 pub extern "C" fn sigil_gpu_reduce(arr_ptr: i64) -> i64 {
3683 sigil_parallel_reduce(arr_ptr)
3685 }
3686
3687 #[repr(C)]
3694 struct MemoEntry {
3695 key1: i64, key2: i64, value: i64, occupied: bool, }
3700
3701 #[repr(C)]
3703 struct MemoCache {
3704 entries: *mut MemoEntry,
3705 capacity: usize,
3706 mask: usize, }
3708
3709 #[no_mangle]
3711 pub extern "C" fn sigil_memo_new(capacity: i64) -> i64 {
3712 let cap = (capacity as usize).next_power_of_two().max(1024);
3713 let layout = std::alloc::Layout::array::<MemoEntry>(cap).unwrap();
3714 let entries = unsafe {
3715 let ptr = std::alloc::alloc_zeroed(layout) as *mut MemoEntry;
3716 ptr
3717 };
3718
3719 let cache = Box::new(MemoCache {
3720 entries,
3721 capacity: cap,
3722 mask: cap - 1,
3723 });
3724 Box::into_raw(cache) as i64
3725 }
3726
3727 #[inline]
3729 fn memo_hash_1(key: i64) -> usize {
3730 let mut h = key as u64;
3732 h = h.wrapping_mul(0x517cc1b727220a95);
3733 h ^= h >> 32;
3734 h as usize
3735 }
3736
3737 #[inline]
3739 fn memo_hash_2(key1: i64, key2: i64) -> usize {
3740 let mut h = key1 as u64;
3741 h = h.wrapping_mul(0x517cc1b727220a95);
3742 h ^= key2 as u64;
3743 h = h.wrapping_mul(0x517cc1b727220a95);
3744 h ^= h >> 32;
3745 h as usize
3746 }
3747
3748 #[no_mangle]
3756 pub extern "C" fn sigil_ackermann(m: i64, n: i64) -> i64 {
3757 let mut stack: Vec<i64> = Vec::with_capacity(1024);
3759 stack.push(m);
3760 let mut n = n;
3761
3762 while let Some(m) = stack.pop() {
3763 if m == 0 {
3764 n = n + 1;
3765 } else if n == 0 {
3766 stack.push(m - 1);
3767 n = 1;
3768 } else {
3769 stack.push(m - 1);
3770 stack.push(m);
3771 n = n - 1;
3772 }
3773 }
3774 n
3775 }
3776
3777 #[no_mangle]
3779 pub extern "C" fn sigil_tak(x: i64, y: i64, z: i64) -> i64 {
3780 #[derive(Clone, Copy)]
3782 enum TakCont {
3783 Eval { x: i64, y: i64, z: i64 },
3784 Cont1 { y: i64, z: i64, x: i64 }, Cont2 { z: i64, x: i64, y: i64, r1: i64 }, Cont3 { r1: i64, r2: i64 }, }
3788
3789 let mut stack: Vec<TakCont> = Vec::with_capacity(256);
3790 stack.push(TakCont::Eval { x, y, z });
3791 let mut result: i64 = 0;
3792
3793 while let Some(cont) = stack.pop() {
3794 match cont {
3795 TakCont::Eval { x, y, z } => {
3796 if y >= x {
3797 result = z;
3798 } else {
3799 stack.push(TakCont::Cont1 { y, z, x });
3801 stack.push(TakCont::Eval { x: x - 1, y, z });
3802 }
3803 }
3804 TakCont::Cont1 { y, z, x } => {
3805 let r1 = result;
3806 stack.push(TakCont::Cont2 { z, x, y, r1 });
3807 stack.push(TakCont::Eval {
3808 x: y - 1,
3809 y: z,
3810 z: x,
3811 });
3812 }
3813 TakCont::Cont2 { z, x, y, r1 } => {
3814 let r2 = result;
3815 stack.push(TakCont::Cont3 { r1, r2 });
3816 stack.push(TakCont::Eval {
3817 x: z - 1,
3818 y: x,
3819 z: y,
3820 });
3821 }
3822 TakCont::Cont3 { r1, r2 } => {
3823 let r3 = result;
3824 stack.push(TakCont::Eval {
3826 x: r1,
3827 y: r2,
3828 z: r3,
3829 });
3830 }
3831 }
3832 }
3833 result
3834 }
3835
3836 const MEMO_NOT_FOUND: i64 = -9223372036854775807;
3839
3840 #[no_mangle]
3843 pub extern "C" fn sigil_memo_get_1(cache_ptr: i64, key: i64) -> i64 {
3844 unsafe {
3845 let cache = &*(cache_ptr as *const MemoCache);
3846 let mut idx = memo_hash_1(key) & cache.mask;
3847
3848 for _ in 0..32 {
3850 let entry = &*cache.entries.add(idx);
3851 if !entry.occupied {
3852 return MEMO_NOT_FOUND;
3853 }
3854 if entry.key1 == key {
3855 return entry.value;
3856 }
3857 idx = (idx + 1) & cache.mask;
3858 }
3859 MEMO_NOT_FOUND
3860 }
3861 }
3862
3863 #[no_mangle]
3865 pub extern "C" fn sigil_memo_set_1(cache_ptr: i64, key: i64, value: i64) {
3866 unsafe {
3867 let cache = &*(cache_ptr as *const MemoCache);
3868 let mut idx = memo_hash_1(key) & cache.mask;
3869
3870 for _ in 0..32 {
3872 let entry = &mut *cache.entries.add(idx);
3873 if !entry.occupied || entry.key1 == key {
3874 entry.key1 = key;
3875 entry.value = value;
3876 entry.occupied = true;
3877 return;
3878 }
3879 idx = (idx + 1) & cache.mask;
3880 }
3881 let entry = &mut *cache.entries.add(memo_hash_1(key) & cache.mask);
3883 entry.key1 = key;
3884 entry.value = value;
3885 entry.occupied = true;
3886 }
3887 }
3888
3889 #[no_mangle]
3891 pub extern "C" fn sigil_memo_get_2(cache_ptr: i64, key1: i64, key2: i64) -> i64 {
3892 unsafe {
3893 let cache = &*(cache_ptr as *const MemoCache);
3894 let mut idx = memo_hash_2(key1, key2) & cache.mask;
3895
3896 for _ in 0..32 {
3897 let entry = &*cache.entries.add(idx);
3898 if !entry.occupied {
3899 return MEMO_NOT_FOUND;
3900 }
3901 if entry.key1 == key1 && entry.key2 == key2 {
3902 return entry.value;
3903 }
3904 idx = (idx + 1) & cache.mask;
3905 }
3906 MEMO_NOT_FOUND
3907 }
3908 }
3909
3910 #[no_mangle]
3912 pub extern "C" fn sigil_memo_set_2(cache_ptr: i64, key1: i64, key2: i64, value: i64) {
3913 unsafe {
3914 let cache = &*(cache_ptr as *const MemoCache);
3915 let mut idx = memo_hash_2(key1, key2) & cache.mask;
3916
3917 for _ in 0..32 {
3918 let entry = &mut *cache.entries.add(idx);
3919 if !entry.occupied || (entry.key1 == key1 && entry.key2 == key2) {
3920 entry.key1 = key1;
3921 entry.key2 = key2;
3922 entry.value = value;
3923 entry.occupied = true;
3924 return;
3925 }
3926 idx = (idx + 1) & cache.mask;
3927 }
3928 let entry = &mut *cache.entries.add(memo_hash_2(key1, key2) & cache.mask);
3929 entry.key1 = key1;
3930 entry.key2 = key2;
3931 entry.value = value;
3932 entry.occupied = true;
3933 }
3934 }
3935
3936 #[no_mangle]
3938 pub extern "C" fn sigil_memo_free(cache_ptr: i64) {
3939 if cache_ptr != 0 {
3940 unsafe {
3941 let cache = Box::from_raw(cache_ptr as *mut MemoCache);
3942 let layout = std::alloc::Layout::array::<MemoEntry>(cache.capacity).unwrap();
3943 std::alloc::dealloc(cache.entries as *mut u8, layout);
3944 }
3945 }
3946 }
3947
3948 #[cfg(test)]
3953 mod tests {
3954 use super::*;
3955 use crate::parser::Parser;
3956
3957 #[test]
3958 fn test_extern_block_parsing_and_declaration() {
3959 let source = r#"
3960 extern "C" {
3961 rite abs(x: c_int) -> c_int;
3962 rite strlen(s: *const c_char) -> usize;
3963 }
3964
3965 rite main() -> i64 {
3966 42
3967 }
3968 "#;
3969
3970 let mut compiler = JitCompiler::new().unwrap();
3971 let result = compiler.compile(source);
3972 assert!(
3973 result.is_ok(),
3974 "Failed to compile FFI declarations: {:?}",
3975 result
3976 );
3977
3978 assert!(
3980 compiler.extern_functions.contains_key("abs"),
3981 "abs not declared"
3982 );
3983 assert!(
3984 compiler.extern_functions.contains_key("strlen"),
3985 "strlen not declared"
3986 );
3987
3988 let abs_sig = compiler.extern_functions.get("abs").unwrap();
3990 assert_eq!(abs_sig.params.len(), 1);
3991 assert_eq!(abs_sig.params[0], types::I32); assert_eq!(abs_sig.returns, Some(types::I32));
3993
3994 let strlen_sig = compiler.extern_functions.get("strlen").unwrap();
3996 assert_eq!(strlen_sig.params.len(), 1);
3997 assert_eq!(strlen_sig.params[0], types::I64); assert_eq!(strlen_sig.returns, Some(types::I64)); }
4000
4001 #[test]
4002 fn test_extern_variadic_function() {
4003 let source = r#"
4004 extern "C" {
4005 rite printf(fmt: *const c_char, ...) -> c_int;
4006 }
4007
4008 rite main() -> i64 {
4009 0
4010 }
4011 "#;
4012
4013 let mut compiler = JitCompiler::new().unwrap();
4014 let result = compiler.compile(source);
4015 assert!(
4016 result.is_ok(),
4017 "Failed to compile variadic FFI: {:?}",
4018 result
4019 );
4020
4021 let printf_sig = compiler.extern_functions.get("printf").unwrap();
4022 assert!(printf_sig.variadic, "printf should be variadic");
4023 }
4024
4025 #[test]
4026 fn test_extern_c_abi_only() {
4027 let source = r#"
4028 extern "Rust" {
4029 rite some_func(x: i32) -> i32;
4030 }
4031
4032 rite main() -> i64 {
4033 0
4034 }
4035 "#;
4036
4037 let mut compiler = JitCompiler::new().unwrap();
4038 let result = compiler.compile(source);
4039 assert!(result.is_err(), "Should reject non-C ABI");
4040 assert!(result.unwrap_err().contains("Unsupported ABI"));
4041 }
4042
4043 #[test]
4044 fn test_c_type_mapping() {
4045 let test_cases = vec![
4047 ("c_char", types::I8),
4048 ("c_int", types::I32),
4049 ("c_long", types::I64),
4050 ("c_float", types::F32),
4051 ("c_double", types::F64),
4052 ("size_t", types::I64),
4053 ("i32", types::I32),
4054 ("f64", types::F64),
4055 ];
4056
4057 for (type_name, expected_cl_type) in test_cases {
4058 let source = format!(
4059 r#"
4060 extern "C" {{
4061 rite test_func(x: {}) -> {};
4062 }}
4063
4064 rite main() -> i64 {{ 0 }}
4065 "#,
4066 type_name, type_name
4067 );
4068
4069 let mut compiler = JitCompiler::new().unwrap();
4070 let result = compiler.compile(&source);
4071 assert!(
4072 result.is_ok(),
4073 "Failed for type {}: {:?}",
4074 type_name,
4075 result
4076 );
4077
4078 let sig = compiler.extern_functions.get("test_func").unwrap();
4079 assert_eq!(
4080 sig.params[0], expected_cl_type,
4081 "Wrong param type for {}",
4082 type_name
4083 );
4084 assert_eq!(
4085 sig.returns,
4086 Some(expected_cl_type),
4087 "Wrong return type for {}",
4088 type_name
4089 );
4090 }
4091 }
4092 }
4093}
4094
4095#[cfg(feature = "jit")]
4097pub use jit::JitCompiler;