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