tidepool_codegen/emit/
join.rs1use crate::pipeline::CodegenPipeline;
2use crate::emit::*;
3use crate::emit::expr::ensure_heap_ptr;
4use tidepool_repr::*;
5use cranelift_codegen::ir::{self, types, InstBuilder, Value};
6use cranelift_frontend::FunctionBuilder;
7
8pub fn emit_join(
12 ctx: &mut EmitContext,
13 pipeline: &mut CodegenPipeline,
14 builder: &mut FunctionBuilder,
15 vmctx: Value,
16 gc_sig: ir::SigRef,
17 tree: &CoreExpr,
18 label: &JoinId,
19 params: &[VarId],
20 rhs_idx: usize,
21 body_idx: usize,
22) -> Result<SsaVal, EmitError> {
23 let join_block = builder.create_block();
25
26 for _ in params {
28 builder.append_block_param(join_block, types::I64);
29 }
30
31 let merge_block = builder.create_block();
33 builder.append_block_param(merge_block, types::I64); let dummy_val = Value::from_u32(0);
38 ctx.join_blocks.insert(*label, JoinInfo {
39 block: join_block,
40 param_types: params.iter().map(|_| SsaVal::HeapPtr(dummy_val)).collect(),
41 });
42
43 let body_result = ctx.emit_node(pipeline, builder, vmctx, gc_sig, tree, body_idx)?;
45 let body_val = ensure_heap_ptr(builder, vmctx, gc_sig, body_result);
46 builder.ins().jump(merge_block, &[body_val]);
47
48 builder.switch_to_block(join_block);
50
51 let block_params = builder.block_params(join_block).to_vec();
53 let mut old_env_vals = Vec::new();
54 for (i, param_var) in params.iter().enumerate() {
55 let val = block_params[i];
56 builder.declare_value_needs_stack_map(val); let old_val = ctx.env.insert(*param_var, SsaVal::HeapPtr(val));
58 old_env_vals.push((*param_var, old_val));
59 }
60
61 let rhs_result = ctx.emit_node(pipeline, builder, vmctx, gc_sig, tree, rhs_idx)?;
62 let rhs_val = ensure_heap_ptr(builder, vmctx, gc_sig, rhs_result);
63 builder.ins().jump(merge_block, &[rhs_val]);
64
65 builder.seal_block(join_block);
68 builder.seal_block(merge_block);
70
71 builder.switch_to_block(merge_block);
73 let result = builder.block_params(merge_block)[0];
74 builder.declare_value_needs_stack_map(result); ctx.join_blocks.remove(label);
78 for (param_var, old_val) in old_env_vals.into_iter().rev() {
79 if let Some(v) = old_val {
80 ctx.env.insert(param_var, v);
81 } else {
82 ctx.env.remove(¶m_var);
83 }
84 }
85
86 Ok(SsaVal::HeapPtr(result))
88}
89
90pub fn emit_jump(
93 ctx: &mut EmitContext,
94 pipeline: &mut CodegenPipeline,
95 builder: &mut FunctionBuilder,
96 vmctx: Value,
97 gc_sig: ir::SigRef,
98 tree: &CoreExpr,
99 label: &JoinId,
100 arg_indices: &[usize],
101) -> Result<SsaVal, EmitError> {
102 let join_block = ctx.join_blocks.get(label)
107 .ok_or_else(|| EmitError::NotYetImplemented(format!("Jump to unknown label {:?}", label)))?.block;
108
109 let mut arg_values = Vec::new();
111 for &arg_idx in arg_indices {
112 let val = ctx.emit_node(pipeline, builder, vmctx, gc_sig, tree, arg_idx)?;
113 arg_values.push(ensure_heap_ptr(builder, vmctx, gc_sig, val));
115 }
116
117 builder.ins().jump(join_block, &arg_values);
119
120 let unreachable_block = builder.create_block();
123 builder.switch_to_block(unreachable_block);
124 builder.seal_block(unreachable_block);
125
126 Ok(SsaVal::Raw(builder.ins().iconst(types::I64, 0), LIT_TAG_INT))
128}