Skip to main content

vm/
context.rs

1use crate::get_type;
2use anyhow::{Result, anyhow};
3use cranelift::codegen::ir::FuncRef;
4use cranelift::prelude::{FunctionBuilder, InstBuilder, Value, Variable, types};
5use cranelift_module::FuncId;
6use dynamic::{Dynamic, Type};
7
8#[derive(Clone, Debug)]
9pub enum LocalVar {
10    None,
11    Variable { var: Variable, ty: Type },
12    Value { val: Value, ty: Type },
13    Closure { id: u32, captures: Vec<(Value, Type)> },
14}
15
16impl Into<LocalVar> for (Value, Type) {
17    fn into(self) -> LocalVar {
18        LocalVar::Value { val: self.0, ty: self.1 }
19    }
20}
21
22impl LocalVar {
23    pub(crate) fn normalize_for_var(ctx: &mut BuildContext, val: Value, ty: &Type) -> Value {
24        let Ok(expected) = get_type(ty) else {
25            return val;
26        };
27        let actual = ctx.builder.func.dfg.value_type(val);
28        if actual == expected {
29            return val;
30        }
31
32        if ty.is_bool() && actual.bits() == 1 {
33            let zero = ctx.builder.ins().iconst(types::I8, 0);
34            let one = ctx.builder.ins().iconst(types::I8, 1);
35            return ctx.builder.ins().select(val, one, zero);
36        }
37
38        if expected.is_int() && actual.is_int() {
39            if actual.bits() > expected.bits() {
40                return ctx.builder.ins().ireduce(expected, val);
41            }
42            if actual.bits() < expected.bits() {
43                return if ty.is_uint() { ctx.builder.ins().uextend(expected, val) } else { ctx.builder.ins().sextend(expected, val) };
44            }
45        }
46
47        if expected.is_float() && actual.is_float() {
48            if actual.bits() > expected.bits() {
49                return ctx.builder.ins().fdemote(expected, val);
50            }
51            if actual.bits() < expected.bits() {
52                return ctx.builder.ins().fpromote(expected, val);
53            }
54        }
55
56        val
57    }
58
59    pub fn is_closure(&self) -> bool {
60        if let Self::Closure { .. } = self { true } else { false }
61    }
62
63    pub fn get_ty(&self) -> Type {
64        match self {
65            Self::Value { val: _, ty } => ty.clone(),
66            Self::Variable { var: _, ty } => ty.clone(),
67            _ => Type::Any,
68        }
69    }
70
71    pub fn new(ctx: &mut BuildContext, val: Value, ty: Type) -> Result<Self> {
72        let val = Self::normalize_for_var(ctx, val, &ty);
73        let var = ctx.builder.declare_var(get_type(&ty)?);
74        ctx.builder.def_var(var, val);
75        Ok(Self::Variable { var, ty })
76    }
77
78    pub fn get(self, ctx: &mut BuildContext) -> Option<(Value, Type)> {
79        match self {
80            Self::Value { val, ty } => Some((val, ty)),
81            Self::Variable { var, ty } => Some((ctx.builder.use_var(var), ty)),
82            _ => None,
83        }
84    }
85
86    pub fn set(&self, ctx: &mut BuildContext, val: Value) {
87        if let Self::Variable { var, ty } = self {
88            let val = Self::normalize_for_var(ctx, val, ty);
89            ctx.builder.def_var(var.clone(), val);
90        }
91    }
92}
93
94//用来生成 函数代码的上下文
95pub struct BuildContext<'a> {
96    pub builder: FunctionBuilder<'a>,
97    pub(crate) vars: Vec<LocalVar>,
98    pub(crate) local_type_hints: Vec<Option<Type>>,
99    pub(crate) fn_refs: Vec<(FuncId, FuncRef)>,
100    pub(crate) ret_ty: Type,
101}
102
103impl<'a> BuildContext<'a> {
104    pub fn new(builder: FunctionBuilder<'a>, arg_tys: &[Type], ret_ty: Type) -> Result<Self> {
105        Self::with_local_type_hints(builder, arg_tys, ret_ty, Vec::new())
106    }
107
108    pub fn with_local_type_hints(mut builder: FunctionBuilder<'a>, arg_tys: &[Type], ret_ty: Type, local_type_hints: Vec<Option<Type>>) -> Result<Self> {
109        let entry_block = builder.create_block();
110        builder.append_block_params_for_function_params(entry_block);
111        builder.switch_to_block(entry_block);
112        let mut vars = Vec::new();
113        for (idx, ty) in arg_tys.iter().enumerate() {
114            vars.push(LocalVar::Value { val: builder.block_params(entry_block)[idx], ty: ty.clone() });
115        }
116        Ok(Self { builder, vars, local_type_hints, fn_refs: Vec::new(), ret_ty })
117    }
118
119    pub fn get_fn_ref(&mut self, fn_id: FuncId) -> Option<FuncRef> {
120        self.fn_refs.iter().find_map(|f| if f.0 == fn_id { Some(f.1.clone()) } else { None })
121    }
122
123    pub fn get_var(&mut self, idx: u32) -> Result<LocalVar> {
124        self.vars.get(idx as usize).cloned().ok_or(anyhow!("未发现变量 {}", idx))
125    }
126
127    pub fn get_var_ty(&self, idx: u32) -> Option<Type> {
128        self.vars.get(idx as usize).map(|v| v.get_ty())
129    }
130
131    pub fn local_type_hint(&self, idx: u32) -> Option<Type> {
132        self.local_type_hints.get(idx as usize).cloned().flatten()
133    }
134
135    pub fn set_var(&mut self, idx: u32, val: LocalVar) -> Result<()> {
136        let idx = idx as usize;
137        if idx >= self.vars.len() {
138            self.vars.resize(idx + 1, LocalVar::None);
139        }
140
141        match val {
142            LocalVar::Closure { .. } | LocalVar::None => self.vars[idx] = val,
143            val => {
144                if let Some(vt) = val.get(self) {
145                    if matches!(self.vars[idx], LocalVar::None | LocalVar::Value { .. }) {
146                        let v = LocalVar::new(self, vt.0, vt.1)?;
147                        self.vars[idx] = v;
148                    } else {
149                        let v = self.vars[idx].clone();
150                        v.set(self, vt.0);
151                    }
152                }
153            }
154        }
155        Ok(())
156    }
157
158    pub fn get_const(&mut self, v: &Dynamic) -> Result<(Value, Type)> {
159        let ty = v.get_type();
160        if ty.is_f32() {
161            return Ok((self.builder.ins().f32const(v.as_float().unwrap() as f32), ty));
162        } else if ty.is_f64() {
163            return Ok((self.builder.ins().f64const(v.as_float().unwrap()), ty));
164        } else if ty.is_int() || ty.is_uint() {
165            return match ty.width() {
166                1 => Ok((self.builder.ins().iconst(types::I8, v.as_int().unwrap()), ty)),
167                2 => Ok((self.builder.ins().iconst(types::I16, v.as_int().unwrap()), ty)),
168                4 => Ok((self.builder.ins().iconst(types::I32, v.as_int().unwrap()), ty)),
169                8 => Ok((self.builder.ins().iconst(types::I64, v.as_int().unwrap()), ty)),
170                _ => panic!("const {:?}", v),
171            };
172        } else if ty.is_bool() {
173            return if v.is_true() { Ok((self.builder.ins().iconst(types::I8, 1), ty)) } else { Ok((self.builder.ins().iconst(types::I8, 0), ty)) };
174        }
175        Err(anyhow!("未实现 {:?}", v))
176    }
177}