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