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