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 pub(crate) fn binary_with_expected(&mut self, ctx: &mut BuildContext, left: (Value, Type), op: BinaryOp, right: &Expr, expected: Option<&Type>) -> Result<(Value, Type)> {
275 if matches!(op, BinaryOp::And | BinaryOp::Or) {
277 return self.short_circuit_logic(ctx, left, op, right);
278 }
279 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()) };
280 let right = if right.is_value() {
281 let right = right.clone().value()?;
282 if right.is_f32() {
283 (ctx.builder.ins().f32const(right.as_float().unwrap() as f32), Type::F32)
284 } else if right.is_f64() {
285 (ctx.builder.ins().f64const(right.as_float().unwrap() as f64), Type::F64)
286 } else if left.1.is_any() {
287 if right.is_int() {
288 (ctx.builder.ins().iconst(types::I64, right.as_int().unwrap()), Type::I64)
289 } else if right.is_null() {
290 self.call(ctx, self.get_method(&Type::Any, "null")?, vec![])?
291 } else {
292 ctx.get_const(&right)?
293 }
294 } else {
295 return self.binary_imm(ctx, left, op, right);
296 }
297 } else {
298 self.eval(ctx, right)?.get(ctx).ok_or_else(|| anyhow!("没有返回值: {:?}", right))?
299 };
300 let right_ty = right_ty_hint.as_ref().unwrap_or(&right.1);
301 let numeric_expected = expected.filter(|ty| (ty.is_int() || ty.is_uint() || ty.is_float()) && (left.1.is_any() || right.1.is_any()));
302 let ty = if (op.is_add() || op.is_logic()) && (left.1.is_str() || right.1.is_str() || right_ty.is_str()) {
303 Type::Str
304 } else if !op.is_logic()
305 && let Some(expected) = numeric_expected
306 {
307 expected.clone()
308 } else if (op.is_add() || op.is_logic()) && (left.1.is_any() || right.1.is_any()) {
309 Type::Any
310 } else {
311 left.1.clone() + right.1.clone()
312 }; if ty.is_str() && op.is_add() {
314 if op == BinaryOp::AddAssign {
315 let left = self.convert(ctx, left, Type::Any)?;
316 let right = self.convert(ctx, right, Type::Any)?;
317 return Ok((self.strcat_assign(ctx, left, right)?, ty));
318 }
319 if left.1.is_str() && right.1.is_str() {
320 return Ok((self.strcat(ctx, left.0, right.0)?, Type::Str));
321 }
322 if left.1.is_str() && right.1.is_int() {
323 let right = self.convert(ctx, right, Type::I64)?;
324 return Ok((self.strcat_i64(ctx, left.0, right)?, Type::Str));
325 }
326 let left = self.convert(ctx, left, Type::Any)?;
327 let right = self.convert(ctx, right, Type::Any)?;
328 let result = self.any_binary(ctx, left, op, right)?.0;
329 return Ok((result, ty));
330 }
331 let left = self.convert(ctx, left, ty.clone())?;
332 let right = self.convert(ctx, right, ty.clone())?;
333 if ty.is_any() {
334 if op.is_logic() {
335 return self.any_logic(ctx, left, op, right);
336 } else {
337 return self.any_binary(ctx, left, op, right);
338 }
339 }
340 if ty.is_str() && op.is_logic() {
341 return self.any_logic(ctx, left, op, right);
342 }
343 match op {
344 BinaryOp::Add | BinaryOp::AddAssign => {
345 if ty.is_int() || ty.is_uint() {
346 return Ok((ctx.builder.ins().iadd(left, right), ty));
347 } else if ty.is_float() {
348 return Ok((ctx.builder.ins().fadd(left, right), ty));
349 } else if ty.is_str() {
350 let result = self.any_binary(ctx, left, op, right)?.0;
351 return Ok((result, ty));
352 }
353 }
354 BinaryOp::Sub | BinaryOp::SubAssign => {
355 if ty.is_int() || ty.is_uint() {
356 return Ok((ctx.builder.ins().isub(left, right), ty));
357 } else if ty.is_float() {
358 return Ok((ctx.builder.ins().fsub(left, right), ty));
359 }
360 }
361 BinaryOp::Mul | BinaryOp::MulAssign => {
362 if ty.is_int() || ty.is_uint() {
363 return Ok((ctx.builder.ins().imul(left, right), ty));
364 } else if ty.is_float() {
365 return Ok((ctx.builder.ins().fmul(left, right), ty));
366 }
367 }
368 BinaryOp::Div | BinaryOp::DivAssign => {
369 if ty.is_int() {
370 return Ok((self.guarded_idiv(ctx, left, right, true, false)?, ty));
371 } else if ty.is_uint() {
372 return Ok((self.guarded_idiv(ctx, left, right, false, false)?, ty));
373 } else if ty.is_float() {
374 return Ok((ctx.builder.ins().fdiv(left, right), ty));
375 }
376 }
377 BinaryOp::Mod | BinaryOp::ModAssign => {
378 if ty.is_int() {
379 return Ok((self.guarded_idiv(ctx, left, right, true, true)?, ty));
380 } else if ty.is_uint() {
381 return Ok((self.guarded_idiv(ctx, left, right, false, true)?, ty));
382 }
383 }
384 BinaryOp::Shl | BinaryOp::ShlAssign => {
385 if ty.is_int() || ty.is_uint() {
386 return Ok((ctx.builder.ins().ishl(left, right), ty));
387 }
388 }
389 BinaryOp::Shr | BinaryOp::ShrAssign => {
390 if ty.is_int() {
391 return Ok((ctx.builder.ins().sshr(left, right), ty));
392 } else if ty.is_uint() {
393 return Ok((ctx.builder.ins().ushr(left, right), ty));
394 }
395 }
396 BinaryOp::BitAnd | BinaryOp::BitAndAssign => {
397 return Ok((ctx.builder.ins().band(left, right), ty));
398 }
399 BinaryOp::BitOr | BinaryOp::BitOrAssign => {
400 return Ok((ctx.builder.ins().bor(left, right), ty));
401 }
402 BinaryOp::BitXor | BinaryOp::BitXorAssign => {
403 return Ok((ctx.builder.ins().bxor(left, right), ty));
404 }
405 BinaryOp::Eq => {
406 if ty.is_int() | ty.is_uint() || ty.is_bool() {
407 return Ok((ctx.builder.ins().icmp(IntCC::Equal, left, right), Type::Bool));
408 } else if ty.is_float() {
409 return Ok((ctx.builder.ins().fcmp(FloatCC::Equal, left, right), Type::Bool));
410 }
411 }
412 BinaryOp::Ne => {
413 if ty.is_int() | ty.is_uint() || ty.is_bool() {
414 return Ok((ctx.builder.ins().icmp(IntCC::NotEqual, left, right), Type::Bool));
415 } else if ty.is_float() {
416 return Ok((ctx.builder.ins().fcmp(FloatCC::NotEqual, left, right), Type::Bool));
417 }
418 }
419 BinaryOp::Lt => {
420 if ty.is_int() {
421 return Ok((ctx.builder.ins().icmp(IntCC::SignedLessThan, left, right), Type::Bool));
422 } else if ty.is_uint() {
423 return Ok((ctx.builder.ins().icmp(IntCC::UnsignedLessThan, left, right), Type::Bool));
424 } else if ty.is_float() {
425 return Ok((ctx.builder.ins().fcmp(FloatCC::LessThan, left, right), Type::Bool));
426 }
427 }
428 BinaryOp::Le => {
429 if ty.is_int() {
430 return Ok((ctx.builder.ins().icmp(IntCC::SignedLessThanOrEqual, left, right), Type::Bool));
431 } else if ty.is_uint() {
432 return Ok((ctx.builder.ins().icmp(IntCC::UnsignedLessThanOrEqual, left, right), Type::Bool));
433 } else if ty.is_float() {
434 return Ok((ctx.builder.ins().fcmp(FloatCC::LessThanOrEqual, left, right), Type::Bool));
435 }
436 }
437 BinaryOp::Gt => {
438 if ty.is_int() {
439 return Ok((ctx.builder.ins().icmp(IntCC::SignedGreaterThan, left, right), Type::Bool));
440 } else if ty.is_uint() {
441 return Ok((ctx.builder.ins().icmp(IntCC::UnsignedGreaterThan, left, right), Type::Bool));
442 } else if ty.is_float() {
443 return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThan, left, right), Type::Bool));
444 }
445 }
446 BinaryOp::Ge => {
447 if ty.is_int() {
448 return Ok((ctx.builder.ins().icmp(IntCC::SignedGreaterThanOrEqual, left, right), Type::Bool));
449 } else if ty.is_uint() {
450 return Ok((ctx.builder.ins().icmp(IntCC::UnsignedGreaterThanOrEqual, left, right), Type::Bool));
451 } else if ty.is_float() {
452 return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThanOrEqual, left, right), Type::Bool));
453 }
454 }
455 _ => {}
456 }
457 log::debug!("binary_with_expected fallback to dynamic: {:?} {:?} {:?}", ty, op, right);
459 let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
460 let right_any = self.convert(ctx, (right, ty.clone()), Type::Any)?;
461 if op.is_logic() {
462 self.any_logic(ctx, left_any, op, right_any)
463 } else {
464 self.any_binary(ctx, left_any, op, right_any)
465 }
466 }
467
468 pub(crate) fn binary_imm<'a>(&mut self, ctx: &'a mut BuildContext, left: (Value, Type), op: BinaryOp, right: Dynamic) -> Result<(Value, Type)> {
469 let ty = left.1.clone() + right.get_type();
470 let bool_imm = || right.as_bool().map(|value| if value { 1 } else { 0 });
471 if ty.is_str() && op.is_add() {
472 if op == BinaryOp::AddAssign {
473 let left = self.convert(ctx, left, Type::Any)?;
474 let right_vt = ctx.get_const(&right).or_else(|_| {
475 let idx = self.compiler.get_const(right.clone());
476 self.get_const_value(ctx, idx)
477 })?;
478 let right = self.convert(ctx, right_vt, Type::Any)?;
479 return Ok((self.strcat_assign(ctx, left, right)?, ty));
480 }
481 if left.1.is_str() && right.is_str() {
482 let right_vt = ctx.get_const(&right).or_else(|_| {
483 let idx = self.compiler.get_const(right.clone());
484 self.get_const_value(ctx, idx)
485 })?;
486 let right = self.convert(ctx, right_vt, Type::Str)?;
487 return Ok((self.strcat(ctx, left.0, right)?, Type::Str));
488 }
489 if left.1.is_str() && right.is_int() {
490 let right = ctx.get_const(&right)?;
491 let right = self.convert(ctx, right, Type::I64)?;
492 return Ok((self.strcat_i64(ctx, left.0, right)?, Type::Str));
493 }
494 let left = self.convert(ctx, left, Type::Any)?;
495 let right_vt = ctx.get_const(&right).or_else(|_| {
496 let idx = self.compiler.get_const(right.clone());
497 self.get_const_value(ctx, idx)
498 })?;
499 let right = self.convert(ctx, right_vt, Type::Any)?;
500 let result = self.any_binary(ctx, left, op, right)?.0;
501 return Ok((result, ty));
502 }
503 let left = self.convert(ctx, left, ty.clone())?;
504 if ty.is_str() && op.is_logic() {
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 self.any_logic(ctx, left, op, right);
511 }
512 let right_float = if ty.is_float() {
513 let right = right.as_float().ok_or(anyhow!("非数字"))?;
514 Some(if ty.is_f32() { ctx.builder.ins().f32const(right as f32) } else { ctx.builder.ins().f64const(right) })
515 } else {
516 None
517 };
518 match op {
519 BinaryOp::Add | BinaryOp::AddAssign => {
520 if ty.is_str() {
521 let right_vt = ctx.get_const(&right).or_else(|_| {
522 let idx = self.compiler.get_const(right.clone());
523 self.get_const_value(ctx, idx)
524 })?;
525 let right = self.convert(ctx, right_vt, Type::Str)?;
526 let result = self.any_binary(ctx, left, op, right)?.0;
527 return Ok((result, ty));
528 }
529 if ty.is_int() | ty.is_uint() {
530 return Ok((ctx.builder.ins().iadd_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
531 } else if ty.is_float() {
532 return Ok((ctx.builder.ins().fadd(left, right_float.unwrap()), ty));
533 }
534 }
535 BinaryOp::Sub | BinaryOp::SubAssign => {
536 if ty.is_int() | ty.is_uint() {
537 return Ok((ctx.builder.ins().iadd_imm(left, -right.as_int().ok_or(anyhow!("非整数"))?), ty));
538 } else if ty.is_float() {
539 return Ok((ctx.builder.ins().fsub(left, right_float.unwrap()), ty));
540 }
541 }
542 BinaryOp::Mul | BinaryOp::MulAssign => {
543 if ty.is_int() | ty.is_uint() {
544 return Ok((ctx.builder.ins().imul_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
545 } else if ty.is_float() {
546 return Ok((ctx.builder.ins().fmul(left, right_float.unwrap()), ty));
547 }
548 }
549 BinaryOp::Div | BinaryOp::DivAssign => {
550 if ty.is_int() || ty.is_uint() {
551 let int_ty = ctx.builder.func.dfg.value_type(left);
552 let rv = ctx.builder.ins().iconst(int_ty, right.as_int().ok_or(anyhow!("非整数"))?);
553 return Ok((self.guarded_idiv(ctx, left, rv, ty.is_int(), false)?, ty));
554 } else if ty.is_float() {
555 return Ok((ctx.builder.ins().fdiv(left, right_float.unwrap()), ty));
556 }
557 }
558 BinaryOp::Shl | BinaryOp::ShlAssign => {
559 if ty.is_int() || ty.is_uint() {
560 return Ok((ctx.builder.ins().ishl_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
561 }
562 }
563 BinaryOp::Shr | BinaryOp::ShrAssign => {
564 if ty.is_int() {
565 return Ok((ctx.builder.ins().sshr_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
566 } else if ty.is_uint() {
567 return Ok((ctx.builder.ins().ushr_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
568 }
569 }
570 BinaryOp::BitAnd | BinaryOp::BitAndAssign => {
571 return Ok((ctx.builder.ins().band_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
572 }
573 BinaryOp::BitOr | BinaryOp::BitOrAssign => {
574 return Ok((ctx.builder.ins().bor_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
575 }
576 BinaryOp::BitXor | BinaryOp::BitXorAssign => {
577 return Ok((ctx.builder.ins().bxor_imm(left, right.as_int().ok_or(anyhow!("非整数"))?), ty));
578 }
579 BinaryOp::Eq => {
580 if ty.is_int() | ty.is_uint() {
581 return Ok((ctx.builder.ins().icmp_imm(IntCC::Equal, left, right.as_int().unwrap()), Type::Bool));
582 } else if ty.is_bool() {
583 return Ok((ctx.builder.ins().icmp_imm(IntCC::Equal, left, bool_imm().unwrap()), Type::Bool));
584 } else if ty.is_float() {
585 return Ok((ctx.builder.ins().fcmp(FloatCC::Equal, left, right_float.unwrap()), Type::Bool));
586 }
587 }
588 BinaryOp::Ne => {
589 if ty.is_int() | ty.is_uint() {
590 return Ok((ctx.builder.ins().icmp_imm(IntCC::NotEqual, left, right.as_int().unwrap()), Type::Bool));
591 } else if ty.is_bool() {
592 return Ok((ctx.builder.ins().icmp_imm(IntCC::NotEqual, left, bool_imm().unwrap()), Type::Bool));
593 } else if ty.is_float() {
594 return Ok((ctx.builder.ins().fcmp(FloatCC::NotEqual, left, right_float.unwrap()), Type::Bool));
595 }
596 }
597 BinaryOp::Le => {
598 if ty.is_int() {
599 return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedLessThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
600 } else if ty.is_uint() {
601 return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedLessThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
602 } else if ty.is_float() {
603 return Ok((ctx.builder.ins().fcmp(FloatCC::LessThanOrEqual, left, right_float.unwrap()), Type::Bool));
604 }
605 }
606 BinaryOp::Lt => {
607 if ty.is_int() {
608 return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedLessThan, left, right.as_int().unwrap()), Type::Bool));
609 } else if ty.is_uint() {
610 return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedLessThan, left, right.as_int().unwrap()), Type::Bool));
611 } else if ty.is_float() {
612 return Ok((ctx.builder.ins().fcmp(FloatCC::LessThan, left, right_float.unwrap()), Type::Bool));
613 }
614 }
615 BinaryOp::Ge => {
616 if ty.is_int() {
617 return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedGreaterThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
618 } else if ty.is_uint() {
619 return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedGreaterThanOrEqual, left, right.as_int().unwrap()), Type::Bool));
620 } else if ty.is_float() {
621 return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThanOrEqual, left, right_float.unwrap()), Type::Bool));
622 }
623 }
624 BinaryOp::Gt => {
625 if ty.is_int() {
626 return Ok((ctx.builder.ins().icmp_imm(IntCC::SignedGreaterThan, left, right.as_int().unwrap()), Type::Bool));
627 } else if ty.is_uint() {
628 return Ok((ctx.builder.ins().icmp_imm(IntCC::UnsignedGreaterThan, left, right.as_int().unwrap()), Type::Bool));
629 } else if ty.is_float() {
630 return Ok((ctx.builder.ins().fcmp(FloatCC::GreaterThan, left, right_float.unwrap()), Type::Bool));
631 }
632 }
633 BinaryOp::Mod | BinaryOp::ModAssign => {
634 if ty.is_int() || ty.is_uint() {
635 let int_ty = ctx.builder.func.dfg.value_type(left);
636 let rv = ctx.builder.ins().iconst(int_ty, right.as_int().ok_or(anyhow!("非整数"))?);
637 return Ok((self.guarded_idiv(ctx, left, rv, ty.is_int(), true)?, ty));
638 }
639 }
640 exp => {
641 log::debug!("binary_imm fallback to dynamic (unsupported op): {:?} {:?}", ty, exp);
643 let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
644 let right_vt = ctx.get_const(&right).or_else(|_| {
645 let idx = self.compiler.get_const(right.clone());
646 self.get_const_value(ctx, idx)
647 })?;
648 let right_any = self.convert(ctx, right_vt, Type::Any)?;
649 if exp.is_logic() {
650 return self.any_logic(ctx, left_any, exp, right_any);
651 }
652 return self.any_binary(ctx, left_any, exp, right_any);
653 }
654 }
655 log::debug!("binary_imm fallback to dynamic (unsupported type combo): {:?} {:?} {:?}", ty, op, right.get_type());
657 let left_any = self.convert(ctx, (left, ty.clone()), Type::Any)?;
658 let right_vt = ctx.get_const(&right).or_else(|_| {
659 let idx = self.compiler.get_const(right.clone());
660 self.get_const_value(ctx, idx)
661 })?;
662 let right_any = self.convert(ctx, right_vt, Type::Any)?;
663 if op.is_logic() {
664 self.any_logic(ctx, left_any, op, right_any)
665 } else {
666 self.any_binary(ctx, left_any, op, right_any)
667 }
668 }
669}