Skip to main content

vm/
binary.rs

1use super::{JITRunTime, context::BuildContext};
2use cranelift::prelude::*;
3use cranelift_module::{DataDescription, Module};
4use dynamic::{Dynamic, Type};
5use parser::{BinaryOp, Expr};
6
7use anyhow::{Result, anyhow};
8
9impl JITRunTime {
10    fn any_to_string(&mut self, ctx: &mut BuildContext, vt: (Value, Type)) -> Result<Value> {
11        let value = self.convert(ctx, vt, Type::Any)?;
12        self.call(ctx, self.get_method(&Type::Any, "to_string")?, vec![value]).map(|(v, _)| v)
13    }
14
15    fn struct_to_dynamic(&mut self, ctx: &mut BuildContext, base: Value, ty: &Type) -> Result<Value> {
16        let Type::Struct { params: _, fields: _ } = ty else {
17            return Err(anyhow!("不是结构体 {:?}", ty));
18        };
19        let id = self.module.declare_anonymous_data(true, false)?;
20        let mut desc = DataDescription::new();
21        let ty_ptr = Box::into_raw(Box::new(ty.clone()));
22        desc.define((ty_ptr as i64).to_le_bytes().into());
23        self.module.define_data(id, &desc)?;
24        let ty_data = self.module.declare_data_in_func(id, &mut ctx.builder.func);
25        let ty_addr = ctx.builder.ins().global_value(crate::ptr_type(), ty_data);
26        let ty_ptr = ctx.builder.ins().load(crate::ptr_type(), MemFlags::new(), ty_addr, 0);
27        let f = self.get_fn(self.get_id("__struct_from_ptr")?, &[Type::I64, Type::I64])?;
28        self.call(ctx, f, vec![base, ty_ptr]).map(|(v, _)| v)
29    }
30
31    pub(crate) fn bool_value(&mut self, ctx: &mut BuildContext, vt: (Value, Type)) -> Result<Value> {
32        if vt.1.is_bool() {
33            Ok(vt.0)
34        } else if vt.1.is_any() {
35            self.call(ctx, self.get_method(&Type::Any, "to_bool")?, vec![vt.0]).map(|(v, _)| v)
36        } else if vt.1.is_int() || vt.1.is_uint() {
37            Ok(ctx.builder.ins().icmp_imm(IntCC::NotEqual, vt.0, 0))
38        } else if vt.1.is_f32() {
39            let zero = ctx.builder.ins().f32const(0.0);
40            Ok(ctx.builder.ins().fcmp(FloatCC::NotEqual, vt.0, zero))
41        } else if vt.1.is_f64() {
42            let zero = ctx.builder.ins().f64const(0.0);
43            Ok(ctx.builder.ins().fcmp(FloatCC::NotEqual, vt.0, zero))
44        } else {
45            Err(anyhow!("cannot convert {:?} to bool", vt.1))
46        }
47    }
48
49    pub fn convert(&mut self, ctx: &mut BuildContext, vt: (Value, Type), ty: Type) -> Result<Value> {
50        if vt.1 != ty {
51            if ty.is_any() {
52                if vt.1.is_struct() {
53                    return self.struct_to_dynamic(ctx, vt.0, &vt.1);
54                } else if vt.1.is_bool() {
55                    return self.call(ctx, self.get_method(&Type::Any, "from_bool")?, vec![vt.0]).map(|(v, _)| v);
56                } else if vt.1.is_uint() {
57                    let v = if vt.1.width() < 8 { ctx.builder.ins().uextend(types::I64, vt.0) } else { vt.0 };
58                    return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
59                } else if vt.1.is_int() {
60                    let v = if vt.1.width() < 8 { ctx.builder.ins().sextend(types::I64, vt.0) } else { vt.0 };
61                    return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
62                } else if vt.1.is_f32() {
63                    let v = ctx.builder.ins().fpromote(types::F64, vt.0);
64                    return self.call(ctx, self.get_method(&Type::Any, "from_f64")?, vec![v]).map(|(v, _)| v);
65                } else if vt.1.is_f64() {
66                    return self.call(ctx, self.get_method(&Type::Any, "from_f64")?, vec![vt.0]).map(|(v, _)| v);
67                } else if vt.1.is_str() {
68                    return Ok(vt.0);
69                }
70            } else if vt.1.is_any() {
71                if ty.is_bool() {
72                    return self.call(ctx, self.get_method(&Type::Any, "to_bool")?, vec![vt.0]).map(|(v, _)| v);
73                } else if ty.is_str() {
74                    return self.call(ctx, self.get_method(&Type::Any, "to_string")?, vec![vt.0]).map(|(v, _)| v);
75                } else if ty.is_int() | ty.is_uint() {
76                    let (v, _) = self.call(ctx, self.get_method(&Type::Any, "to_i64")?, vec![vt.0])?;
77                    return Ok(match ty.width() {
78                        1 => ctx.builder.ins().ireduce(types::I8, v),
79                        2 => ctx.builder.ins().ireduce(types::I16, v),
80                        4 => ctx.builder.ins().ireduce(types::I32, v),
81                        _ => v,
82                    });
83                } else if ty.is_f32() {
84                    let v = self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v)?;
85                    return Ok(ctx.builder.ins().fdemote(types::F32, v));
86                } else if ty.is_f64() {
87                    return self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v);
88                } else {
89                    return Ok(vt.0);
90                }
91            } else if ty.is_str() {
92                return self.any_to_string(ctx, vt);
93            } else if ty.is_int() || ty.is_uint() {
94                if vt.1.is_f32() || vt.1.is_f64() {
95                    let target = crate::get_type(&ty)?;
96                    if ty.is_uint() {
97                        return Ok(ctx.builder.ins().fcvt_to_uint(target, vt.0));
98                    } else if ty.is_int() {
99                        return Ok(ctx.builder.ins().fcvt_to_sint(target, vt.0));
100                    }
101                }
102                if vt.1.is_int() || vt.1.is_uint() || vt.1.is_bool() {
103                    let target = crate::get_type(&ty)?;
104                    let actual = ctx.builder.func.dfg.value_type(vt.0);
105                    if actual == target {
106                        return Ok(vt.0);
107                    }
108                    if actual.is_int() && target.is_int() {
109                        if actual.bits() > target.bits() {
110                            return Ok(ctx.builder.ins().ireduce(target, vt.0));
111                        }
112                        if actual.bits() < target.bits() {
113                            return if vt.1.is_int() { Ok(ctx.builder.ins().sextend(target, vt.0)) } else { Ok(ctx.builder.ins().uextend(target, vt.0)) };
114                        }
115                    }
116                }
117            } else if ty.is_f32() {
118                if vt.1.is_int() {
119                    return Ok(ctx.builder.ins().fcvt_from_sint(types::F32, vt.0));
120                } else if vt.1.is_uint() {
121                    return Ok(ctx.builder.ins().fcvt_from_uint(types::F32, vt.0));
122                } else if vt.1.is_f64() {
123                    return Ok(ctx.builder.ins().fdemote(types::F32, vt.0));
124                }
125            } else if ty.is_f64() {
126                if vt.1.is_int() {
127                    return Ok(ctx.builder.ins().fcvt_from_sint(types::F64, vt.0));
128                } else if vt.1.is_uint() {
129                    return Ok(ctx.builder.ins().fcvt_from_uint(types::F64, vt.0));
130                } else if vt.1.is_f32() {
131                    return Ok(ctx.builder.ins().fpromote(types::F64, vt.0));
132                }
133            } else if let Type::Symbol { id: _, params: _ } = ty {
134                log::info!("convert {:?} -> {:?}", vt, ty);
135                return Ok(vt.0); //结构类型 可以看作 External 类型
136            }
137            if vt.1.is_bool() {
138                let v = ctx.builder.ins().sextend(types::I64, vt.0);
139                return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
140            }
141            log::error!("未实现 {:?} {:?}", vt, ty); //暂时还没有实现 struct 的 初始化
142            Ok(vt.0)
143        } else {
144            Ok(vt.0)
145        }
146    }
147
148    pub(crate) fn binary(&mut self, ctx: &mut BuildContext, left: (Value, Type), op: BinaryOp, right: &Expr) -> Result<(Value, Type)> {
149        //处理可以计算的简单情形
150        if matches!(op, BinaryOp::And | BinaryOp::Or) {
151            return self.short_circuit_logic(ctx, left, op, right);
152        }
153        let right = if right.is_value() {
154            let right = right.clone().value()?;
155            if right.is_f32() {
156                (ctx.builder.ins().f32const(right.as_float().unwrap() as f32), Type::F32)
157            } else if right.is_f64() {
158                (ctx.builder.ins().f64const(right.as_float().unwrap() as f64), Type::F64)
159            } else if left.1.is_any() {
160                if right.is_int() {
161                    (ctx.builder.ins().iconst(types::I64, right.as_int().unwrap()), Type::I64)
162                } else if right.is_null() {
163                    self.call(ctx, self.get_method(&Type::Any, "null")?, vec![])?
164                } else {
165                    ctx.get_const(&right)?
166                }
167            } else {
168                return self.binary_imm(ctx, left, op, right);
169            }
170        } else {
171            self.eval(ctx, right)?.get(ctx).ok_or_else(|| anyhow!("没有返回值: {:?}", right))?
172        };
173        let ty = if op.is_add() && (left.1.is_str() || right.1.is_str()) {
174            Type::Str
175        } else if op.is_add() && (left.1.is_any() || right.1.is_any()) {
176            Type::Any
177        } else {
178            left.1.clone() + right.1.clone()
179        }; //为了支持字符串的加法需要单独处理
180        let left = self.convert(ctx, left, ty.clone())?;
181        let right = self.convert(ctx, right, ty.clone())?;
182        if ty.is_any() {
183            if op.is_logic() {
184                let op = ctx.builder.ins().iconst(types::I32, i32::from(op) as i64);
185                return self.call(ctx, self.get_method(&Type::Any, "logic")?, vec![left, op, right]);
186            } else {
187                let op = ctx.builder.ins().iconst(types::I32, i32::from(op) as i64);
188                return self.call(ctx, self.get_method(&Type::Any, "binary")?, vec![left, op, right]);
189            }
190        }
191        match op {
192            BinaryOp::Add | BinaryOp::AddAssign => {
193                if ty.is_int() || ty.is_uint() {
194                    return Ok((ctx.builder.ins().iadd(left, right), ty));
195                } else if ty.is_float() {
196                    return Ok((ctx.builder.ins().fadd(left, right), ty));
197                } else if ty.is_str() {
198                    let op = ctx.builder.ins().iconst(types::I32, i32::from(op) as i64);
199                    let result = self.call(ctx, self.get_method(&Type::Any, "binary")?, vec![left, op, right])?.0;
200                    return Ok((result, ty));
201                }
202            }
203            BinaryOp::Sub | BinaryOp::SubAssign => {
204                if ty.is_int() || ty.is_uint() {
205                    return Ok((ctx.builder.ins().isub(left, right), ty));
206                } else if ty.is_float() {
207                    return Ok((ctx.builder.ins().fsub(left, right), ty));
208                }
209            }
210            BinaryOp::Mul | BinaryOp::MulAssign => {
211                if ty.is_int() || ty.is_uint() {
212                    return Ok((ctx.builder.ins().imul(left, right), ty));
213                } else if ty.is_float() {
214                    return Ok((ctx.builder.ins().fmul(left, right), ty));
215                }
216            }
217            BinaryOp::Div | BinaryOp::DivAssign => {
218                if ty.is_int() {
219                    return Ok((ctx.builder.ins().sdiv(left, right), ty));
220                } else if ty.is_uint() {
221                    return Ok((ctx.builder.ins().udiv(left, right), ty));
222                } else if ty.is_float() {
223                    return Ok((ctx.builder.ins().fdiv(left, right), ty));
224                }
225            }
226            BinaryOp::Mod | BinaryOp::ModAssign => {
227                if ty.is_int() {
228                    return Ok((ctx.builder.ins().srem(left, right), ty));
229                } else if ty.is_uint() {
230                    return Ok((ctx.builder.ins().urem(left, right), ty));
231                }
232            }
233            BinaryOp::Shl | BinaryOp::ShlAssign => {
234                if ty.is_int() || ty.is_uint() {
235                    return Ok((ctx.builder.ins().ishl(left, right), ty));
236                }
237            }
238            BinaryOp::Shr | BinaryOp::ShrAssign => {
239                if ty.is_int() {
240                    return Ok((ctx.builder.ins().sshr(left, right), ty));
241                } else if ty.is_uint() {
242                    return Ok((ctx.builder.ins().ushr(left, right), ty));
243                }
244            }
245            BinaryOp::BitAnd | BinaryOp::BitAndAssign => {
246                return Ok((ctx.builder.ins().band(left, right), ty));
247            }
248            BinaryOp::BitOr | BinaryOp::BitOrAssign => {
249                return Ok((ctx.builder.ins().bor(left, right), ty));
250            }
251            BinaryOp::BitXor | BinaryOp::BitXorAssign => {
252                return Ok((ctx.builder.ins().bxor(left, right), ty));
253            }
254            BinaryOp::Eq => {
255                if ty.is_int() | ty.is_uint() || ty.is_bool() {
256                    return Ok((ctx.builder.ins().icmp(IntCC::Equal, left, right), Type::Bool));
257                } else if ty.is_float() {
258                    return Ok((ctx.builder.ins().fcmp(FloatCC::Equal, left, right), Type::Bool));
259                }
260            }
261            BinaryOp::Ne => {
262                if ty.is_int() | ty.is_uint() || ty.is_bool() {
263                    return Ok((ctx.builder.ins().icmp(IntCC::NotEqual, left, right), Type::Bool));
264                } else if ty.is_float() {
265                    return Ok((ctx.builder.ins().fcmp(FloatCC::NotEqual, left, right), Type::Bool));
266                }
267            }
268            BinaryOp::Lt => {
269                if ty.is_int() {
270                    return Ok((ctx.builder.ins().icmp(IntCC::SignedLessThan, left, right), Type::Bool));
271                } else if ty.is_uint() {
272                    return Ok((ctx.builder.ins().icmp(IntCC::UnsignedLessThan, left, right), Type::Bool));
273                } else if ty.is_float() {
274                    return Ok((ctx.builder.ins().fcmp(FloatCC::LessThan, left, right), Type::Bool));
275                }
276            }
277            BinaryOp::Le => {
278                if ty.is_int() {
279                    return Ok((ctx.builder.ins().icmp(IntCC::SignedLessThanOrEqual, left, right), Type::Bool));
280                } else if ty.is_uint() {
281                    return Ok((ctx.builder.ins().icmp(IntCC::UnsignedLessThanOrEqual, left, right), Type::Bool));
282                } else if ty.is_float() {
283                    return Ok((ctx.builder.ins().fcmp(FloatCC::LessThanOrEqual, left, right), Type::Bool));
284                }
285            }
286            BinaryOp::Gt => {
287                if ty.is_int() {
288                    return Ok((ctx.builder.ins().icmp(IntCC::SignedGreaterThan, left, right), Type::Bool));
289                } else if ty.is_uint() {
290                    return Ok((ctx.builder.ins().icmp(IntCC::UnsignedGreaterThan, left, right), Type::Bool));
291                } else if ty.is_float() {
292                    return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThan, left, right), Type::Bool));
293                }
294            }
295            BinaryOp::Ge => {
296                if ty.is_int() {
297                    return Ok((ctx.builder.ins().icmp(IntCC::SignedGreaterThanOrEqual, left, right), Type::Bool));
298                } else if ty.is_uint() {
299                    return Ok((ctx.builder.ins().icmp(IntCC::UnsignedGreaterThanOrEqual, left, right), Type::Bool));
300                } else if ty.is_float() {
301                    return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThanOrEqual, left, right), Type::Bool));
302                }
303            }
304            _ => {}
305        }
306        panic!("未实现 {:?} {:?} {:?} {:?}", left, op, right, ty)
307    }
308
309    pub(crate) fn binary_imm<'a>(&mut self, ctx: &'a mut BuildContext, left: (Value, Type), op: BinaryOp, right: Dynamic) -> Result<(Value, Type)> {
310        let ty = left.1.clone() + right.get_type();
311        let left = self.convert(ctx, left, ty.clone())?;
312        match op {
313            BinaryOp::Add | BinaryOp::AddAssign => {
314                if ty.is_str() {
315                    let right_vt = ctx.get_const(&right).or_else(|_| {
316                        let idx = self.compiler.get_const(right.clone());
317                        self.get_const_value(ctx, idx)
318                    })?;
319                    let right = self.convert(ctx, right_vt, Type::Str)?;
320                    let op = ctx.builder.ins().iconst(types::I32, i32::from(op) as i64);
321                    let result = self.call(ctx, self.get_method(&Type::Any, "binary")?, vec![left, op, right])?.0;
322                    return Ok((result, ty));
323                }
324                if ty.is_int() | ty.is_uint() {
325                    return Ok((ctx.builder.ins().iadd_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
326                }
327            }
328            BinaryOp::Sub | BinaryOp::SubAssign => {
329                if ty.is_int() | ty.is_uint() {
330                    return Ok((ctx.builder.ins().iadd_imm(left, -right.as_int().ok_or(anyhow!("非整数"))?), ty));
331                }
332            }
333            BinaryOp::Mul | BinaryOp::MulAssign => {
334                if ty.is_int() | ty.is_uint() {
335                    return Ok((ctx.builder.ins().imul_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
336                }
337            }
338            BinaryOp::Div | BinaryOp::DivAssign => {
339                if ty.is_int() {
340                    return Ok((ctx.builder.ins().sdiv_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
341                } else if ty.is_uint() {
342                    return Ok((ctx.builder.ins().udiv_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
343                }
344            }
345            BinaryOp::Shl | BinaryOp::ShlAssign => {
346                if ty.is_int() || ty.is_uint() {
347                    return Ok((ctx.builder.ins().ishl_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
348                }
349            }
350            BinaryOp::Shr | BinaryOp::ShrAssign => {
351                if ty.is_int() {
352                    return Ok((ctx.builder.ins().sshr_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
353                } else if ty.is_uint() {
354                    return Ok((ctx.builder.ins().ushr_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
355                }
356            }
357            BinaryOp::BitAnd | BinaryOp::BitAndAssign => {
358                return Ok((ctx.builder.ins().band_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
359            }
360            BinaryOp::BitOr | BinaryOp::BitOrAssign => {
361                return Ok((ctx.builder.ins().bor_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
362            }
363            BinaryOp::BitXor | BinaryOp::BitXorAssign => {
364                return Ok((ctx.builder.ins().bxor_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
365            }
366            BinaryOp::Eq => {
367                if ty.is_int() | ty.is_uint() {
368                    return Ok((ctx.builder.ins().icmp_imm(IntCC::Equal, left, right.as_int().unwrap()), Type::Bool));
369                }
370            }
371            BinaryOp::Ne => {
372                if ty.is_int() | ty.is_uint() {
373                    return Ok((ctx.builder.ins().icmp_imm(IntCC::NotEqual, left, right.as_int().unwrap()), Type::Bool));
374                }
375            }
376            BinaryOp::Le => {
377                if ty.is_int() {
378                    return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedLessThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
379                } else if ty.is_uint() {
380                    return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedLessThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
381                }
382            }
383            BinaryOp::Lt => {
384                if ty.is_int() {
385                    return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedLessThan, left, right.as_int().unwrap()), Type::Bool));
386                } else if ty.is_uint() {
387                    return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedLessThan, left, right.as_int().unwrap()), Type::Bool));
388                }
389            }
390            BinaryOp::Ge => {
391                if ty.is_int() {
392                    return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
393                } else if ty.is_uint() {
394                    return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedGreaterThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
395                }
396            }
397            BinaryOp::Gt => {
398                if ty.is_int() {
399                    return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedGreaterThan, left, right.as_int().unwrap()), Type::Bool));
400                } else if ty.is_uint() {
401                    return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedGreaterThan, left, right.as_int().unwrap()), Type::Bool));
402                }
403            }
404            BinaryOp::Mod | BinaryOp::ModAssign => {
405                if ty.is_int() {
406                    return Ok((ctx.builder.ins().srem_imm(left, right.as_int().unwrap()), ty));
407                } else if ty.is_uint() {
408                    return Ok((ctx.builder.ins().urem_imm(left, right.as_int().unwrap()), ty));
409                }
410            }
411            exp => {
412                panic!("不支持的操作 {:?}", exp)
413            }
414        }
415        panic!("未实现 {:?} {:?} {:?}", ty, op, right.get_type())
416    }
417}