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