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