1use super::{JITRunTime, context::BuildContext};
2use cranelift::prelude::*;
3use dynamic::{Dynamic, Type};
4use parser::{BinaryOp, Expr};
5
6use anyhow::{Result, anyhow};
7
8impl JITRunTime {
9 fn strcat(&mut self, ctx: &mut BuildContext, left: Value, right: Value) -> Result<Value> {
10 let fn_id = self.strcat_fn.ok_or_else(|| anyhow!("VM strcat runtime is not registered"))?;
11 let fn_ref = self.get_fn_ref(ctx, fn_id);
12 let call_inst = ctx.builder.ins().call(fn_ref, &[left, right]);
13 Ok(ctx.builder.inst_results(call_inst)[0])
14 }
15
16 fn strcat_i64(&mut self, ctx: &mut BuildContext, left: Value, right: Value) -> Result<Value> {
17 let fn_id = self.strcat_i64_fn.ok_or_else(|| anyhow!("VM strcat i64 runtime is not registered"))?;
18 let fn_ref = self.get_fn_ref(ctx, fn_id);
19 let call_inst = ctx.builder.ins().call(fn_ref, &[left, right]);
20 Ok(ctx.builder.inst_results(call_inst)[0])
21 }
22
23 fn strcat_assign(&mut self, ctx: &mut BuildContext, left: Value, right: Value) -> Result<Value> {
24 let fn_id = self.strcat_assign_fn.ok_or_else(|| anyhow!("VM strcat assign runtime is not registered"))?;
25 let fn_ref = self.get_fn_ref(ctx, fn_id);
26 let call_inst = ctx.builder.ins().call(fn_ref, &[left, right]);
27 Ok(ctx.builder.inst_results(call_inst)[0])
28 }
29
30 fn any_to_string(&mut self, ctx: &mut BuildContext, vt: (Value, Type)) -> Result<Value> {
31 let value = self.convert(ctx, vt, Type::Any)?;
32 self.call(ctx, self.get_method(&Type::Any, "to_string")?, vec![value]).map(|(v, _)| v)
33 }
34
35 fn any_logic(&mut self, ctx: &mut BuildContext, left: Value, op: BinaryOp, right: Value) -> Result<(Value, Type)> {
36 let op = ctx.builder.ins().iconst(types::I32, i32::from(op) as i64);
37 self.call(ctx, self.get_method(&Type::Any, "logic")?, vec![left, op, right])
38 }
39
40 fn any_binary(&mut self, ctx: &mut BuildContext, left: Value, op: BinaryOp, right: Value) -> Result<(Value, Type)> {
41 let op = ctx.builder.ins().iconst(types::I32, i32::from(op) as i64);
42 self.call(ctx, self.get_method(&Type::Any, "binary")?, vec![left, op, right])
43 }
44
45 fn struct_to_dynamic(&mut self, ctx: &mut BuildContext, base: Value, ty: &Type) -> Result<Value> {
46 let Type::Struct { params: _, fields: _ } = ty else {
47 return Err(anyhow!("不是结构体 {:?}", ty));
48 };
49 let ty_ptr = Self::type_ptr_const(ctx, ty);
50 let fn_id = self.struct_from_ptr_fn.ok_or_else(|| anyhow!("VM struct Dynamic runtime is not registered"))?;
51 let fn_ref = self.get_fn_ref(ctx, fn_id);
52 let call_inst = ctx.builder.ins().call(fn_ref, &[base, ty_ptr]);
53 Ok(ctx.builder.inst_results(call_inst)[0])
54 }
55
56 fn array_to_dynamic(&mut self, ctx: &mut BuildContext, base: Value, ty: &Type) -> Result<Value> {
57 let Type::Array(_, _) = ty else {
58 return Err(anyhow!("不是数组 {:?}", ty));
59 };
60 let ty_ptr = Self::type_ptr_const(ctx, ty);
61 let fn_id = self.array_from_ptr_fn.ok_or_else(|| anyhow!("VM array Dynamic runtime is not registered"))?;
62 let fn_ref = self.get_fn_ref(ctx, fn_id);
63 let call_inst = ctx.builder.ins().call(fn_ref, &[base, ty_ptr]);
64 Ok(ctx.builder.inst_results(call_inst)[0])
65 }
66
67 pub(crate) fn bool_value(&mut self, ctx: &mut BuildContext, vt: (Value, Type)) -> Result<Value> {
68 if vt.1.is_bool() {
69 Ok(vt.0)
70 } else if vt.1.is_void() {
71 Ok(ctx.builder.ins().iconst(types::I8, 0))
72 } else if vt.1.is_any() {
73 self.call(ctx, self.get_method(&Type::Any, "to_bool")?, vec![vt.0]).map(|(v, _)| v)
74 } else if vt.1.is_int() || vt.1.is_uint() {
75 Ok(ctx.builder.ins().icmp_imm(IntCC::NotEqual, vt.0, 0))
76 } else if vt.1.is_f32() {
77 let zero = ctx.builder.ins().f32const(0.0);
78 Ok(ctx.builder.ins().fcmp(FloatCC::NotEqual, vt.0, zero))
79 } else if vt.1.is_f64() {
80 let zero = ctx.builder.ins().f64const(0.0);
81 Ok(ctx.builder.ins().fcmp(FloatCC::NotEqual, vt.0, zero))
82 } else {
83 Err(anyhow!("cannot convert {:?} to bool", vt.1))
84 }
85 }
86
87 pub fn convert(&mut self, ctx: &mut BuildContext, vt: (Value, Type), ty: Type) -> Result<Value> {
88 let vt = if matches!(vt.1, Type::Symbol { .. }) {
89 let resolved = self.compiler.symbols.get_type(&vt.1).unwrap_or_else(|_| vt.1.clone());
90 (vt.0, resolved)
91 } else {
92 vt
93 };
94 if vt.1 != ty {
95 if ty.is_any() {
96 if self.is_opaque_custom_ty(&vt.1) {
97 return Ok(vt.0);
98 } else if vt.1.is_array() {
99 return self.array_to_dynamic(ctx, vt.0, &vt.1);
100 } else if vt.1.is_struct() {
101 return self.struct_to_dynamic(ctx, vt.0, &vt.1);
102 } else if vt.1.is_bool() {
103 return self.call(ctx, self.get_method(&Type::Any, "from_bool")?, vec![vt.0]).map(|(v, _)| v);
104 } else if vt.1.is_uint() {
105 if vt.1.width() == 8 {
106 return self.call(ctx, self.get_method(&Type::Any, "from_u64")?, vec![vt.0]).map(|(v, _)| v);
108 }
109 let v = ctx.builder.ins().uextend(types::I64, vt.0);
110 return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
111 } else if vt.1.is_int() {
112 let v = if vt.1.width() < 8 { ctx.builder.ins().sextend(types::I64, vt.0) } else { vt.0 };
113 return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
114 } else if vt.1.is_f32() {
115 let v = ctx.builder.ins().fpromote(types::F64, vt.0);
116 return self.call(ctx, self.get_method(&Type::Any, "from_f64")?, vec![v]).map(|(v, _)| v);
117 } else if vt.1.is_f64() {
118 return self.call(ctx, self.get_method(&Type::Any, "from_f64")?, vec![vt.0]).map(|(v, _)| v);
119 } else if vt.1.is_str() {
120 return Ok(vt.0);
121 } else if matches!(vt.1, Type::Map | Type::List(_) | Type::Iter) {
122 return Ok(vt.0);
123 } else if matches!(vt.1, Type::Symbol { .. }) {
124 return Ok(vt.0);
125 }
126 } else if vt.1.is_any() {
127 if ty.is_bool() {
128 return self.call(ctx, self.get_method(&Type::Any, "to_bool")?, vec![vt.0]).map(|(v, _)| v);
129 } else if ty.is_array() {
130 return self.any_to_array(ctx, vt.0, &ty);
131 } else if ty.is_str() {
132 return self.call(ctx, self.get_method(&Type::Any, "to_string")?, vec![vt.0]).map(|(v, _)| v);
133 } else if ty.is_int() | ty.is_uint() {
134 let (v, _) = self.call(ctx, self.get_method(&Type::Any, "to_i64")?, vec![vt.0])?;
135 return Ok(match ty.width() {
136 1 => ctx.builder.ins().ireduce(types::I8, v),
137 2 => ctx.builder.ins().ireduce(types::I16, v),
138 4 => ctx.builder.ins().ireduce(types::I32, v),
139 _ => v,
140 });
141 } else if ty.is_f32() {
142 let v = self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v)?;
143 return Ok(ctx.builder.ins().fdemote(types::F32, v));
144 } else if ty.is_f64() {
145 return self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v);
146 } else {
147 return Ok(vt.0);
148 }
149 } else if ty.is_str() {
150 return self.any_to_string(ctx, vt);
151 } else if ty.is_int() || ty.is_uint() {
152 if vt.1.is_f32() || vt.1.is_f64() {
153 let target = crate::get_type(&ty)?;
154 if ty.is_uint() {
155 return Ok(ctx.builder.ins().fcvt_to_uint(target, vt.0));
156 } else if ty.is_int() {
157 return Ok(ctx.builder.ins().fcvt_to_sint(target, vt.0));
158 }
159 }
160 if vt.1.is_int() || vt.1.is_uint() || vt.1.is_bool() {
161 let target = crate::get_type(&ty)?;
162 let actual = ctx.builder.func.dfg.value_type(vt.0);
163 if actual == target {
164 return Ok(vt.0);
165 }
166 if actual.is_int() && target.is_int() {
167 if actual.bits() > target.bits() {
168 return Ok(ctx.builder.ins().ireduce(target, vt.0));
169 }
170 if actual.bits() < target.bits() {
171 return if vt.1.is_int() { Ok(ctx.builder.ins().sextend(target, vt.0)) } else { Ok(ctx.builder.ins().uextend(target, vt.0)) };
172 }
173 }
174 }
175 if vt.1.is_str() {
176 let (v, _) = self.call(ctx, self.get_method(&Type::Any, "to_i64")?, vec![vt.0])?;
177 return Ok(match ty.width() {
178 1 => ctx.builder.ins().ireduce(types::I8, v),
179 2 => ctx.builder.ins().ireduce(types::I16, v),
180 4 => ctx.builder.ins().ireduce(types::I32, v),
181 _ => v,
182 });
183 }
184 } else if ty.is_f32() {
185 if vt.1.is_int() {
186 return Ok(ctx.builder.ins().fcvt_from_sint(types::F32, vt.0));
187 } else if vt.1.is_uint() {
188 return Ok(ctx.builder.ins().fcvt_from_uint(types::F32, vt.0));
189 } else if vt.1.is_f64() {
190 return Ok(ctx.builder.ins().fdemote(types::F32, vt.0));
191 } else if vt.1.is_str() {
192 let v = self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v)?;
193 return Ok(ctx.builder.ins().fdemote(types::F32, v));
194 }
195 } else if ty.is_f64() {
196 if vt.1.is_int() {
197 return Ok(ctx.builder.ins().fcvt_from_sint(types::F64, vt.0));
198 } else if vt.1.is_uint() {
199 return Ok(ctx.builder.ins().fcvt_from_uint(types::F64, vt.0));
200 } else if vt.1.is_f32() {
201 return Ok(ctx.builder.ins().fpromote(types::F64, vt.0));
202 } else if vt.1.is_str() {
203 return self.call(ctx, self.get_method(&Type::Any, "to_f64")?, vec![vt.0]).map(|(v, _)| v);
204 }
205 } else if let Type::Symbol { id: _, params: _ } = ty {
206 log::debug!("convert {:?} -> {:?}", vt, ty);
207 return Ok(vt.0); }
209 if vt.1.is_bool() {
210 let v = ctx.builder.ins().sextend(types::I64, vt.0);
211 return self.call(ctx, self.get_method(&Type::Any, "from_i64")?, vec![v]).map(|(v, _)| v);
212 }
213 log::error!("未实现 {:?} {:?}", vt, ty); Ok(vt.0)
215 } else {
216 Ok(vt.0)
217 }
218 }
219
220 fn guarded_idiv(&mut self, ctx: &mut BuildContext, left: Value, right: Value, signed: bool, is_rem: bool) -> Result<Value> {
227 use cranelift::codegen::ir::BlockArg;
228 let int_ty = ctx.builder.func.dfg.value_type(left);
229 let is_zero = ctx.builder.ins().icmp_imm(IntCC::Equal, right, 0);
230 let is_bad = if signed {
231 let min = match int_ty.bits() {
232 8 => i8::MIN as i64,
233 16 => i16::MIN as i64,
234 32 => i32::MIN as i64,
235 _ => i64::MIN,
236 };
237 let is_min = ctx.builder.ins().icmp_imm(IntCC::Equal, left, min);
238 let is_neg_one = ctx.builder.ins().icmp_imm(IntCC::Equal, right, -1);
239 let is_overflow = ctx.builder.ins().band(is_min, is_neg_one);
240 ctx.builder.ins().bor(is_zero, is_overflow)
241 } else {
242 is_zero
243 };
244
245 let ok_block = ctx.builder.create_block();
246 let bad_block = ctx.builder.create_block();
247 let merge_block = ctx.builder.create_block();
248 ctx.builder.append_block_param(merge_block, int_ty);
249 ctx.builder.ins().brif(is_bad, bad_block, &[], ok_block, &[]);
250
251 ctx.builder.switch_to_block(ok_block);
252 let raw = match (signed, is_rem) {
253 (true, false) => ctx.builder.ins().sdiv(left, right),
254 (false, false) => ctx.builder.ins().udiv(left, right),
255 (true, true) => ctx.builder.ins().srem(left, right),
256 (false, true) => ctx.builder.ins().urem(left, right),
257 };
258 ctx.builder.ins().jump(merge_block, &[BlockArg::Value(raw)]);
259 ctx.builder.seal_block(ok_block);
260
261 ctx.builder.switch_to_block(bad_block);
262 let fault_fn = self.arith_fault_fn.ok_or_else(|| anyhow!("VM arith fault runtime is not registered"))?;
263 let fault_ref = self.get_fn_ref(ctx, fault_fn);
264 ctx.builder.ins().call(fault_ref, &[]);
265 let zero = ctx.builder.ins().iconst(int_ty, 0);
266 ctx.builder.ins().jump(merge_block, &[BlockArg::Value(zero)]);
267 ctx.builder.seal_block(bad_block);
268
269 ctx.builder.switch_to_block(merge_block);
270 ctx.builder.seal_block(merge_block);
271 Ok(ctx.builder.block_params(merge_block)[0])
272 }
273
274 fn idiv_imm(&mut self, ctx: &mut BuildContext, left: Value, divisor: i64, signed: bool, is_rem: bool) -> Result<Value> {
282 let int_ty = ctx.builder.func.dfg.value_type(left);
283 if divisor == 0 {
284 let fault_fn = self.arith_fault_fn.ok_or_else(|| anyhow!("VM arith fault runtime is not registered"))?;
285 let fault_ref = self.get_fn_ref(ctx, fault_fn);
286 ctx.builder.ins().call(fault_ref, &[]);
287 return Ok(ctx.builder.ins().iconst(int_ty, 0));
288 }
289 if signed && divisor == -1 {
290 let rv = ctx.builder.ins().iconst(int_ty, -1);
291 return self.guarded_idiv(ctx, left, rv, true, is_rem);
292 }
293 Ok(match (signed, is_rem) {
294 (true, false) => ctx.builder.ins().sdiv_imm(left, divisor),
295 (false, false) => ctx.builder.ins().udiv_imm(left, divisor),
296 (true, true) => ctx.builder.ins().srem_imm(left, divisor),
297 (false, true) => ctx.builder.ins().urem_imm(left, divisor),
298 })
299 }
300
301 pub(crate) fn binary_with_expected(&mut self, ctx: &mut BuildContext, left: (Value, Type), op: BinaryOp, right: &Expr, expected: Option<&Type>) -> Result<(Value, Type)> {
302 if matches!(op, BinaryOp::And | BinaryOp::Or) {
304 return self.short_circuit_logic(ctx, left, op, right);
305 }
306 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()) };
307 let right = if right.is_value() {
308 let right = right.clone().value()?;
309 if right.is_f32() {
310 (ctx.builder.ins().f32const(right.as_float().unwrap() as f32), Type::F32)
311 } else if right.is_f64() {
312 (ctx.builder.ins().f64const(right.as_float().unwrap() as f64), Type::F64)
313 } else if left.1.is_any() {
314 if right.is_int() {
315 (ctx.builder.ins().iconst(types::I64, right.as_int().unwrap()), Type::I64)
316 } else if right.is_null() {
317 self.call(ctx, self.get_method(&Type::Any, "null")?, vec![])?
318 } else {
319 ctx.get_const(&right)?
320 }
321 } else {
322 return self.binary_imm(ctx, left, op, right);
323 }
324 } else {
325 self.eval(ctx, right)?.get(ctx).ok_or_else(|| anyhow!("没有返回值: {:?}", right))?
326 };
327 let right_ty = right_ty_hint.as_ref().unwrap_or(&right.1);
328 let numeric_expected = expected.filter(|ty| (ty.is_int() || ty.is_uint() || ty.is_float()) && (left.1.is_any() || right.1.is_any()));
329 let ty = if (op.is_add() || op.is_logic()) && (left.1.is_str() || right.1.is_str() || right_ty.is_str()) {
330 Type::Str
331 } else if !op.is_logic()
332 && let Some(expected) = numeric_expected
333 {
334 expected.clone()
335 } else if (op.is_add() || op.is_logic()) && (left.1.is_any() || right.1.is_any()) {
336 Type::Any
337 } else {
338 left.1.clone() + right.1.clone()
339 }; if ty.is_str() && op.is_add() {
341 if op == BinaryOp::AddAssign {
342 let left = self.convert(ctx, left, Type::Any)?;
343 let right = self.convert(ctx, right, Type::Any)?;
344 return Ok((self.strcat_assign(ctx, left, right)?, ty));
345 }
346 if left.1.is_str() && right.1.is_str() {
347 return Ok((self.strcat(ctx, left.0, right.0)?, Type::Str));
348 }
349 if left.1.is_str() && right.1.is_int() {
350 let right = self.convert(ctx, right, Type::I64)?;
351 return Ok((self.strcat_i64(ctx, left.0, right)?, Type::Str));
352 }
353 let left = self.convert(ctx, left, Type::Any)?;
354 let right = self.convert(ctx, right, Type::Any)?;
355 let result = self.any_binary(ctx, left, op, right)?.0;
356 return Ok((result, ty));
357 }
358 let left = self.convert(ctx, left, ty.clone())?;
359 let right = self.convert(ctx, right, ty.clone())?;
360 if ty.is_any() {
361 if op.is_logic() {
362 return self.any_logic(ctx, left, op, right);
363 } else {
364 return self.any_binary(ctx, left, op, right);
365 }
366 }
367 if ty.is_str() && op.is_logic() {
368 return self.any_logic(ctx, left, op, right);
369 }
370 match op {
371 BinaryOp::Add | BinaryOp::AddAssign => {
372 if ty.is_int() || ty.is_uint() {
373 return Ok((ctx.builder.ins().iadd(left, right), ty));
374 } else if ty.is_float() {
375 return Ok((ctx.builder.ins().fadd(left, right), ty));
376 } else if ty.is_str() {
377 let result = self.any_binary(ctx, left, op, right)?.0;
378 return Ok((result, ty));
379 }
380 }
381 BinaryOp::Sub | BinaryOp::SubAssign => {
382 if ty.is_int() || ty.is_uint() {
383 return Ok((ctx.builder.ins().isub(left, right), ty));
384 } else if ty.is_float() {
385 return Ok((ctx.builder.ins().fsub(left, right), ty));
386 }
387 }
388 BinaryOp::Mul | BinaryOp::MulAssign => {
389 if ty.is_int() || ty.is_uint() {
390 return Ok((ctx.builder.ins().imul(left, right), ty));
391 } else if ty.is_float() {
392 return Ok((ctx.builder.ins().fmul(left, right), ty));
393 }
394 }
395 BinaryOp::Div | BinaryOp::DivAssign => {
396 if ty.is_int() {
397 return Ok((self.guarded_idiv(ctx, left, right, true, false)?, ty));
398 } else if ty.is_uint() {
399 return Ok((self.guarded_idiv(ctx, left, right, false, false)?, ty));
400 } else if ty.is_float() {
401 return Ok((ctx.builder.ins().fdiv(left, right), ty));
402 }
403 }
404 BinaryOp::Mod | BinaryOp::ModAssign => {
405 if ty.is_int() {
406 return Ok((self.guarded_idiv(ctx, left, right, true, true)?, ty));
407 } else if ty.is_uint() {
408 return Ok((self.guarded_idiv(ctx, left, right, false, true)?, ty));
409 }
410 }
411 BinaryOp::Shl | BinaryOp::ShlAssign => {
412 if ty.is_int() || ty.is_uint() {
413 return Ok((ctx.builder.ins().ishl(left, right), ty));
414 }
415 }
416 BinaryOp::Shr | BinaryOp::ShrAssign => {
417 if ty.is_int() {
418 return Ok((ctx.builder.ins().sshr(left, right), ty));
419 } else if ty.is_uint() {
420 return Ok((ctx.builder.ins().ushr(left, right), ty));
421 }
422 }
423 BinaryOp::BitAnd | BinaryOp::BitAndAssign => {
424 return Ok((ctx.builder.ins().band(left, right), ty));
425 }
426 BinaryOp::BitOr | BinaryOp::BitOrAssign => {
427 return Ok((ctx.builder.ins().bor(left, right), ty));
428 }
429 BinaryOp::BitXor | BinaryOp::BitXorAssign => {
430 return Ok((ctx.builder.ins().bxor(left, right), ty));
431 }
432 BinaryOp::Eq => {
433 if ty.is_int() | ty.is_uint() || ty.is_bool() {
434 return Ok((ctx.builder.ins().icmp(IntCC::Equal, left, right), Type::Bool));
435 } else if ty.is_float() {
436 return Ok((ctx.builder.ins().fcmp(FloatCC::Equal, left, right), Type::Bool));
437 }
438 }
439 BinaryOp::Ne => {
440 if ty.is_int() | ty.is_uint() || ty.is_bool() {
441 return Ok((ctx.builder.ins().icmp(IntCC::NotEqual, left, right), Type::Bool));
442 } else if ty.is_float() {
443 return Ok((ctx.builder.ins().fcmp(FloatCC::NotEqual, left, right), Type::Bool));
444 }
445 }
446 BinaryOp::Lt => {
447 if ty.is_int() {
448 return Ok((ctx.builder.ins().icmp(IntCC::SignedLessThan, left, right), Type::Bool));
449 } else if ty.is_uint() {
450 return Ok((ctx.builder.ins().icmp(IntCC::UnsignedLessThan, left, right), Type::Bool));
451 } else if ty.is_float() {
452 return Ok((ctx.builder.ins().fcmp(FloatCC::LessThan, left, right), Type::Bool));
453 }
454 }
455 BinaryOp::Le => {
456 if ty.is_int() {
457 return Ok((ctx.builder.ins().icmp(IntCC::SignedLessThanOrEqual, left, right), Type::Bool));
458 } else if ty.is_uint() {
459 return Ok((ctx.builder.ins().icmp(IntCC::UnsignedLessThanOrEqual, left, right), Type::Bool));
460 } else if ty.is_float() {
461 return Ok((ctx.builder.ins().fcmp(FloatCC::LessThanOrEqual, left, right), Type::Bool));
462 }
463 }
464 BinaryOp::Gt => {
465 if ty.is_int() {
466 return Ok((ctx.builder.ins().icmp(IntCC::SignedGreaterThan, left, right), Type::Bool));
467 } else if ty.is_uint() {
468 return Ok((ctx.builder.ins().icmp(IntCC::UnsignedGreaterThan, left, right), Type::Bool));
469 } else if ty.is_float() {
470 return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThan, left, right), Type::Bool));
471 }
472 }
473 BinaryOp::Ge => {
474 if ty.is_int() {
475 return Ok((ctx.builder.ins().icmp(IntCC::SignedGreaterThanOrEqual, left, right), Type::Bool));
476 } else if ty.is_uint() {
477 return Ok((ctx.builder.ins().icmp(IntCC::UnsignedGreaterThanOrEqual, left, right), Type::Bool));
478 } else if ty.is_float() {
479 return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThanOrEqual, left, right), Type::Bool));
480 }
481 }
482 _ => {}
483 }
484 log::debug!("binary_with_expected fallback to dynamic: {:?} {:?} {:?}", ty, op, right);
486 let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
487 let right_any = self.convert(ctx, (right, ty.clone()), Type::Any)?;
488 if op.is_logic() { self.any_logic(ctx, left_any, op, right_any) } else { self.any_binary(ctx, left_any, op, right_any) }
489 }
490
491 pub(crate) fn binary_imm<'a>(&mut self, ctx: &'a mut BuildContext, left: (Value, Type), op: BinaryOp, right: Dynamic) -> Result<(Value, Type)> {
492 let ty = left.1.clone() + right.get_type();
493 let bool_imm = || right.as_bool().map(|value| if value { 1 } else { 0 });
494 if ty.is_str() && op.is_add() {
495 if op == BinaryOp::AddAssign {
496 let left = self.convert(ctx, left, Type::Any)?;
497 let right_vt = ctx.get_const(&right).or_else(|_| {
498 let idx = self.compiler.get_const(right.clone());
499 self.get_const_value(ctx, idx)
500 })?;
501 let right = self.convert(ctx, right_vt, Type::Any)?;
502 return Ok((self.strcat_assign(ctx, left, right)?, ty));
503 }
504 if left.1.is_str() && right.is_str() {
505 let right_vt = ctx.get_const(&right).or_else(|_| {
506 let idx = self.compiler.get_const(right.clone());
507 self.get_const_value(ctx, idx)
508 })?;
509 let right = self.convert(ctx, right_vt, Type::Str)?;
510 return Ok((self.strcat(ctx, left.0, right)?, Type::Str));
511 }
512 if left.1.is_str() && right.is_int() {
513 let right = ctx.get_const(&right)?;
514 let right = self.convert(ctx, right, Type::I64)?;
515 return Ok((self.strcat_i64(ctx, left.0, right)?, Type::Str));
516 }
517 let left = self.convert(ctx, left, Type::Any)?;
518 let right_vt = ctx.get_const(&right).or_else(|_| {
519 let idx = self.compiler.get_const(right.clone());
520 self.get_const_value(ctx, idx)
521 })?;
522 let right = self.convert(ctx, right_vt, Type::Any)?;
523 let result = self.any_binary(ctx, left, op, right)?.0;
524 return Ok((result, ty));
525 }
526 let left = self.convert(ctx, left, ty.clone())?;
527 if ty.is_str() && op.is_logic() {
528 let right_vt = ctx.get_const(&right).or_else(|_| {
529 let idx = self.compiler.get_const(right.clone());
530 self.get_const_value(ctx, idx)
531 })?;
532 let right = self.convert(ctx, right_vt, Type::Str)?;
533 return self.any_logic(ctx, left, op, right);
534 }
535 let right_float = if ty.is_float() {
536 let right = right.as_float().ok_or(anyhow!("非数字"))?;
537 Some(if ty.is_f32() { ctx.builder.ins().f32const(right as f32) } else { ctx.builder.ins().f64const(right) })
538 } else {
539 None
540 };
541 match op {
542 BinaryOp::Add | BinaryOp::AddAssign => {
543 if ty.is_str() {
544 let right_vt = ctx.get_const(&right).or_else(|_| {
545 let idx = self.compiler.get_const(right.clone());
546 self.get_const_value(ctx, idx)
547 })?;
548 let right = self.convert(ctx, right_vt, Type::Str)?;
549 let result = self.any_binary(ctx, left, op, right)?.0;
550 return Ok((result, ty));
551 }
552 if ty.is_int() | ty.is_uint() {
553 return Ok((ctx.builder.ins().iadd_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
554 } else if ty.is_float() {
555 return Ok((ctx.builder.ins().fadd(left, right_float.unwrap()), ty));
556 }
557 }
558 BinaryOp::Sub | BinaryOp::SubAssign => {
559 if ty.is_int() | ty.is_uint() {
560 return Ok((ctx.builder.ins().iadd_imm(left, -right.as_int().ok_or(anyhow!("非整数"))?), ty));
561 } else if ty.is_float() {
562 return Ok((ctx.builder.ins().fsub(left, right_float.unwrap()), ty));
563 }
564 }
565 BinaryOp::Mul | BinaryOp::MulAssign => {
566 if ty.is_int() | ty.is_uint() {
567 return Ok((ctx.builder.ins().imul_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
568 } else if ty.is_float() {
569 return Ok((ctx.builder.ins().fmul(left, right_float.unwrap()), ty));
570 }
571 }
572 BinaryOp::Div | BinaryOp::DivAssign => {
573 if ty.is_int() || ty.is_uint() {
574 let divisor = right.as_int().ok_or(anyhow!("非整数"))?;
575 return Ok((self.idiv_imm(ctx, left, divisor, ty.is_int(), false)?, ty));
576 } else if ty.is_float() {
577 return Ok((ctx.builder.ins().fdiv(left, right_float.unwrap()), ty));
578 }
579 }
580 BinaryOp::Shl | BinaryOp::ShlAssign => {
581 if ty.is_int() || ty.is_uint() {
582 return Ok((ctx.builder.ins().ishl_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
583 }
584 }
585 BinaryOp::Shr | BinaryOp::ShrAssign => {
586 if ty.is_int() {
587 return Ok((ctx.builder.ins().sshr_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
588 } else if ty.is_uint() {
589 return Ok((ctx.builder.ins().ushr_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
590 }
591 }
592 BinaryOp::BitAnd | BinaryOp::BitAndAssign => {
593 return Ok((ctx.builder.ins().band_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
594 }
595 BinaryOp::BitOr | BinaryOp::BitOrAssign => {
596 return Ok((ctx.builder.ins().bor_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
597 }
598 BinaryOp::BitXor | BinaryOp::BitXorAssign => {
599 return Ok((ctx.builder.ins().bxor_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
600 }
601 BinaryOp::Eq => {
602 if ty.is_int() | ty.is_uint() {
603 return Ok((ctx.builder.ins().icmp_imm(IntCC::Equal, left, right.as_int().unwrap()), Type::Bool));
604 } else if ty.is_bool() {
605 return Ok((ctx.builder.ins().icmp_imm(IntCC::Equal, left, bool_imm().unwrap()), Type::Bool));
606 } else if ty.is_float() {
607 return Ok((ctx.builder.ins().fcmp(FloatCC::Equal, left, right_float.unwrap()), Type::Bool));
608 }
609 }
610 BinaryOp::Ne => {
611 if ty.is_int() | ty.is_uint() {
612 return Ok((ctx.builder.ins().icmp_imm(IntCC::NotEqual, left, right.as_int().unwrap()), Type::Bool));
613 } else if ty.is_bool() {
614 return Ok((ctx.builder.ins().icmp_imm(IntCC::NotEqual, left, bool_imm().unwrap()), Type::Bool));
615 } else if ty.is_float() {
616 return Ok((ctx.builder.ins().fcmp(FloatCC::NotEqual, left, right_float.unwrap()), Type::Bool));
617 }
618 }
619 BinaryOp::Le => {
620 if ty.is_int() {
621 return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedLessThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
622 } else if ty.is_uint() {
623 return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedLessThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
624 } else if ty.is_float() {
625 return Ok((ctx.builder.ins().fcmp(FloatCC::LessThanOrEqual, left, right_float.unwrap()), Type::Bool));
626 }
627 }
628 BinaryOp::Lt => {
629 if ty.is_int() {
630 return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedLessThan, left, right.as_int().unwrap()), Type::Bool));
631 } else if ty.is_uint() {
632 return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedLessThan, left, right.as_int().unwrap()), Type::Bool));
633 } else if ty.is_float() {
634 return Ok((ctx.builder.ins().fcmp(FloatCC::LessThan, left, right_float.unwrap()), Type::Bool));
635 }
636 }
637 BinaryOp::Ge => {
638 if ty.is_int() {
639 return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
640 } else if ty.is_uint() {
641 return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedGreaterThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
642 } else if ty.is_float() {
643 return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThanOrEqual, left, right_float.unwrap()), Type::Bool));
644 }
645 }
646 BinaryOp::Gt => {
647 if ty.is_int() {
648 return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedGreaterThan, left, right.as_int().unwrap()), Type::Bool));
649 } else if ty.is_uint() {
650 return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedGreaterThan, left, right.as_int().unwrap()), Type::Bool));
651 } else if ty.is_float() {
652 return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThan, left, right_float.unwrap()), Type::Bool));
653 }
654 }
655 BinaryOp::Mod | BinaryOp::ModAssign => {
656 if ty.is_int() || ty.is_uint() {
657 let divisor = right.as_int().ok_or(anyhow!("非整数"))?;
658 return Ok((self.idiv_imm(ctx, left, divisor, ty.is_int(), true)?, ty));
659 }
660 }
661 exp => {
662 log::debug!("binary_imm fallback to dynamic (unsupported op): {:?} {:?}", ty, exp);
664 let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
665 let right_vt = ctx.get_const(&right).or_else(|_| {
666 let idx = self.compiler.get_const(right.clone());
667 self.get_const_value(ctx, idx)
668 })?;
669 let right_any = self.convert(ctx, right_vt, Type::Any)?;
670 if exp.is_logic() {
671 return self.any_logic(ctx, left_any, exp, right_any);
672 }
673 return self.any_binary(ctx, left_any, exp, right_any);
674 }
675 }
676 log::debug!("binary_imm fallback to dynamic (unsupported type combo): {:?} {:?} {:?}", ty, op, right.get_type());
678 let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
679 let right_vt = ctx.get_const(&right).or_else(|_| {
680 let idx = self.compiler.get_const(right.clone());
681 self.get_const_value(ctx, idx)
682 })?;
683 let right_any = self.convert(ctx, right_vt, Type::Any)?;
684 if op.is_logic() { self.any_logic(ctx, left_any, op, right_any) } else { self.any_binary(ctx, left_any, op, right_any) }
685 }
686}