Skip to main content

tidepool_codegen/emit/
mod.rs

1pub mod expr;
2pub mod primop;
3pub mod case;
4pub mod join;
5
6use cranelift_codegen::ir::Value;
7use tidepool_repr::{VarId, JoinId, PrimOpKind};
8use std::collections::HashMap;
9
10// HeapObject layout constants
11pub const HEAP_HEADER_SIZE: u64 = 8;
12pub const CLOSURE_CODE_PTR_OFFSET: i32 = 8;
13pub const CLOSURE_NUM_CAPTURED_OFFSET: i32 = 16;
14pub const CLOSURE_CAPTURED_START: i32 = 24;
15pub const CON_TAG_OFFSET: i32 = 8;
16pub const CON_NUM_FIELDS_OFFSET: i32 = 16;
17pub const CON_FIELDS_START: i32 = 24;
18pub const LIT_TAG_OFFSET: i32 = 8;
19pub const LIT_VALUE_OFFSET: i32 = 16;
20pub const LIT_TOTAL_SIZE: u64 = 24;
21pub const LIT_TAG_INT: i64 = 0;
22pub const LIT_TAG_WORD: i64 = 1;
23pub const LIT_TAG_CHAR: i64 = 2;
24pub const LIT_TAG_FLOAT: i64 = 3;
25pub const LIT_TAG_DOUBLE: i64 = 4;
26pub const LIT_TAG_STRING: i64 = 5;
27
28/// SSA value with boxed/unboxed tracking.
29#[derive(Debug, Clone, Copy)]
30pub enum SsaVal {
31    /// Unboxed raw value (i64 or f64 bits) with its literal tag.
32    Raw(Value, i64),
33    /// Heap pointer. Already declared via `declare_value_needs_stack_map`.
34    HeapPtr(Value),
35}
36
37impl SsaVal {
38    pub fn value(self) -> Value {
39        match self {
40            SsaVal::Raw(v, _) | SsaVal::HeapPtr(v) => v,
41        }
42    }
43}
44
45/// Emission context — bundles state during IR generation for one function.
46pub struct EmitContext {
47    pub env: HashMap<VarId, SsaVal>,
48    pub join_blocks: HashMap<JoinId, JoinInfo>,
49    pub lambda_counter: u32,
50    pub prefix: String,
51}
52
53/// Placeholder for join point info (used by case/join leaf later).
54pub struct JoinInfo {
55    pub block: cranelift_codegen::ir::Block,
56    pub param_types: Vec<SsaVal>,
57}
58
59/// Errors during IR emission.
60#[derive(Debug)]
61pub enum EmitError {
62    UnboundVariable(VarId),
63    NotYetImplemented(String),
64    CraneliftError(String),
65    InvalidArity(PrimOpKind, usize, usize),
66}
67
68impl std::fmt::Display for EmitError {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        match self {
71            EmitError::UnboundVariable(v) => write!(f, "unbound variable: {:?}", v),
72            EmitError::NotYetImplemented(s) => write!(f, "not yet implemented: {}", s),
73            EmitError::CraneliftError(s) => write!(f, "cranelift error: {}", s),
74            EmitError::InvalidArity(op, expected, got) => {
75                write!(f, "invalid arity for {:?}: expected {}, got {}", op, expected, got)
76            }
77        }
78    }
79}
80
81impl std::error::Error for EmitError {}
82
83impl EmitContext {
84    pub fn new(prefix: String) -> Self {
85        Self {
86            env: HashMap::new(),
87            join_blocks: HashMap::new(),
88            lambda_counter: 0,
89            prefix,
90        }
91    }
92
93    pub fn next_lambda_name(&mut self) -> String {
94        let n = self.lambda_counter;
95        self.lambda_counter += 1;
96        format!("{}_lambda_{}", self.prefix, n)
97    }
98}