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 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
94pub struct BuildContext<'a> {
96 pub builder: FunctionBuilder<'a>,
97 pub(crate) vars: Vec<LocalVar>,
98 pub(crate) fn_refs: Vec<(FuncId, FuncRef)>,
99 pub(crate) ret_ty: Type,
100}
101
102impl<'a> BuildContext<'a> {
103 pub fn new(mut builder: FunctionBuilder<'a>, arg_tys: &[Type], ret_ty: Type) -> Result<Self> {
104 let entry_block = builder.create_block();
105 builder.append_block_params_for_function_params(entry_block);
106 builder.switch_to_block(entry_block);
107 let mut vars = Vec::new();
108 for (idx, ty) in arg_tys.iter().enumerate() {
109 vars.push(LocalVar::Value { val: builder.block_params(entry_block)[idx], ty: ty.clone() });
110 }
111 Ok(Self { builder, vars, fn_refs: Vec::new(), ret_ty })
112 }
113
114 pub fn get_fn_ref(&mut self, fn_id: FuncId) -> Option<FuncRef> {
115 self.fn_refs.iter().find_map(|f| if f.0 == fn_id { Some(f.1.clone()) } else { None })
116 }
117
118 pub fn get_var(&mut self, idx: u32) -> Result<LocalVar> {
119 self.vars.get(idx as usize).cloned().ok_or(anyhow!("未发现变量 {}", idx))
120 }
121
122 pub fn get_var_ty(&self, idx: u32) -> Option<Type> {
123 self.vars.get(idx as usize).map(|v| v.get_ty())
124 }
125
126 pub fn set_var(&mut self, idx: u32, val: LocalVar) -> Result<()> {
127 if idx as usize == self.vars.len() {
128 if val.is_closure() {
129 self.vars.push(val);
130 } else if let Some(vt) = val.get(self) {
131 let v = LocalVar::new(self, vt.0, vt.1)?;
132 self.vars.push(v);
133 }
134 } else if (idx as usize) < self.vars.len() {
135 if val.is_closure() {
136 self.vars[idx as usize] = val;
137 } else if let Some(vt) = val.get(self) {
138 if matches!(self.vars[idx as usize], LocalVar::None | LocalVar::Value { .. }) {
139 let v = LocalVar::new(self, vt.0, vt.1)?;
140 self.vars[idx as usize] = v;
141 } else {
142 let v = self.vars[idx as usize].clone();
143 v.set(self, vt.0);
144 }
145 }
146 } else {
147 self.vars.resize(idx as usize, LocalVar::None);
148 if val.is_closure() {
149 self.vars.push(val);
150 } else if let Some(vt) = val.get(self) {
151 let v = LocalVar::new(self, vt.0, vt.1)?;
152 self.vars.push(v);
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}