tidepool_codegen/
pipeline.rs1use cranelift_codegen::ir::{self, AbiParam, types};
2use cranelift_codegen::isa::TargetIsa;
3use cranelift_codegen::settings::{self, Configurable};
4use cranelift_codegen::Context;
5use cranelift_codegen::control::ControlPlane;
6use cranelift_jit::{JITBuilder, JITModule};
7use cranelift_module::{Module, Linkage, FuncId};
8use std::sync::Arc;
9
10use crate::debug::LambdaRegistry;
11use crate::stack_map::{StackMapRegistry, RawStackMap};
12
13pub struct CodegenPipeline {
19 pub module: JITModule,
26 pub isa: Arc<dyn TargetIsa>,
28 pub stack_maps: StackMapRegistry,
30 pending_stack_maps: Vec<(FuncId, u32, Vec<RawStackMap>)>,
33 lambda_names: Vec<(FuncId, String)>,
35}
36
37impl CodegenPipeline {
38 pub fn new(symbols: &[(&str, *const u8)]) -> Self {
43 let mut flag_builder = settings::builder();
44 flag_builder.set("preserve_frame_pointers", "true").unwrap();
46 flag_builder.set("opt_level", "speed").unwrap();
47
48 let isa_builder = cranelift_native::builder().expect("host machine not supported");
49 let isa = isa_builder.finish(settings::Flags::new(flag_builder.clone())).unwrap();
50
51 let mut jit_builder = JITBuilder::with_isa(
52 isa.clone(),
53 cranelift_module::default_libcall_names(),
54 );
55
56 for (name, ptr) in symbols {
57 jit_builder.symbol(*name, *ptr);
58 }
59
60 let module = JITModule::new(jit_builder);
61
62 Self {
63 module,
64 isa,
65 stack_maps: StackMapRegistry::new(),
66 pending_stack_maps: Vec::new(),
67 lambda_names: Vec::new(),
68 }
69 }
70
71 pub fn make_func_signature(&self) -> ir::Signature {
76 let mut sig = ir::Signature::new(self.isa.default_call_conv());
77 sig.params.push(AbiParam::new(types::I64)); sig.returns.push(AbiParam::new(types::I64)); sig
80 }
81
82 pub fn declare_function(&mut self, name: &str) -> FuncId {
84 let sig = self.make_func_signature();
85 self.module
86 .declare_function(name, Linkage::Export, &sig)
87 .unwrap_or_else(|e| panic!("failed to declare function `{}`: {}", name, e))
88 }
89
90 pub fn define_function(&mut self, func_id: FuncId, ctx: &mut Context) {
98 let mut ctrl_plane = ControlPlane::default();
100 let compiled = ctx.compile(self.isa.as_ref(), &mut ctrl_plane)
101 .unwrap_or_else(|e| {
102 panic!("first compilation failed for function ID {:?}: {:?}", func_id, e);
103 });
104
105 let func_size = compiled.buffer.data().len() as u32;
106
107 let raw_maps: Vec<RawStackMap> = compiled
109 .buffer
110 .user_stack_maps()
111 .iter()
112 .map(|(offset, span, usm)| {
113 let entries: Vec<_> = usm.entries().collect();
114 (*offset, *span, entries)
115 })
116 .collect();
117
118 self.module
120 .define_function(func_id, ctx)
121 .unwrap_or_else(|e| {
122 panic!("define_function failed for FuncId {:?}: {:?}", func_id, e);
123 });
124
125 self.pending_stack_maps.push((func_id, func_size, raw_maps));
127 }
128
129 pub fn finalize(&mut self) {
132 self.module.finalize_definitions()
133 .expect("finalize_definitions failed");
134
135 let pending = std::mem::take(&mut self.pending_stack_maps);
137 for (func_id, func_size, raw_maps) in pending {
138 let base_ptr = self.module.get_finalized_function(func_id) as usize;
139 self.stack_maps.register(base_ptr, func_size, &raw_maps);
140 }
141 }
142
143 pub fn get_function_ptr(&self, func_id: FuncId) -> *const u8 {
145 self.module.get_finalized_function(func_id)
146 }
147
148 pub fn register_lambda(&mut self, func_id: FuncId, name: String) {
150 self.lambda_names.push((func_id, name));
151 }
152
153 pub fn build_lambda_registry(&self) -> LambdaRegistry {
156 let mut registry = LambdaRegistry::new();
157 for (func_id, name) in &self.lambda_names {
158 let ptr = self.module.get_finalized_function(*func_id) as usize;
159 registry.register(ptr, name.clone());
160 }
161 registry
162 }
163}