From 080bedec69af2a7c06cecc6d48b10d1431943a7a Mon Sep 17 00:00:00 2001 From: Jordan Mecom Date: Sat, 27 Dec 2025 21:54:07 -0500 Subject: [PATCH 1/2] Add intrinsic registry and implement string starts_with --- capc/src/codegen/intrinsics.rs | 1085 ++++++++++++++++++++++++++++++++ capc/src/codegen/mod.rs | 1081 +------------------------------ stdlib/sys/string.cap | 20 +- 3 files changed, 1106 insertions(+), 1080 deletions(-) create mode 100644 capc/src/codegen/intrinsics.rs diff --git a/capc/src/codegen/intrinsics.rs b/capc/src/codegen/intrinsics.rs new file mode 100644 index 0000000..8c9f047 --- /dev/null +++ b/capc/src/codegen/intrinsics.rs @@ -0,0 +1,1085 @@ +//! Runtime intrinsic registry. +//! +//! Any stdlib function listed here is treated as an intrinsic: its `.cap` body +//! is ignored, and codegen emits a direct call to the runtime symbol. If a +//! function is not listed here, the Capable implementation is used instead. + +use std::collections::HashMap; + +use cranelift_codegen::ir::Type; + +use crate::abi::AbiType; + +use super::{FnInfo, FnSig}; + +pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { + let mut map = HashMap::new(); + let system_console = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let system_fs_read = FnSig { + params: vec![AbiType::Handle, AbiType::String], + ret: AbiType::Handle, + }; + let system_filesystem = FnSig { + params: vec![AbiType::Handle, AbiType::String], + ret: AbiType::Handle, + }; + let fs_root_dir = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let fs_subdir = FnSig { + params: vec![AbiType::Handle, AbiType::String], + ret: AbiType::Handle, + }; + let fs_open_read = FnSig { + params: vec![AbiType::Handle, AbiType::String], + ret: AbiType::Handle, + }; + let fs_read_to_string = FnSig { + params: vec![AbiType::Handle, AbiType::String], + ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), + }; + let fs_read_to_string_abi = FnSig { + params: vec![AbiType::Handle, AbiType::String, AbiType::ResultString], + ret: AbiType::ResultString, + }; + let fs_file_read_to_string = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), + }; + let fs_file_read_to_string_abi = FnSig { + params: vec![AbiType::Handle, AbiType::ResultString], + ret: AbiType::ResultString, + }; + let console_println = FnSig { + params: vec![AbiType::Handle, AbiType::String], + ret: AbiType::Unit, + }; + let console_print = FnSig { + params: vec![AbiType::Handle, AbiType::String], + ret: AbiType::Unit, + }; + let console_print_i32 = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::Unit, + }; + let math_i32 = FnSig { + params: vec![AbiType::I32, AbiType::I32], + ret: AbiType::I32, + }; + let math_u32 = FnSig { + params: vec![AbiType::U32, AbiType::U32], + ret: AbiType::U32, + }; + let math_u8 = FnSig { + params: vec![AbiType::U8, AbiType::U8], + ret: AbiType::U8, + }; + let mem_malloc = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::Ptr, + }; + let mem_free = FnSig { + params: vec![AbiType::Handle, AbiType::Ptr], + ret: AbiType::Unit, + }; + let mem_cast = FnSig { + params: vec![AbiType::Handle, AbiType::Ptr], + ret: AbiType::Ptr, + }; + let mem_alloc_default = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let system_mint_args = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let system_mint_stdin = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let args_at = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), + }; + let args_at_abi = FnSig { + params: vec![AbiType::Handle, AbiType::I32, AbiType::ResultString], + ret: AbiType::ResultString, + }; + let mem_slice_from_ptr = FnSig { + params: vec![AbiType::Handle, AbiType::Ptr, AbiType::I32], + ret: AbiType::Handle, + }; + let mem_slice_len = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::I32, + }; + let mem_slice_at = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::U8, + }; + let mem_buffer_new = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::Result(Box::new(AbiType::Handle), Box::new(AbiType::I32)), + }; + let mem_buffer_new_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::I32, + AbiType::ResultOut(Box::new(AbiType::Handle), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::Handle), Box::new(AbiType::I32)), + }; + let mem_buffer_len = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::I32, + }; + let mem_buffer_push = FnSig { + params: vec![AbiType::Handle, AbiType::U8], + ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let mem_buffer_push_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::U8, + AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let mem_buffer_as_slice = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let mem_buffer_as_mut_slice = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let mem_buffer_free = FnSig { + params: vec![AbiType::Handle, AbiType::Handle], + ret: AbiType::Unit, + }; + let vec_new = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let vec_u8_get = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::Result(Box::new(AbiType::U8), Box::new(AbiType::I32)), + }; + let vec_u8_get_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::I32, + AbiType::ResultOut(Box::new(AbiType::U8), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::U8), Box::new(AbiType::I32)), + }; + let vec_u8_set = FnSig { + params: vec![AbiType::Handle, AbiType::I32, AbiType::U8], + ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_u8_set_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::I32, + AbiType::U8, + AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_u8_push = FnSig { + params: vec![AbiType::Handle, AbiType::U8], + ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_u8_push_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::U8, + AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_u8_pop = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Result(Box::new(AbiType::U8), Box::new(AbiType::I32)), + }; + let vec_u8_pop_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::ResultOut(Box::new(AbiType::U8), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::U8), Box::new(AbiType::I32)), + }; + let vec_u8_as_slice = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Handle, + }; + let vec_u8_free = FnSig { + params: vec![AbiType::Handle, AbiType::Handle], + ret: AbiType::Unit, + }; + let vec_i32_get = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::Result(Box::new(AbiType::I32), Box::new(AbiType::I32)), + }; + let vec_i32_get_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::I32, + AbiType::ResultOut(Box::new(AbiType::I32), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::I32), Box::new(AbiType::I32)), + }; + let vec_i32_set = FnSig { + params: vec![AbiType::Handle, AbiType::I32, AbiType::I32], + ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_i32_set_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::I32, + AbiType::I32, + AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_i32_push = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_i32_push_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::I32, + AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_i32_pop = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Result(Box::new(AbiType::I32), Box::new(AbiType::I32)), + }; + let vec_i32_pop_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::ResultOut(Box::new(AbiType::I32), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::I32), Box::new(AbiType::I32)), + }; + let vec_i32_free = FnSig { + params: vec![AbiType::Handle, AbiType::Handle], + ret: AbiType::Unit, + }; + let vec_string_len = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::I32, + }; + let vec_string_get = FnSig { + params: vec![AbiType::Handle, AbiType::I32], + ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), + }; + let vec_string_get_abi = FnSig { + params: vec![AbiType::Handle, AbiType::I32, AbiType::ResultString], + ret: AbiType::ResultString, + }; + let vec_string_push = FnSig { + params: vec![AbiType::Handle, AbiType::String], + ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_string_push_abi = FnSig { + params: vec![ + AbiType::Handle, + AbiType::String, + AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + ], + ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), + }; + let vec_string_pop = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), + }; + let vec_string_pop_abi = FnSig { + params: vec![AbiType::Handle, AbiType::ResultString], + ret: AbiType::ResultString, + }; + let vec_string_free = FnSig { + params: vec![AbiType::Handle, AbiType::Handle], + ret: AbiType::Unit, + }; + let string_len = FnSig { + params: vec![AbiType::String], + ret: AbiType::I32, + }; + let string_byte_at = FnSig { + params: vec![AbiType::String, AbiType::I32], + ret: AbiType::U8, + }; + let string_as_slice = FnSig { + params: vec![AbiType::String], + ret: AbiType::Handle, + }; + let string_split = FnSig { + params: vec![AbiType::String], + ret: AbiType::Handle, + }; + let string_lines = FnSig { + params: vec![AbiType::String], + ret: AbiType::Handle, + }; + let string_split_delim = FnSig { + params: vec![AbiType::String, AbiType::U8], + ret: AbiType::Handle, + }; + let vec_u8_len = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::I32, + }; + let vec_i32_len = FnSig { + params: vec![AbiType::Handle], + ret: AbiType::I32, + }; + + map.insert( + "sys.system.RootCap__mint_console".to_string(), + FnInfo { + sig: system_console, + abi_sig: None, + symbol: "capable_rt_mint_console".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.system.RootCap__mint_readfs".to_string(), + FnInfo { + sig: system_fs_read, + abi_sig: None, + symbol: "capable_rt_mint_readfs".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.system.RootCap__mint_filesystem".to_string(), + FnInfo { + sig: system_filesystem, + abi_sig: None, + symbol: "capable_rt_mint_filesystem".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.system.RootCap__mint_args".to_string(), + FnInfo { + sig: system_mint_args, + abi_sig: None, + symbol: "capable_rt_mint_args".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.system.RootCap__mint_stdin".to_string(), + FnInfo { + sig: system_mint_stdin, + abi_sig: None, + symbol: "capable_rt_mint_stdin".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.args.Args__len".to_string(), + FnInfo { + sig: FnSig { + params: vec![AbiType::Handle], + ret: AbiType::I32, + }, + abi_sig: None, + symbol: "capable_rt_args_len".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.args.Args__at".to_string(), + FnInfo { + sig: args_at, + abi_sig: Some(args_at_abi), + symbol: "capable_rt_args_at".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.stdin.Stdin__read_to_string".to_string(), + FnInfo { + sig: FnSig { + params: vec![AbiType::Handle], + ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), + }, + abi_sig: Some(FnSig { + params: vec![AbiType::Handle, AbiType::ResultString], + ret: AbiType::ResultString, + }), + symbol: "capable_rt_read_stdin_to_string".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.system.RootCap__mint_alloc_default".to_string(), + FnInfo { + sig: mem_alloc_default, + abi_sig: None, + symbol: "capable_rt_alloc_default".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.console.Console__println".to_string(), + FnInfo { + sig: console_println, + abi_sig: None, + symbol: "capable_rt_console_println".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.console.Console__print".to_string(), + FnInfo { + sig: console_print, + abi_sig: None, + symbol: "capable_rt_console_print".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.console.Console__print_i32".to_string(), + FnInfo { + sig: console_print_i32.clone(), + abi_sig: None, + symbol: "capable_rt_console_print_i32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.console.Console__println_i32".to_string(), + FnInfo { + sig: console_print_i32, + abi_sig: None, + symbol: "capable_rt_console_println_i32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.console.Console__assert".to_string(), + FnInfo { + sig: FnSig { + params: vec![AbiType::Handle, AbiType::Bool, AbiType::String], + ret: AbiType::Unit, + }, + abi_sig: None, + symbol: "capable_rt_assert".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.add_wrap_i32".to_string(), + FnInfo { + sig: math_i32.clone(), + abi_sig: None, + symbol: "capable_rt_math_add_wrap_i32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.sub_wrap_i32".to_string(), + FnInfo { + sig: math_i32.clone(), + abi_sig: None, + symbol: "capable_rt_math_sub_wrap_i32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.mul_wrap_i32".to_string(), + FnInfo { + sig: math_i32, + abi_sig: None, + symbol: "capable_rt_math_mul_wrap_i32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.add_wrap_u32".to_string(), + FnInfo { + sig: math_u32.clone(), + abi_sig: None, + symbol: "capable_rt_math_add_wrap_u32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.sub_wrap_u32".to_string(), + FnInfo { + sig: math_u32.clone(), + abi_sig: None, + symbol: "capable_rt_math_sub_wrap_u32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.mul_wrap_u32".to_string(), + FnInfo { + sig: math_u32, + abi_sig: None, + symbol: "capable_rt_math_mul_wrap_u32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.add_wrap_u8".to_string(), + FnInfo { + sig: math_u8.clone(), + abi_sig: None, + symbol: "capable_rt_math_add_wrap_u8".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.sub_wrap_u8".to_string(), + FnInfo { + sig: math_u8.clone(), + abi_sig: None, + symbol: "capable_rt_math_sub_wrap_u8".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.math.mul_wrap_u8".to_string(), + FnInfo { + sig: math_u8, + abi_sig: None, + symbol: "capable_rt_math_mul_wrap_u8".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.fs.ReadFS__read_to_string".to_string(), + FnInfo { + sig: fs_read_to_string, + abi_sig: Some(fs_read_to_string_abi), + symbol: "capable_rt_fs_read_to_string".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.fs.Filesystem__root_dir".to_string(), + FnInfo { + sig: fs_root_dir, + abi_sig: None, + symbol: "capable_rt_fs_root_dir".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.fs.Dir__subdir".to_string(), + FnInfo { + sig: fs_subdir, + abi_sig: None, + symbol: "capable_rt_fs_subdir".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.fs.Dir__open_read".to_string(), + FnInfo { + sig: fs_open_read, + abi_sig: None, + symbol: "capable_rt_fs_open_read".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.fs.FileRead__read_to_string".to_string(), + FnInfo { + sig: fs_file_read_to_string, + abi_sig: Some(fs_file_read_to_string_abi), + symbol: "capable_rt_fs_file_read_to_string".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__buffer_new".to_string(), + FnInfo { + sig: mem_buffer_new, + abi_sig: Some(mem_buffer_new_abi), + symbol: "capable_rt_buffer_new".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__buffer_free".to_string(), + FnInfo { + sig: mem_buffer_free, + abi_sig: None, + symbol: "capable_rt_buffer_free".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__malloc".to_string(), + FnInfo { + sig: mem_malloc, + abi_sig: None, + symbol: "capable_rt_malloc".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__free".to_string(), + FnInfo { + sig: mem_free, + abi_sig: None, + symbol: "capable_rt_free".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__cast_u8_to_u32".to_string(), + FnInfo { + sig: mem_cast.clone(), + abi_sig: None, + symbol: "capable_rt_cast_u8_to_u32".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__cast_u32_to_u8".to_string(), + FnInfo { + sig: mem_cast, + abi_sig: None, + symbol: "capable_rt_cast_u32_to_u8".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__slice_from_ptr".to_string(), + FnInfo { + sig: mem_slice_from_ptr.clone(), + abi_sig: None, + symbol: "capable_rt_slice_from_ptr".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__mut_slice_from_ptr".to_string(), + FnInfo { + sig: mem_slice_from_ptr, + abi_sig: None, + symbol: "capable_rt_mut_slice_from_ptr".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Buffer__len".to_string(), + FnInfo { + sig: mem_buffer_len, + abi_sig: None, + symbol: "capable_rt_buffer_len".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Buffer__push".to_string(), + FnInfo { + sig: mem_buffer_push, + abi_sig: Some(mem_buffer_push_abi), + symbol: "capable_rt_buffer_push".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Buffer__as_slice".to_string(), + FnInfo { + sig: mem_buffer_as_slice, + abi_sig: None, + symbol: "capable_rt_buffer_as_slice".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Buffer__as_mut_slice".to_string(), + FnInfo { + sig: mem_buffer_as_mut_slice, + abi_sig: None, + symbol: "capable_rt_buffer_as_mut_slice".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Slice__len".to_string(), + FnInfo { + sig: mem_slice_len, + abi_sig: None, + symbol: "capable_rt_slice_len".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Slice__at".to_string(), + FnInfo { + sig: mem_slice_at.clone(), + abi_sig: None, + symbol: "capable_rt_slice_at".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.MutSlice__at".to_string(), + FnInfo { + sig: mem_slice_at, + abi_sig: None, + symbol: "capable_rt_mut_slice_at".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__vec_u8_new".to_string(), + FnInfo { + sig: vec_new.clone(), + abi_sig: None, + symbol: "capable_rt_vec_u8_new".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__vec_u8_free".to_string(), + FnInfo { + sig: vec_u8_free, + abi_sig: None, + symbol: "capable_rt_vec_u8_free".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__vec_i32_new".to_string(), + FnInfo { + sig: vec_new.clone(), + abi_sig: None, + symbol: "capable_rt_vec_i32_new".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__vec_i32_free".to_string(), + FnInfo { + sig: vec_i32_free, + abi_sig: None, + symbol: "capable_rt_vec_i32_free".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__vec_string_new".to_string(), + FnInfo { + sig: vec_new, + abi_sig: None, + symbol: "capable_rt_vec_string_new".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.buffer.Alloc__vec_string_free".to_string(), + FnInfo { + sig: vec_string_free, + abi_sig: None, + symbol: "capable_rt_vec_string_free".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecU8__len".to_string(), + FnInfo { + sig: vec_u8_len, + abi_sig: None, + symbol: "capable_rt_vec_u8_len".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecU8__get".to_string(), + FnInfo { + sig: vec_u8_get, + abi_sig: Some(vec_u8_get_abi), + symbol: "capable_rt_vec_u8_get".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecU8__set".to_string(), + FnInfo { + sig: vec_u8_set, + abi_sig: Some(vec_u8_set_abi), + symbol: "capable_rt_vec_u8_set".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecU8__push".to_string(), + FnInfo { + sig: vec_u8_push, + abi_sig: Some(vec_u8_push_abi), + symbol: "capable_rt_vec_u8_push".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecU8__pop".to_string(), + FnInfo { + sig: vec_u8_pop, + abi_sig: Some(vec_u8_pop_abi), + symbol: "capable_rt_vec_u8_pop".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecU8__as_slice".to_string(), + FnInfo { + sig: vec_u8_as_slice, + abi_sig: None, + symbol: "capable_rt_vec_u8_as_slice".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecI32__len".to_string(), + FnInfo { + sig: vec_i32_len, + abi_sig: None, + symbol: "capable_rt_vec_i32_len".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecI32__get".to_string(), + FnInfo { + sig: vec_i32_get, + abi_sig: Some(vec_i32_get_abi), + symbol: "capable_rt_vec_i32_get".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecI32__set".to_string(), + FnInfo { + sig: vec_i32_set, + abi_sig: Some(vec_i32_set_abi), + symbol: "capable_rt_vec_i32_set".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecI32__push".to_string(), + FnInfo { + sig: vec_i32_push, + abi_sig: Some(vec_i32_push_abi), + symbol: "capable_rt_vec_i32_push".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecI32__pop".to_string(), + FnInfo { + sig: vec_i32_pop, + abi_sig: Some(vec_i32_pop_abi), + symbol: "capable_rt_vec_i32_pop".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecString__len".to_string(), + FnInfo { + sig: vec_string_len, + abi_sig: None, + symbol: "capable_rt_vec_string_len".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecString__get".to_string(), + FnInfo { + sig: vec_string_get, + abi_sig: Some(vec_string_get_abi), + symbol: "capable_rt_vec_string_get".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecString__push".to_string(), + FnInfo { + sig: vec_string_push, + abi_sig: Some(vec_string_push_abi), + symbol: "capable_rt_vec_string_push".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.vec.VecString__pop".to_string(), + FnInfo { + sig: vec_string_pop, + abi_sig: Some(vec_string_pop_abi), + symbol: "capable_rt_vec_string_pop".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.string.string__len".to_string(), + FnInfo { + sig: string_len, + abi_sig: None, + symbol: "capable_rt_string_len".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.string.string__byte_at".to_string(), + FnInfo { + sig: string_byte_at, + abi_sig: None, + symbol: "capable_rt_string_byte_at".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.string.string__as_slice".to_string(), + FnInfo { + sig: string_as_slice.clone(), + abi_sig: None, + symbol: "capable_rt_string_as_slice".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.string.string__bytes".to_string(), + FnInfo { + // bytes() is an alias for as_slice(); both map to the same runtime symbol. + sig: string_as_slice, + abi_sig: None, + symbol: "capable_rt_string_as_slice".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.string.string__split_whitespace".to_string(), + FnInfo { + sig: string_split, + abi_sig: None, + symbol: "capable_rt_string_split_whitespace".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.string.string__lines".to_string(), + FnInfo { + sig: string_lines, + abi_sig: None, + symbol: "capable_rt_string_split_lines".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.string.string__split".to_string(), + FnInfo { + sig: string_split_delim, + abi_sig: None, + symbol: "capable_rt_string_split".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + map.insert( + "sys.bytes.u8__is_whitespace".to_string(), + FnInfo { + sig: FnSig { + params: vec![AbiType::U8], + ret: AbiType::Bool, + }, + abi_sig: None, + symbol: "capable_rt_bytes_is_whitespace".to_string(), + runtime_symbol: None, + is_runtime: true, + }, + ); + + let _ = ptr_ty; + map +} diff --git a/capc/src/codegen/mod.rs b/capc/src/codegen/mod.rs index 2ea8d83..7f8e23a 100644 --- a/capc/src/codegen/mod.rs +++ b/capc/src/codegen/mod.rs @@ -23,6 +23,7 @@ use miette::{Diagnostic, SourceSpan}; use thiserror::Error; mod emit; +mod intrinsics; mod layout; use emit::{emit_hir_stmt, emit_runtime_wrapper_call, flatten_value, store_local, value_from_params}; @@ -433,1085 +434,7 @@ fn append_ty_returns(signature: &mut Signature, ty: &AbiType, ptr_ty: Type) { } fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { - let mut map = HashMap::new(); - let system_console = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Handle, - }; - let system_fs_read = FnSig { - params: vec![AbiType::Handle, AbiType::String], - ret: AbiType::Handle, - }; - let system_filesystem = FnSig { - params: vec![AbiType::Handle, AbiType::String], - ret: AbiType::Handle, - }; - let fs_root_dir = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Handle, - }; - let fs_subdir = FnSig { - params: vec![AbiType::Handle, AbiType::String], - ret: AbiType::Handle, - }; - let fs_open_read = FnSig { - params: vec![AbiType::Handle, AbiType::String], - ret: AbiType::Handle, - }; - let fs_read_to_string = FnSig { - params: vec![AbiType::Handle, AbiType::String], - ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), - }; - let fs_read_to_string_abi = FnSig { - params: vec![AbiType::Handle, AbiType::String, AbiType::ResultString], - ret: AbiType::ResultString, - }; - let fs_file_read_to_string = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), - }; - let fs_file_read_to_string_abi = FnSig { - params: vec![AbiType::Handle, AbiType::ResultString], - ret: AbiType::ResultString, - }; - let console_println = FnSig { - params: vec![AbiType::Handle, AbiType::String], - ret: AbiType::Unit, - }; - let console_print = FnSig { - params: vec![AbiType::Handle, AbiType::String], - ret: AbiType::Unit, - }; - let console_print_i32 = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::Unit, - }; - let math_i32 = FnSig { - params: vec![AbiType::I32, AbiType::I32], - ret: AbiType::I32, - }; - let math_u32 = FnSig { - params: vec![AbiType::U32, AbiType::U32], - ret: AbiType::U32, - }; - let math_u8 = FnSig { - params: vec![AbiType::U8, AbiType::U8], - ret: AbiType::U8, - }; - let mem_malloc = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::Ptr, - }; - let mem_free = FnSig { - params: vec![AbiType::Handle, AbiType::Ptr], - ret: AbiType::Unit, - }; - let mem_cast = FnSig { - params: vec![AbiType::Handle, AbiType::Ptr], - ret: AbiType::Ptr, - }; - let mem_alloc_default = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Handle, - }; - let system_mint_args = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Handle, - }; - let system_mint_stdin = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Handle, - }; - let mem_slice_from_ptr = FnSig { - params: vec![AbiType::Handle, AbiType::Ptr, AbiType::I32], - ret: AbiType::Handle, - }; - let mem_slice_len = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::I32, - }; - let mem_slice_at = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::U8, - }; - let mem_buffer_new = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::Result(Box::new(AbiType::Handle), Box::new(AbiType::I32)), - }; - let mem_buffer_new_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::I32, - AbiType::ResultOut(Box::new(AbiType::Handle), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::Handle), Box::new(AbiType::I32)), - }; - let mem_buffer_len = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::I32, - }; - let mem_buffer_push = FnSig { - params: vec![AbiType::Handle, AbiType::U8], - ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let mem_buffer_push_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::U8, - AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let mem_buffer_free = FnSig { - params: vec![AbiType::Handle, AbiType::Handle], - ret: AbiType::Unit, - }; - let mem_buffer_as_slice = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Handle, - }; - let args_len = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::I32, - }; - let args_at = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), - }; - let args_at_abi = FnSig { - params: vec![AbiType::Handle, AbiType::I32, AbiType::ResultString], - ret: AbiType::ResultString, - }; - let io_read_stdin = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), - }; - let io_read_stdin_abi = FnSig { - params: vec![AbiType::Handle, AbiType::ResultString], - ret: AbiType::ResultString, - }; - let console_assert = FnSig { - params: vec![AbiType::Handle, AbiType::Bool], - ret: AbiType::Unit, - }; - let string_len = FnSig { - params: vec![AbiType::String], - ret: AbiType::I32, - }; - let string_byte_at = FnSig { - params: vec![AbiType::String, AbiType::I32], - ret: AbiType::U8, - }; - let string_as_slice = FnSig { - params: vec![AbiType::String], - ret: AbiType::Handle, - }; - let string_split = FnSig { - params: vec![AbiType::String], - ret: AbiType::Handle, - }; - let string_lines = FnSig { - params: vec![AbiType::String], - ret: AbiType::Handle, - }; - let string_split_delim = FnSig { - params: vec![AbiType::String, AbiType::U8], - ret: AbiType::Handle, - }; - let string_starts_with = FnSig { - params: vec![AbiType::String, AbiType::String], - ret: AbiType::Bool, - }; - let vec_new = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Handle, - }; - let vec_len = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::I32, - }; - let vec_u8_get = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::Result(Box::new(AbiType::U8), Box::new(AbiType::I32)), - }; - let vec_u8_get_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::I32, - AbiType::ResultOut(Box::new(AbiType::U8), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::U8), Box::new(AbiType::I32)), - }; - let vec_u8_set = FnSig { - params: vec![AbiType::Handle, AbiType::I32, AbiType::U8], - ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_u8_set_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::I32, - AbiType::U8, - AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_u8_push = FnSig { - params: vec![AbiType::Handle, AbiType::U8], - ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_u8_push_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::U8, - AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_u8_pop = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Result(Box::new(AbiType::U8), Box::new(AbiType::I32)), - }; - let vec_u8_pop_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::ResultOut(Box::new(AbiType::U8), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::U8), Box::new(AbiType::I32)), - }; - let vec_u8_as_slice = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Handle, - }; - let vec_u8_free = FnSig { - params: vec![AbiType::Handle, AbiType::Handle], - ret: AbiType::Unit, - }; - let vec_i32_get = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::Result(Box::new(AbiType::I32), Box::new(AbiType::I32)), - }; - let vec_i32_get_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::I32, - AbiType::ResultOut(Box::new(AbiType::I32), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::I32), Box::new(AbiType::I32)), - }; - let vec_i32_set = FnSig { - params: vec![AbiType::Handle, AbiType::I32, AbiType::I32], - ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_i32_set_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::I32, - AbiType::I32, - AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_i32_push = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_i32_push_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::I32, - AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_i32_pop = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Result(Box::new(AbiType::I32), Box::new(AbiType::I32)), - }; - let vec_i32_pop_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::ResultOut(Box::new(AbiType::I32), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::I32), Box::new(AbiType::I32)), - }; - let vec_i32_free = FnSig { - params: vec![AbiType::Handle, AbiType::Handle], - ret: AbiType::Unit, - }; - let vec_string_len = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::I32, - }; - let vec_string_get = FnSig { - params: vec![AbiType::Handle, AbiType::I32], - ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), - }; - let vec_string_get_abi = FnSig { - params: vec![AbiType::Handle, AbiType::I32, AbiType::ResultString], - ret: AbiType::ResultString, - }; - let vec_string_push = FnSig { - params: vec![AbiType::Handle, AbiType::String], - ret: AbiType::Result(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_string_push_abi = FnSig { - params: vec![ - AbiType::Handle, - AbiType::String, - AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - ], - ret: AbiType::ResultOut(Box::new(AbiType::Unit), Box::new(AbiType::I32)), - }; - let vec_string_pop = FnSig { - params: vec![AbiType::Handle], - ret: AbiType::Result(Box::new(AbiType::String), Box::new(AbiType::I32)), - }; - let vec_string_pop_abi = FnSig { - params: vec![AbiType::Handle, AbiType::ResultString], - ret: AbiType::ResultString, - }; - let vec_string_free = FnSig { - params: vec![AbiType::Handle, AbiType::Handle], - ret: AbiType::Unit, - }; - - map.insert( - "sys.system.RootCap__mint_console".to_string(), - FnInfo { - sig: system_console.clone(), - abi_sig: None, - symbol: "capable_rt_mint_console".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.system.RootCap__mint_readfs".to_string(), - FnInfo { - sig: system_fs_read.clone(), - abi_sig: None, - symbol: "capable_rt_mint_readfs".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.system.RootCap__mint_filesystem".to_string(), - FnInfo { - sig: system_filesystem, - abi_sig: None, - symbol: "capable_rt_mint_filesystem".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.system.RootCap__mint_args".to_string(), - FnInfo { - sig: system_mint_args, - abi_sig: None, - symbol: "capable_rt_mint_args".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.system.RootCap__mint_stdin".to_string(), - FnInfo { - sig: system_mint_stdin, - abi_sig: None, - symbol: "capable_rt_mint_stdin".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.args.Args__len".to_string(), - FnInfo { - sig: args_len, - abi_sig: None, - symbol: "capable_rt_args_len".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.args.Args__at".to_string(), - FnInfo { - sig: args_at, - abi_sig: Some(args_at_abi), - symbol: "capable_rt_args_at".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.stdin.Stdin__read_to_string".to_string(), - FnInfo { - sig: io_read_stdin, - abi_sig: Some(io_read_stdin_abi), - symbol: "capable_rt_read_stdin_to_string".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.system.RootCap__mint_alloc_default".to_string(), - FnInfo { - sig: mem_alloc_default.clone(), - abi_sig: None, - symbol: "capable_rt_alloc_default".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.console.Console__println".to_string(), - FnInfo { - sig: console_println, - abi_sig: None, - symbol: "capable_rt_console_println".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.console.Console__print".to_string(), - FnInfo { - sig: console_print, - abi_sig: None, - symbol: "capable_rt_console_print".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.console.Console__print_i32".to_string(), - FnInfo { - sig: console_print_i32.clone(), - abi_sig: None, - symbol: "capable_rt_console_print_i32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.console.Console__println_i32".to_string(), - FnInfo { - sig: console_print_i32, - abi_sig: None, - symbol: "capable_rt_console_println_i32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.console.Console__assert".to_string(), - FnInfo { - sig: console_assert, - abi_sig: None, - symbol: "capable_rt_assert".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.add_wrap_i32".to_string(), - FnInfo { - sig: math_i32.clone(), - abi_sig: None, - symbol: "capable_rt_math_add_wrap_i32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.sub_wrap_i32".to_string(), - FnInfo { - sig: math_i32.clone(), - abi_sig: None, - symbol: "capable_rt_math_sub_wrap_i32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.mul_wrap_i32".to_string(), - FnInfo { - sig: math_i32, - abi_sig: None, - symbol: "capable_rt_math_mul_wrap_i32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.add_wrap_u32".to_string(), - FnInfo { - sig: math_u32.clone(), - abi_sig: None, - symbol: "capable_rt_math_add_wrap_u32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.sub_wrap_u32".to_string(), - FnInfo { - sig: math_u32.clone(), - abi_sig: None, - symbol: "capable_rt_math_sub_wrap_u32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.mul_wrap_u32".to_string(), - FnInfo { - sig: math_u32, - abi_sig: None, - symbol: "capable_rt_math_mul_wrap_u32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.add_wrap_u8".to_string(), - FnInfo { - sig: math_u8.clone(), - abi_sig: None, - symbol: "capable_rt_math_add_wrap_u8".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.sub_wrap_u8".to_string(), - FnInfo { - sig: math_u8.clone(), - abi_sig: None, - symbol: "capable_rt_math_sub_wrap_u8".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.math.mul_wrap_u8".to_string(), - FnInfo { - sig: math_u8, - abi_sig: None, - symbol: "capable_rt_math_mul_wrap_u8".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.fs.ReadFS__read_to_string".to_string(), - FnInfo { - sig: fs_read_to_string, - abi_sig: Some(fs_read_to_string_abi), - symbol: "capable_rt_fs_read_to_string".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.fs.Filesystem__root_dir".to_string(), - FnInfo { - sig: fs_root_dir, - abi_sig: None, - symbol: "capable_rt_fs_root_dir".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.fs.Dir__subdir".to_string(), - FnInfo { - sig: fs_subdir, - abi_sig: None, - symbol: "capable_rt_fs_subdir".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.fs.Dir__open_read".to_string(), - FnInfo { - sig: fs_open_read, - abi_sig: None, - symbol: "capable_rt_fs_open_read".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.fs.FileRead__read_to_string".to_string(), - FnInfo { - sig: fs_file_read_to_string, - abi_sig: Some(fs_file_read_to_string_abi), - symbol: "capable_rt_fs_file_read_to_string".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__buffer_new".to_string(), - FnInfo { - sig: mem_buffer_new.clone(), - abi_sig: Some(mem_buffer_new_abi.clone()), - symbol: "capable_rt_buffer_new".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__malloc".to_string(), - FnInfo { - sig: mem_malloc, - abi_sig: None, - symbol: "capable_rt_malloc".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__free".to_string(), - FnInfo { - sig: mem_free, - abi_sig: None, - symbol: "capable_rt_free".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__cast_u8_to_u32".to_string(), - FnInfo { - sig: mem_cast.clone(), - abi_sig: None, - symbol: "capable_rt_cast_u8_to_u32".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__cast_u32_to_u8".to_string(), - FnInfo { - sig: mem_cast, - abi_sig: None, - symbol: "capable_rt_cast_u32_to_u8".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__slice_from_ptr".to_string(), - FnInfo { - sig: mem_slice_from_ptr.clone(), - abi_sig: None, - symbol: "capable_rt_slice_from_ptr".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__mut_slice_from_ptr".to_string(), - FnInfo { - sig: mem_slice_from_ptr, - abi_sig: None, - symbol: "capable_rt_mut_slice_from_ptr".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__buffer_free".to_string(), - FnInfo { - sig: mem_buffer_free, - abi_sig: None, - symbol: "capable_rt_buffer_free".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Buffer__len".to_string(), - FnInfo { - sig: mem_buffer_len, - abi_sig: None, - symbol: "capable_rt_buffer_len".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Buffer__push".to_string(), - FnInfo { - sig: mem_buffer_push, - abi_sig: Some(mem_buffer_push_abi), - symbol: "capable_rt_buffer_push".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Buffer__as_slice".to_string(), - FnInfo { - sig: mem_buffer_as_slice.clone(), - abi_sig: None, - symbol: "capable_rt_buffer_as_slice".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Buffer__as_mut_slice".to_string(), - FnInfo { - sig: mem_buffer_as_slice, - abi_sig: None, - symbol: "capable_rt_buffer_as_mut_slice".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Slice__len".to_string(), - FnInfo { - sig: mem_slice_len.clone(), - abi_sig: None, - symbol: "capable_rt_slice_len".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Slice__at".to_string(), - FnInfo { - sig: mem_slice_at.clone(), - abi_sig: None, - symbol: "capable_rt_slice_at".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.MutSlice__at".to_string(), - FnInfo { - sig: mem_slice_at, - abi_sig: None, - symbol: "capable_rt_mut_slice_at".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__vec_u8_new".to_string(), - FnInfo { - sig: vec_new.clone(), - abi_sig: None, - symbol: "capable_rt_vec_u8_new".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__vec_u8_free".to_string(), - FnInfo { - sig: vec_u8_free, - abi_sig: None, - symbol: "capable_rt_vec_u8_free".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__vec_i32_new".to_string(), - FnInfo { - sig: vec_new.clone(), - abi_sig: None, - symbol: "capable_rt_vec_i32_new".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__vec_i32_free".to_string(), - FnInfo { - sig: vec_i32_free, - abi_sig: None, - symbol: "capable_rt_vec_i32_free".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__vec_string_new".to_string(), - FnInfo { - sig: vec_new, - abi_sig: None, - symbol: "capable_rt_vec_string_new".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.buffer.Alloc__vec_string_free".to_string(), - FnInfo { - sig: vec_string_free, - abi_sig: None, - symbol: "capable_rt_vec_string_free".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecU8__len".to_string(), - FnInfo { - sig: vec_len.clone(), - abi_sig: None, - symbol: "capable_rt_vec_u8_len".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecU8__get".to_string(), - FnInfo { - sig: vec_u8_get.clone(), - abi_sig: Some(vec_u8_get_abi), - symbol: "capable_rt_vec_u8_get".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecU8__set".to_string(), - FnInfo { - sig: vec_u8_set.clone(), - abi_sig: Some(vec_u8_set_abi), - symbol: "capable_rt_vec_u8_set".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecU8__push".to_string(), - FnInfo { - sig: vec_u8_push.clone(), - abi_sig: Some(vec_u8_push_abi), - symbol: "capable_rt_vec_u8_push".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecU8__pop".to_string(), - FnInfo { - sig: vec_u8_pop.clone(), - abi_sig: Some(vec_u8_pop_abi), - symbol: "capable_rt_vec_u8_pop".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecU8__as_slice".to_string(), - FnInfo { - sig: vec_u8_as_slice, - abi_sig: None, - symbol: "capable_rt_vec_u8_as_slice".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecI32__len".to_string(), - FnInfo { - sig: vec_len.clone(), - abi_sig: None, - symbol: "capable_rt_vec_i32_len".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecI32__get".to_string(), - FnInfo { - sig: vec_i32_get.clone(), - abi_sig: Some(vec_i32_get_abi), - symbol: "capable_rt_vec_i32_get".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecI32__set".to_string(), - FnInfo { - sig: vec_i32_set.clone(), - abi_sig: Some(vec_i32_set_abi), - symbol: "capable_rt_vec_i32_set".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecI32__push".to_string(), - FnInfo { - sig: vec_i32_push.clone(), - abi_sig: Some(vec_i32_push_abi), - symbol: "capable_rt_vec_i32_push".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecI32__pop".to_string(), - FnInfo { - sig: vec_i32_pop.clone(), - abi_sig: Some(vec_i32_pop_abi), - symbol: "capable_rt_vec_i32_pop".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecString__len".to_string(), - FnInfo { - sig: vec_string_len, - abi_sig: None, - symbol: "capable_rt_vec_string_len".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecString__get".to_string(), - FnInfo { - sig: vec_string_get, - abi_sig: Some(vec_string_get_abi), - symbol: "capable_rt_vec_string_get".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecString__push".to_string(), - FnInfo { - sig: vec_string_push, - abi_sig: Some(vec_string_push_abi), - symbol: "capable_rt_vec_string_push".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.vec.VecString__pop".to_string(), - FnInfo { - sig: vec_string_pop, - abi_sig: Some(vec_string_pop_abi), - symbol: "capable_rt_vec_string_pop".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.string.string__len".to_string(), - FnInfo { - sig: string_len, - abi_sig: None, - symbol: "capable_rt_string_len".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.string.string__byte_at".to_string(), - FnInfo { - sig: string_byte_at, - abi_sig: None, - symbol: "capable_rt_string_byte_at".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.string.string__as_slice".to_string(), - FnInfo { - sig: string_as_slice.clone(), - abi_sig: None, - symbol: "capable_rt_string_as_slice".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.string.string__bytes".to_string(), - FnInfo { - // bytes() is an alias for as_slice(); both map to the same runtime symbol. - sig: string_as_slice, - abi_sig: None, - symbol: "capable_rt_string_as_slice".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.string.string__split_whitespace".to_string(), - FnInfo { - sig: string_split, - abi_sig: None, - symbol: "capable_rt_string_split_whitespace".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.string.string__lines".to_string(), - FnInfo { - sig: string_lines, - abi_sig: None, - symbol: "capable_rt_string_split_lines".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.string.string__split".to_string(), - FnInfo { - sig: string_split_delim, - abi_sig: None, - symbol: "capable_rt_string_split".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.string.string__starts_with".to_string(), - FnInfo { - sig: string_starts_with, - abi_sig: None, - symbol: "capable_rt_string_starts_with".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - map.insert( - "sys.bytes.u8__is_whitespace".to_string(), - FnInfo { - sig: FnSig { - params: vec![AbiType::U8], - ret: AbiType::Bool, - }, - abi_sig: None, - symbol: "capable_rt_bytes_is_whitespace".to_string(), - runtime_symbol: None, - is_runtime: true, - }, - ); - - let _ = ptr_ty; - map + intrinsics::register_runtime_intrinsics(ptr_ty) } fn register_user_functions( diff --git a/stdlib/sys/string.cap b/stdlib/sys/string.cap index 6db7d02..862f865 100644 --- a/stdlib/sys/string.cap +++ b/stdlib/sys/string.cap @@ -6,14 +6,17 @@ use sys::bytes use sys::vec impl string { + /// Intrinsic; implemented by the runtime. pub fn len(self) -> i32 { return 0 } + /// Intrinsic; implemented by the runtime. pub fn byte_at(self, index: i32) -> u8 { return 0u8 } + /// Intrinsic; implemented by the runtime. pub fn as_slice(self) -> Slice[u8] { return () } @@ -23,19 +26,34 @@ impl string { return self.as_slice() } + /// Intrinsic; implemented by the runtime. pub fn split_whitespace(self) -> VecString { return () } + /// Intrinsic; implemented by the runtime. pub fn lines(self) -> VecString { return () } + /// Intrinsic; implemented by the runtime. pub fn split(self, delim: u8) -> VecString { return () } pub fn starts_with(self, prefix: string) -> bool { - return false + let self_len = self.len() + let prefix_len = prefix.len() + if (prefix_len > self_len) { + return false + } + let i = 0 + while (i < prefix_len) { + if self.byte_at(i) != prefix.byte_at(i) { + return false + } + i = i + 1 + } + return true } } From 87070de2046f0dd257277e8c95a6c485edf23bfb Mon Sep 17 00:00:00 2001 From: Jordan Mecom Date: Sun, 28 Dec 2025 14:42:54 -0800 Subject: [PATCH 2/2] Refine intrinsics layout and ResultString handling --- capc/src/codegen/emit.rs | 170 ++++++++++++++++----------------- capc/src/codegen/intrinsics.rs | 19 ++++ 2 files changed, 100 insertions(+), 89 deletions(-) diff --git a/capc/src/codegen/emit.rs b/capc/src/codegen/emit.rs index 849810c..e2463fb 100644 --- a/capc/src/codegen/emit.rs +++ b/capc/src/codegen/emit.rs @@ -21,6 +21,16 @@ use super::{ use super::layout::{align_to, resolve_struct_layout, type_layout_for_abi}; use super::sig_to_clif; +#[derive(Copy, Clone, Debug)] +struct ResultStringSlots { + slot_ptr: ir::StackSlot, + slot_len: ir::StackSlot, + slot_err: ir::StackSlot, + ptr_align: u32, + len_align: u32, + err_align: u32, +} + /// Emit a single HIR statement. pub(super) fn emit_hir_stmt( @@ -607,39 +617,15 @@ fn emit_hir_expr_inner( } // Handle result out-parameters (same logic as AST version) - let mut out_slots = None; + let mut out_slots: Option = None; let mut result_out = None; let abi_sig = info.abi_sig.as_ref().unwrap_or(&info.sig); if abi_sig.ret == AbiType::ResultString { let ptr_ty = module.isa().pointer_type(); - let ptr_align = ptr_ty.bytes() as u32; - let len_bytes = result_string_len_bytes(); - let len_align = len_bytes; - let err_align = 4u32; - - let slot_ptr = builder.create_sized_stack_slot(ir::StackSlotData::new( - ir::StackSlotKind::ExplicitSlot, - aligned_slot_size(ptr_ty.bytes() as u32, ptr_align), - )); - let slot_len = builder.create_sized_stack_slot(ir::StackSlotData::new( - ir::StackSlotKind::ExplicitSlot, - aligned_slot_size(len_bytes, len_align), - )); - let slot_err = builder.create_sized_stack_slot(ir::StackSlotData::new( - ir::StackSlotKind::ExplicitSlot, - aligned_slot_size(4, err_align), - )); - - let ptr_ptr = aligned_stack_addr(builder, slot_ptr, ptr_align, ptr_ty); - let len_ptr = aligned_stack_addr(builder, slot_len, len_align, ptr_ty); - let err_ptr = aligned_stack_addr(builder, slot_err, err_align, ptr_ty); - - args.push(ptr_ptr); - args.push(len_ptr); - args.push(err_ptr); - - out_slots = Some((slot_ptr, slot_len, slot_err)); + let slots = result_string_slots(builder, ptr_ty); + push_result_string_out_params(builder, ptr_ty, &slots, &mut args); + out_slots = Some(slots); } if let AbiType::ResultOut(ok_ty, err_ty) = &abi_sig.ret { @@ -698,25 +684,10 @@ fn emit_hir_expr_inner( let tag = results .get(0) .ok_or_else(|| CodegenError::Codegen("missing result tag".to_string()))?; - let (slot_ptr, slot_len, slot_err) = + let slots = out_slots.ok_or_else(|| CodegenError::Codegen("missing slots".to_string()))?; let ptr_ty = module.isa().pointer_type(); - let ptr_align = ptr_ty.bytes() as u32; - let len_align = result_string_len_bytes(); - let err_align = 4u32; - let ptr_addr = aligned_stack_addr(builder, slot_ptr, ptr_align, ptr_ty); - let len_addr = aligned_stack_addr(builder, slot_len, len_align, ptr_ty); - let err_addr = aligned_stack_addr(builder, slot_err, err_align, ptr_ty); - let ptr = - builder - .ins() - .load(module.isa().pointer_type(), MemFlags::new(), ptr_addr, 0); - let len = builder - .ins() - .load(ir::types::I64, MemFlags::new(), len_addr, 0); - let err = builder - .ins() - .load(ir::types::I32, MemFlags::new(), err_addr, 0); + let (ptr, len, err) = read_result_string_slots(builder, ptr_ty, &slots); match &info.sig.ret { AbiType::Result(ok_ty, err_ty) => { if **ok_ty != AbiType::String || **err_ty != AbiType::I32 { @@ -1495,6 +1466,65 @@ fn result_string_len_bytes() -> u32 { 8 } +fn result_string_slots(builder: &mut FunctionBuilder, ptr_ty: Type) -> ResultStringSlots { + let ptr_align = ptr_ty.bytes() as u32; + let len_bytes = result_string_len_bytes(); + let len_align = len_bytes; + let err_align = 4u32; + let slot_ptr = builder.create_sized_stack_slot(ir::StackSlotData::new( + ir::StackSlotKind::ExplicitSlot, + aligned_slot_size(ptr_ty.bytes() as u32, ptr_align), + )); + let slot_len = builder.create_sized_stack_slot(ir::StackSlotData::new( + ir::StackSlotKind::ExplicitSlot, + aligned_slot_size(len_bytes, len_align), + )); + let slot_err = builder.create_sized_stack_slot(ir::StackSlotData::new( + ir::StackSlotKind::ExplicitSlot, + aligned_slot_size(4, err_align), + )); + ResultStringSlots { + slot_ptr, + slot_len, + slot_err, + ptr_align, + len_align, + err_align, + } +} + +fn push_result_string_out_params( + builder: &mut FunctionBuilder, + ptr_ty: Type, + slots: &ResultStringSlots, + args: &mut Vec, +) { + let ptr_ptr = aligned_stack_addr(builder, slots.slot_ptr, slots.ptr_align, ptr_ty); + let len_ptr = aligned_stack_addr(builder, slots.slot_len, slots.len_align, ptr_ty); + let err_ptr = aligned_stack_addr(builder, slots.slot_err, slots.err_align, ptr_ty); + args.push(ptr_ptr); + args.push(len_ptr); + args.push(err_ptr); +} + +fn read_result_string_slots( + builder: &mut FunctionBuilder, + ptr_ty: Type, + slots: &ResultStringSlots, +) -> (Value, Value, Value) { + let ptr_addr = aligned_stack_addr(builder, slots.slot_ptr, slots.ptr_align, ptr_ty); + let len_addr = aligned_stack_addr(builder, slots.slot_len, slots.len_align, ptr_ty); + let err_addr = aligned_stack_addr(builder, slots.slot_err, slots.err_align, ptr_ty); + let ptr = builder.ins().load(ptr_ty, MemFlags::new(), ptr_addr, 0); + let len = builder + .ins() + .load(ir::types::I64, MemFlags::new(), len_addr, 0); + let err = builder + .ins() + .load(ir::types::I32, MemFlags::new(), err_addr, 0); + (ptr, len, err) +} + /// Compute pointer/len offsets for the string layout. fn string_offsets(ptr_ty: Type) -> (u32, u32) { let ptr_size = ptr_ty.bytes() as u32; @@ -2293,37 +2323,14 @@ pub(super) fn emit_runtime_wrapper_call( ) -> Result { ensure_abi_sig_handled(info)?; let abi_sig = info.abi_sig.as_ref().unwrap_or(&info.sig); - let mut out_slots = None; + let mut out_slots: Option = None; let mut result_out = None; if abi_sig.ret == AbiType::ResultString { let ptr_ty = module.isa().pointer_type(); - let ptr_align = ptr_ty.bytes() as u32; - let len_bytes = result_string_len_bytes(); - let len_align = len_bytes; - let err_align = 4u32; - let slot_ptr = builder.create_sized_stack_slot(ir::StackSlotData::new( - ir::StackSlotKind::ExplicitSlot, - aligned_slot_size(ptr_ty.bytes(), ptr_align), - )); - let slot_len = builder.create_sized_stack_slot(ir::StackSlotData::new( - ir::StackSlotKind::ExplicitSlot, - aligned_slot_size(len_bytes, len_align), - )); - let slot_err = builder.create_sized_stack_slot(ir::StackSlotData::new( - ir::StackSlotKind::ExplicitSlot, - aligned_slot_size(4, err_align), - )); - - let ptr_ptr = aligned_stack_addr(builder, slot_ptr, ptr_align, ptr_ty); - let len_ptr = aligned_stack_addr(builder, slot_len, len_align, ptr_ty); - let err_ptr = aligned_stack_addr(builder, slot_err, err_align, ptr_ty); - - args.push(ptr_ptr); - args.push(len_ptr); - args.push(err_ptr); - - out_slots = Some((slot_ptr, slot_len, slot_err)); + let slots = result_string_slots(builder, ptr_ty); + push_result_string_out_params(builder, ptr_ty, &slots, &mut args); + out_slots = Some(slots); } if let AbiType::ResultOut(ok_ty, err_ty) = &abi_sig.ret { @@ -2375,24 +2382,9 @@ pub(super) fn emit_runtime_wrapper_call( let tag = results .get(0) .ok_or_else(|| CodegenError::Codegen("missing result tag".to_string()))?; - let (slot_ptr, slot_len, slot_err) = - out_slots.ok_or_else(|| CodegenError::Codegen("missing slots".to_string()))?; + let slots = out_slots.ok_or_else(|| CodegenError::Codegen("missing slots".to_string()))?; let ptr_ty = module.isa().pointer_type(); - let ptr_align = ptr_ty.bytes() as u32; - let len_align = result_string_len_bytes(); - let err_align = 4u32; - let ptr_addr = aligned_stack_addr(builder, slot_ptr, ptr_align, ptr_ty); - let len_addr = aligned_stack_addr(builder, slot_len, len_align, ptr_ty); - let err_addr = aligned_stack_addr(builder, slot_err, err_align, ptr_ty); - let ptr = builder - .ins() - .load(module.isa().pointer_type(), MemFlags::new(), ptr_addr, 0); - let len = builder - .ins() - .load(ir::types::I64, MemFlags::new(), len_addr, 0); - let err = builder - .ins() - .load(ir::types::I32, MemFlags::new(), err_addr, 0); + let (ptr, len, err) = read_result_string_slots(builder, ptr_ty, &slots); match &info.sig.ret { AbiType::Result(ok_ty, err_ty) => { if **ok_ty != AbiType::String || **err_ty != AbiType::I32 { diff --git a/capc/src/codegen/intrinsics.rs b/capc/src/codegen/intrinsics.rs index 8c9f047..affd40a 100644 --- a/capc/src/codegen/intrinsics.rs +++ b/capc/src/codegen/intrinsics.rs @@ -14,6 +14,7 @@ use super::{FnInfo, FnSig}; pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { let mut map = HashMap::new(); + // System + args. let system_console = FnSig { params: vec![AbiType::Handle], ret: AbiType::Handle, @@ -26,6 +27,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { params: vec![AbiType::Handle, AbiType::String], ret: AbiType::Handle, }; + // Filesystem. let fs_root_dir = FnSig { params: vec![AbiType::Handle], ret: AbiType::Handle, @@ -54,6 +56,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { params: vec![AbiType::Handle, AbiType::ResultString], ret: AbiType::ResultString, }; + // Console. let console_println = FnSig { params: vec![AbiType::Handle, AbiType::String], ret: AbiType::Unit, @@ -66,6 +69,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { params: vec![AbiType::Handle, AbiType::I32], ret: AbiType::Unit, }; + // Math. let math_i32 = FnSig { params: vec![AbiType::I32, AbiType::I32], ret: AbiType::I32, @@ -78,6 +82,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { params: vec![AbiType::U8, AbiType::U8], ret: AbiType::U8, }; + // Buffer + slices. let mem_malloc = FnSig { params: vec![AbiType::Handle, AbiType::I32], ret: AbiType::Ptr, @@ -110,6 +115,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { params: vec![AbiType::Handle, AbiType::I32, AbiType::ResultString], ret: AbiType::ResultString, }; + // Buffer + slices. let mem_slice_from_ptr = FnSig { params: vec![AbiType::Handle, AbiType::Ptr, AbiType::I32], ret: AbiType::Handle, @@ -122,6 +128,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { params: vec![AbiType::Handle, AbiType::I32], ret: AbiType::U8, }; + // Vecs. let mem_buffer_new = FnSig { params: vec![AbiType::Handle, AbiType::I32], ret: AbiType::Result(Box::new(AbiType::Handle), Box::new(AbiType::I32)), @@ -310,6 +317,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { params: vec![AbiType::Handle, AbiType::Handle], ret: AbiType::Unit, }; + // Strings. let string_len = FnSig { params: vec![AbiType::String], ret: AbiType::I32, @@ -334,6 +342,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { params: vec![AbiType::String, AbiType::U8], ret: AbiType::Handle, }; + // Vec lengths. let vec_u8_len = FnSig { params: vec![AbiType::Handle], ret: AbiType::I32, @@ -343,6 +352,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { ret: AbiType::I32, }; + // === System + args === map.insert( "sys.system.RootCap__mint_console".to_string(), FnInfo { @@ -416,6 +426,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === Stdin === map.insert( "sys.stdin.Stdin__read_to_string".to_string(), FnInfo { @@ -432,6 +443,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === Alloc === map.insert( "sys.system.RootCap__mint_alloc_default".to_string(), FnInfo { @@ -442,6 +454,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === Console === map.insert( "sys.console.Console__println".to_string(), FnInfo { @@ -495,6 +508,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === Math === map.insert( "sys.math.add_wrap_i32".to_string(), FnInfo { @@ -585,6 +599,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === Filesystem === map.insert( "sys.fs.ReadFS__read_to_string".to_string(), FnInfo { @@ -635,6 +650,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === Buffer + slices === map.insert( "sys.buffer.Alloc__buffer_new".to_string(), FnInfo { @@ -785,6 +801,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === Vec === map.insert( "sys.buffer.Alloc__vec_u8_new".to_string(), FnInfo { @@ -995,6 +1012,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === String === map.insert( "sys.string.string__len".to_string(), FnInfo { @@ -1066,6 +1084,7 @@ pub fn register_runtime_intrinsics(ptr_ty: Type) -> HashMap { is_runtime: true, }, ); + // === Bytes === map.insert( "sys.bytes.u8__is_whitespace".to_string(), FnInfo {