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