Skip to content

Commit 95f6ddb

Browse files
author
Arnaud Riess
committed
refactor: reorganize code generation functions and add utility methods for IR handling
1 parent 49a33aa commit 95f6ddb

2 files changed

Lines changed: 71 additions & 86 deletions

File tree

crates/herkos/src/codegen/mod.rs

Lines changed: 6 additions & 86 deletions
Original file line numberDiff line numberDiff line change
@@ -22,31 +22,6 @@ fn module_name_to_trait_name(module_name: &str) -> String {
2222
format!("{}Imports", module_name.to_upper_camel_case())
2323
}
2424

25-
/// Group items by module name using a key function.
26-
fn group_by_module<'a, T, F>(
27-
items: &'a [T],
28-
key: F,
29-
) -> std::collections::BTreeMap<String, Vec<&'a T>>
30-
where
31-
F: Fn(&T) -> &str,
32-
{
33-
let mut grouped: std::collections::BTreeMap<String, Vec<&'a T>> =
34-
std::collections::BTreeMap::new();
35-
for item in items {
36-
grouped.entry(key(item).to_string()).or_default().push(item);
37-
}
38-
grouped
39-
}
40-
41-
/// Collect all unique module names from function and global imports.
42-
fn all_import_module_names(info: &ModuleInfo) -> std::collections::BTreeSet<String> {
43-
info.func_imports
44-
.iter()
45-
.map(|i| i.module_name.clone())
46-
.chain(info.imported_globals.iter().map(|g| g.module_name.clone()))
47-
.collect()
48-
}
49-
5025
/// Build a call args vector by conditionally adding globals/memory/table/host.
5126
fn build_inner_call_args(
5227
base_args: &[String],
@@ -197,22 +172,16 @@ impl<'a, B: Backend> CodeGenerator<'a, B> {
197172
let mut code = String::new();
198173
code.push_str("// Generated by herkos\n");
199174
code.push_str("// DO NOT EDIT\n\n");
175+
code.push_str("use herkos_runtime::*;\n\n");
200176
code
201177
}
202178

203179
/// Generate standalone functions (no module wrapper).
204180
fn generate_standalone_module(&self, info: &ModuleInfo) -> Result<String> {
205181
let mut rust_code = Self::rust_code_preamble();
206182

207-
// Imports
208-
rust_code.push_str("#[allow(unused_imports)]\n");
209183
if info.has_memory {
210-
rust_code.push_str("use herkos_runtime::{WasmResult, WasmTrap, IsolatedMemory};\n\n");
211184
rust_code.push_str(&format!("const MAX_PAGES: usize = {};\n\n", info.max_pages));
212-
} else if info.has_memory_import {
213-
rust_code.push_str("use herkos_runtime::{WasmResult, WasmTrap, IsolatedMemory};\n\n");
214-
} else {
215-
rust_code.push_str("use herkos_runtime::{WasmResult, WasmTrap};\n\n");
216185
}
217186

218187
// Host trait definitions
@@ -239,28 +208,10 @@ impl<'a, B: Backend> CodeGenerator<'a, B> {
239208
let mut rust_code = Self::rust_code_preamble();
240209
let has_mut_globals = info.has_mutable_globals();
241210

242-
// Imports
243-
rust_code.push_str("#[allow(unused_imports)]\n");
244-
let funcref_import = if !info.element_segments.is_empty() {
245-
", FuncRef"
246-
} else {
247-
""
248-
};
249211
if info.has_memory {
250-
rust_code.push_str(&format!(
251-
"use herkos_runtime::{{WasmResult, WasmTrap, IsolatedMemory, Module, Table{funcref_import}}};\n\n",
252-
));
253-
rust_code.push_str(&format!("const MAX_PAGES: usize = {};\n", info.max_pages));
254-
} else if info.has_memory_import {
255-
// Memory imported — use LibraryModule, include IsolatedMemory, no MAX_PAGES constant
256-
rust_code.push_str(&format!(
257-
"use herkos_runtime::{{WasmResult, WasmTrap, IsolatedMemory, LibraryModule, Table{funcref_import}}};\n\n",
258-
));
259-
} else {
260-
rust_code.push_str(&format!(
261-
"use herkos_runtime::{{WasmResult, WasmTrap, LibraryModule, Table{funcref_import}}};\n\n",
262-
));
212+
rust_code.push_str(&format!("const MAX_PAGES: usize = {};\n\n", info.max_pages));
263213
}
214+
264215
if info.has_table() {
265216
rust_code.push_str(&format!("const TABLE_MAX: usize = {};\n", info.table_max));
266217
}
@@ -542,32 +493,6 @@ impl<'a, B: Backend> CodeGenerator<'a, B> {
542493
code
543494
}
544495

545-
/// Check if an IR function contains any CallImport instructions.
546-
fn has_import_calls(ir_func: &IrFunction) -> bool {
547-
ir_func.blocks.iter().any(|block| {
548-
block
549-
.instructions
550-
.iter()
551-
.any(|instr| matches!(instr, IrInstr::CallImport { .. }))
552-
})
553-
}
554-
555-
/// Check if an IR function accesses any imported globals.
556-
fn has_global_import_access(ir_func: &IrFunction, num_imported_globals: usize) -> bool {
557-
if num_imported_globals == 0 {
558-
return false;
559-
}
560-
ir_func.blocks.iter().any(|block| {
561-
block.instructions.iter().any(|instr| {
562-
matches!(
563-
instr,
564-
IrInstr::GlobalGet { index, .. } | IrInstr::GlobalSet { index, .. }
565-
if *index < num_imported_globals
566-
)
567-
})
568-
})
569-
}
570-
571496
/// Generate a complete Rust function from IR with module info.
572497
///
573498
/// `is_public` controls whether the function is `pub fn` or `fn`.
@@ -731,12 +656,7 @@ impl<'a, B: Backend> CodeGenerator<'a, B> {
731656

732657
for (var, ty) in sorted_vars {
733658
let rust_ty = self.wasm_type_to_rust(ty);
734-
let default = match ty {
735-
WasmType::I32 => "0i32",
736-
WasmType::I64 => "0i64",
737-
WasmType::F32 => "0.0f32",
738-
WasmType::F64 => "0.0f64",
739-
};
659+
let default = ty.default_value_literal();
740660
output.push_str(&format!(" let mut {var}: {rust_ty} = {default};\n"));
741661
}
742662

@@ -810,8 +730,8 @@ impl<'a, B: Backend> CodeGenerator<'a, B> {
810730
let visibility = if is_public { "pub " } else { "" };
811731

812732
// Check if function needs host parameter (imports or global imports)
813-
let needs_host = Self::has_import_calls(ir_func)
814-
|| Self::has_global_import_access(ir_func, info.imported_globals.len());
733+
let needs_host = has_import_calls(ir_func)
734+
|| has_global_import_access(ir_func, info.imported_globals.len());
815735
let trait_bounds_opt = if needs_host {
816736
self.build_trait_bounds(info)
817737
} else {

crates/herkos/src/ir/types.rs

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,20 @@ impl WasmType {
6161
_ => panic!("Unsupported value type: {:?}", vt),
6262
}
6363
}
64+
65+
/// Get the default/zero value literal string for this type (used in code generation).
66+
///
67+
/// Examples:
68+
/// - `I32` → `"0i32"`
69+
/// - `F64` → `"0.0f64"`
70+
pub fn default_value_literal(&self) -> &'static str {
71+
match self {
72+
WasmType::I32 => "0i32",
73+
WasmType::I64 => "0i64",
74+
WasmType::F32 => "0.0f32",
75+
WasmType::F64 => "0.0f64",
76+
}
77+
}
6478
}
6579

6680
/// IR representation of a complete function.
@@ -810,3 +824,54 @@ impl ModuleInfo {
810824
}
811825
}
812826
}
827+
828+
/// Group items by module name using a key function.
829+
pub fn group_by_module<'a, T, F>(
830+
items: &'a [T],
831+
key: F,
832+
) -> std::collections::BTreeMap<String, Vec<&'a T>>
833+
where
834+
F: Fn(&T) -> &str,
835+
{
836+
let mut grouped: std::collections::BTreeMap<String, Vec<&'a T>> =
837+
std::collections::BTreeMap::new();
838+
for item in items {
839+
grouped.entry(key(item).to_string()).or_default().push(item);
840+
}
841+
grouped
842+
}
843+
844+
/// Collect all unique module names from function and global imports.
845+
pub fn all_import_module_names(info: &ModuleInfo) -> std::collections::BTreeSet<String> {
846+
info.func_imports
847+
.iter()
848+
.map(|i| i.module_name.clone())
849+
.chain(info.imported_globals.iter().map(|g| g.module_name.clone()))
850+
.collect()
851+
}
852+
853+
/// Check if an IR function contains any CallImport instructions.
854+
pub fn has_import_calls(ir_func: &IrFunction) -> bool {
855+
ir_func.blocks.iter().any(|block| {
856+
block
857+
.instructions
858+
.iter()
859+
.any(|instr| matches!(instr, IrInstr::CallImport { .. }))
860+
})
861+
}
862+
863+
/// Check if an IR function accesses any imported globals.
864+
pub fn has_global_import_access(ir_func: &IrFunction, num_imported_globals: usize) -> bool {
865+
if num_imported_globals == 0 {
866+
return false;
867+
}
868+
ir_func.blocks.iter().any(|block| {
869+
block.instructions.iter().any(|instr| {
870+
matches!(
871+
instr,
872+
IrInstr::GlobalGet { index, .. } | IrInstr::GlobalSet { index, .. }
873+
if *index < num_imported_globals
874+
)
875+
})
876+
})
877+
}

0 commit comments

Comments
 (0)