1use super::numtype::NumberTypes;
7use super::runtime;
8use cranelift::codegen::ir::{FuncRef, GlobalValue, InstBuilder, StackSlotData, StackSlotKind};
9use cranelift::prelude::*;
10use cranelift_frontend::FunctionBuilder;
11use ling_ast::ast::{BinOp, UnOp};
12use ling_mir::ir::*;
13use std::collections::HashMap;
14
15pub(crate) fn int_zero(builder: &mut FunctionBuilder) -> Value {
16 builder.ins().iconst(types::I64, 0)
17}
18
19pub(crate) fn int_one(builder: &mut FunctionBuilder) -> Value {
20 builder.ins().iconst(types::I64, 1)
21}
22
23pub(crate) fn build_function_body(
27 builder: &mut FunctionBuilder,
28 func: &MirFunction,
29 blocks: &[Block],
30 ctx: &TransCtx,
31) {
32 let vars = ctx.vars;
33 let pred_count = count_predecessors(func);
34 let mut sealed = vec![false; func.basic_blocks.len()];
35 let mut filled_pred = vec![0u32; func.basic_blocks.len()];
36
37 for bi in 0..func.basic_blocks.len() {
38 builder.switch_to_block(blocks[bi]);
39 if bi == 0 && !sealed[bi] {
40 builder.seal_block(blocks[bi]);
41 sealed[bi] = true;
42 }
43 if bi == 0 {
44 builder.append_block_params_for_function_params(blocks[bi]);
45 let params: Vec<Value> = builder.block_params(blocks[bi]).to_vec();
46 for (j, val) in params.iter().enumerate() {
47 if let Some(&var) = vars.get(&Local(j + 1)) {
48 builder.def_var(var, *val);
49 }
50 }
51 }
52
53 for stmt in &func.basic_blocks[bi].statements {
54 translate_stmt(stmt, builder, ctx);
55 }
56 if let Some(term) = &func.basic_blocks[bi].terminator {
57 translate_terminator(term, builder, blocks, ctx);
58 match &term.kind {
59 TerminatorKind::Goto { target } => {
60 filled_pred[target.0] += 1;
61 if filled_pred[target.0] == pred_count[target.0] && !sealed[target.0] {
62 builder.seal_block(blocks[target.0]);
63 sealed[target.0] = true;
64 }
65 },
66 TerminatorKind::SwitchInt { targets, otherwise, .. } => {
67 for (_, t) in targets {
68 filled_pred[t.0] += 1;
69 if filled_pred[t.0] == pred_count[t.0] && !sealed[t.0] {
70 builder.seal_block(blocks[t.0]);
71 sealed[t.0] = true;
72 }
73 }
74 filled_pred[otherwise.0] += 1;
75 if filled_pred[otherwise.0] == pred_count[otherwise.0] && !sealed[otherwise.0] {
76 builder.seal_block(blocks[otherwise.0]);
77 sealed[otherwise.0] = true;
78 }
79 },
80 _ => {},
81 }
82 }
83 }
84
85 for (i, block) in blocks.iter().enumerate() {
86 if !sealed[i] {
87 builder.seal_block(*block);
88 }
89 }
90}
91
92pub(crate) fn count_predecessors(func: &MirFunction) -> Vec<u32> {
93 let mut pred_count = vec![0u32; func.basic_blocks.len()];
94 for bb in &func.basic_blocks {
95 if let Some(term) = &bb.terminator {
96 match &term.kind {
97 TerminatorKind::Goto { target } => pred_count[target.0] += 1,
98 TerminatorKind::SwitchInt { targets, otherwise, .. } => {
99 for (_, t) in targets {
100 pred_count[t.0] += 1;
101 }
102 pred_count[otherwise.0] += 1;
103 },
104 _ => {},
105 }
106 }
107 }
108 pred_count
109}
110
111pub(crate) fn max_local_index(func: &MirFunction) -> usize {
112 let mut max = 0usize;
113 for bb in &func.basic_blocks {
115 for stmt in &bb.statements {
116 if let StatementKind::Assign(local, rval) = &stmt.kind {
117 max = max.max(local.0);
118 collect_local_from_rvalue(rval, &mut max);
119 }
120 if let StatementKind::SetAttr(obj, _, val) = &stmt.kind {
121 if let Operand::Copy(l) | Operand::Move(l) = obj {
122 max = max.max(l.0);
123 }
124 if let Operand::Copy(l) | Operand::Move(l) = val {
125 max = max.max(l.0);
126 }
127 }
128 if let StatementKind::SetIndex(obj, idx, val) = &stmt.kind {
129 if let Operand::Copy(l) | Operand::Move(l) = obj {
130 max = max.max(l.0);
131 }
132 if let Operand::Copy(l) | Operand::Move(l) = idx {
133 max = max.max(l.0);
134 }
135 if let Operand::Copy(l) | Operand::Move(l) = val {
136 max = max.max(l.0);
137 }
138 }
139 if let StatementKind::StorageLive(l)
140 | StatementKind::StorageDead(l)
141 | StatementKind::Drop(l) = &stmt.kind
142 {
143 max = max.max(l.0);
144 }
145 }
146 if let Some(term) = &bb.terminator {
147 if let TerminatorKind::SwitchInt {
148 discr: Operand::Copy(l) | Operand::Move(l), ..
149 } = &term.kind
150 {
151 max = max.max(l.0);
152 }
153 }
154 }
155 max = max.max(func.arg_count);
157 max
158}
159
160pub(crate) fn collect_local_from_rvalue(rval: &Rvalue, max: &mut usize) {
161 match rval {
162 Rvalue::Use(op) | Rvalue::UnaryOp(_, op) => {
163 if let Operand::Copy(l) | Operand::Move(l) = op {
164 *max = (*max).max(l.0);
165 }
166 },
167 Rvalue::BinaryOp(_, lhs, rhs) => {
168 if let Operand::Copy(l) | Operand::Move(l) = lhs {
169 *max = (*max).max(l.0);
170 }
171 if let Operand::Copy(l) | Operand::Move(l) = rhs {
172 *max = (*max).max(l.0);
173 }
174 },
175 Rvalue::Call { args, .. } => {
176 for arg in args {
177 if let Operand::Copy(l) | Operand::Move(l) = arg {
178 *max = (*max).max(l.0);
179 }
180 }
181 },
182 Rvalue::Aggregate(_, ops) => {
183 for op in ops {
184 if let Operand::Copy(l) | Operand::Move(l) = op {
185 *max = (*max).max(l.0);
186 }
187 }
188 },
189 Rvalue::GetAttr(op, _) | Rvalue::GetIndex(op, _) => {
190 if let Operand::Copy(l) | Operand::Move(l) = op {
191 *max = (*max).max(l.0);
192 }
193 },
194 Rvalue::Ref(l) | Rvalue::MutRef(l) => {
195 *max = (*max).max(l.0);
196 },
197 _ => {},
198 }
199}
200
201pub(crate) struct TransCtx<'a> {
204 pub vars: &'a HashMap<Local, Variable>,
205 pub string_gvs: &'a HashMap<String, GlobalValue>,
206 pub builtin_gvs: &'a HashMap<String, GlobalValue>,
207 pub runtime_refs: &'a HashMap<String, FuncRef>,
208 pub func_refs: &'a HashMap<String, FuncRef>,
209 pub nt: &'a NumberTypes,
210 pub fname: &'a str,
211}
212
213pub(crate) fn translate_stmt(stmt: &Statement, builder: &mut FunctionBuilder, ctx: &TransCtx) {
214 if let StatementKind::Assign(local, rvalue) = &stmt.kind {
215 let val = translate_rvalue(rvalue, builder, ctx);
216 if let Some(&var) = ctx.vars.get(local) {
217 builder.def_var(var, val);
218 }
219 }
220}
221
222pub(crate) fn translate_rvalue(
223 rvalue: &Rvalue,
224 builder: &mut FunctionBuilder,
225 ctx: &TransCtx,
226) -> Value {
227 match rvalue {
228 Rvalue::Use(op) => translate_op(op, builder, ctx),
229 Rvalue::BinaryOp(op, lhs, rhs) => {
230 let tys = OperandTypes {
231 both_num: ctx.nt.operand_is_num(ctx.fname, lhs)
232 && ctx.nt.operand_is_num(ctx.fname, rhs),
233 l_bool: ctx.nt.operand_is_bool(ctx.fname, lhs),
234 r_bool: ctx.nt.operand_is_bool(ctx.fname, rhs),
235 };
236 let lv = translate_op(lhs, builder, ctx);
237 let rv = translate_op(rhs, builder, ctx);
238 translate_binop(op, builder, lv, rv, tys, ctx.runtime_refs)
239 },
240 Rvalue::UnaryOp(op, operand) => {
241 let v = translate_op(operand, builder, ctx);
242 translate_unop(op, builder, v, ctx.runtime_refs)
243 },
244 Rvalue::Call { func: callee, args } => {
245 let callee_name = match callee {
246 Operand::Constant(Constant::Function(n)) => n.clone(),
247 _ => String::new(),
248 };
249 let mut cal_args = Vec::new();
250 for arg in args {
251 cal_args.push(translate_op(arg, builder, ctx));
252 }
253 if let Some(&fr) = ctx.func_refs.get(&callee_name) {
254 let inst = builder.ins().call(fr, &cal_args);
255 builder.inst_results(inst)[0]
256 } else {
257 emit_builtin_call(
258 callee_name,
259 cal_args,
260 builder,
261 ctx.builtin_gvs,
262 ctx.runtime_refs,
263 )
264 }
265 },
266 Rvalue::Aggregate(_, ops) => {
267 let mut list = emit_runtime_call0(builder, "__ling_list_new", ctx.runtime_refs);
268 for op in ops {
269 let v = translate_op(op, builder, ctx);
270 list = emit_runtime_call2(builder, "__ling_list_push", list, v, ctx.runtime_refs);
271 }
272 list
273 },
274 Rvalue::GetIndex(obj, idx) => {
275 let obj_val = translate_op(obj, builder, ctx);
276 let idx_val = translate_op(idx, builder, ctx);
277 emit_runtime_call2(
278 builder,
279 "__ling_list_get",
280 obj_val,
281 idx_val,
282 ctx.runtime_refs,
283 )
284 },
285 _ => int_zero(builder),
286 }
287}
288
289pub(crate) fn translate_op(op: &Operand, builder: &mut FunctionBuilder, ctx: &TransCtx) -> Value {
290 let TransCtx { vars, string_gvs, runtime_refs, .. } = ctx;
291 match op {
292 Operand::Copy(l) | Operand::Move(l) => builder.use_var(vars[l]),
293 Operand::Constant(c) => match c {
294 Constant::I64(v) => {
295 let bits = (*v as f64).to_bits();
296 builder.ins().iconst(types::I64, bits as i64)
297 },
298 Constant::F64(v) => builder.ins().iconst(types::I64, *v as i64),
299 Constant::Bool(b) => builder.ins().iconst(
300 types::I64,
301 if *b {
302 runtime::TAG_TRUE as i64
303 } else {
304 runtime::TAG_FALSE as i64
305 },
306 ),
307 Constant::Str(s) => {
308 if let Some(&gv) = string_gvs.get(s.as_str()) {
309 let ptr = builder.ins().symbol_value(types::I64, gv);
310 let len = builder.ins().iconst(types::I64, s.len() as i64);
311 let fr = *runtime_refs.get("__ling_str_new").unwrap();
312 let inst = builder.ins().call(fr, &[ptr, len]);
313 builder.inst_results(inst)[0]
314 } else {
315 int_zero(builder)
316 }
317 },
318 Constant::Function(_) | Constant::GlobalData(_) | Constant::None => {
319 builder.ins().iconst(types::I64, runtime::TAG_UNIT as i64)
320 },
321 },
322 }
323}
324
325#[derive(Clone, Copy)]
327pub(crate) struct OperandTypes {
328 pub both_num: bool,
329 pub l_bool: bool,
330 pub r_bool: bool,
331}
332
333pub(crate) fn translate_binop(
334 op: &BinOp,
335 builder: &mut FunctionBuilder,
336 lv: Value,
337 rv: Value,
338 tys: OperandTypes,
339 runtime_refs: &HashMap<String, FuncRef>,
340) -> Value {
341 let OperandTypes { both_num, l_bool, r_bool } = tys;
342 if both_num {
345 match op {
346 BinOp::Add => return raw_f64_binop(builder, lv, rv, |b, a, v| b.ins().fadd(a, v)),
347 BinOp::Sub => return raw_f64_binop(builder, lv, rv, |b, a, v| b.ins().fsub(a, v)),
348 BinOp::Mul => return raw_f64_binop(builder, lv, rv, |b, a, v| b.ins().fmul(a, v)),
349 BinOp::Div => return raw_f64_binop(builder, lv, rv, |b, a, v| b.ins().fdiv(a, v)),
350 BinOp::Rem => {
351 return raw_f64_binop(builder, lv, rv, |b, a, v| {
352 let div = b.ins().fdiv(a, v);
353 let trunc = b.ins().trunc(div);
354 let prod = b.ins().fmul(trunc, v);
355 b.ins().fsub(a, prod)
356 })
357 },
358 BinOp::Eq => return raw_f64_cmp(builder, lv, rv, FloatCC::Equal),
359 BinOp::Ne => return raw_f64_cmp(builder, lv, rv, FloatCC::NotEqual),
360 BinOp::Lt => return raw_f64_cmp(builder, lv, rv, FloatCC::LessThan),
361 BinOp::Le => return raw_f64_cmp(builder, lv, rv, FloatCC::LessThanOrEqual),
362 BinOp::Gt => return raw_f64_cmp(builder, lv, rv, FloatCC::GreaterThan),
363 BinOp::Ge => return raw_f64_cmp(builder, lv, rv, FloatCC::GreaterThanOrEqual),
364 _ => {},
365 }
366 }
367 match op {
368 BinOp::Add => emit_f64_or_runtime(
369 builder,
370 lv,
371 rv,
372 "__ling_add",
373 |b, a, v| b.ins().fadd(a, v),
374 runtime_refs,
375 ),
376 BinOp::Sub => emit_f64_or_runtime(
377 builder,
378 lv,
379 rv,
380 "__ling_sub",
381 |b, a, v| b.ins().fsub(a, v),
382 runtime_refs,
383 ),
384 BinOp::Mul => emit_f64_or_runtime(
385 builder,
386 lv,
387 rv,
388 "__ling_mul",
389 |b, a, v| b.ins().fmul(a, v),
390 runtime_refs,
391 ),
392 BinOp::Div => emit_f64_or_runtime(
393 builder,
394 lv,
395 rv,
396 "__ling_div",
397 |b, a, v| b.ins().fdiv(a, v),
398 runtime_refs,
399 ),
400 BinOp::Rem => emit_f64_or_runtime(
401 builder,
402 lv,
403 rv,
404 "__ling_rem",
405 |b, a, v| {
406 let div = b.ins().fdiv(a, v);
407 let trunc = b.ins().trunc(div);
408 let prod = b.ins().fmul(trunc, v);
409 b.ins().fsub(a, prod)
410 },
411 runtime_refs,
412 ),
413 BinOp::Eq => {
414 emit_f64_cmp_or_runtime(builder, lv, rv, "__ling_eq", FloatCC::Equal, runtime_refs)
415 },
416 BinOp::Ne => emit_f64_cmp_or_runtime(
417 builder,
418 lv,
419 rv,
420 "__ling_ne",
421 FloatCC::NotEqual,
422 runtime_refs,
423 ),
424 BinOp::Lt => emit_f64_cmp_or_runtime(
425 builder,
426 lv,
427 rv,
428 "__ling_lt",
429 FloatCC::LessThan,
430 runtime_refs,
431 ),
432 BinOp::Le => emit_f64_cmp_or_runtime(
433 builder,
434 lv,
435 rv,
436 "__ling_le",
437 FloatCC::LessThanOrEqual,
438 runtime_refs,
439 ),
440 BinOp::Gt => emit_f64_cmp_or_runtime(
441 builder,
442 lv,
443 rv,
444 "__ling_gt",
445 FloatCC::GreaterThan,
446 runtime_refs,
447 ),
448 BinOp::Ge => emit_f64_cmp_or_runtime(
449 builder,
450 lv,
451 rv,
452 "__ling_ge",
453 FloatCC::GreaterThanOrEqual,
454 runtime_refs,
455 ),
456 BinOp::And => emit_short_circuit_and(builder, lv, rv, l_bool, r_bool, runtime_refs),
457 BinOp::Or => emit_short_circuit_or(builder, lv, rv, l_bool, r_bool, runtime_refs),
458 _ => emit_runtime_call2(builder, "__ling_add", lv, rv, runtime_refs),
459 }
460}
461
462pub(crate) fn raw_f64_binop(
464 builder: &mut FunctionBuilder,
465 a: Value,
466 b: Value,
467 f64_op: impl FnOnce(&mut FunctionBuilder, Value, Value) -> Value,
468) -> Value {
469 let fa = i64_as_f64(builder, a);
470 let fb = i64_as_f64(builder, b);
471 let r = f64_op(builder, fa, fb);
472 f64_as_i64(builder, r)
473}
474
475pub(crate) fn raw_f64_cmp(builder: &mut FunctionBuilder, a: Value, b: Value, cc: FloatCC) -> Value {
477 let fa = i64_as_f64(builder, a);
478 let fb = i64_as_f64(builder, b);
479 let cmp = builder.ins().fcmp(cc, fa, fb);
480 let t = builder.ins().iconst(types::I64, runtime::TAG_TRUE as i64);
481 let f = builder.ins().iconst(types::I64, runtime::TAG_FALSE as i64);
482 builder.ins().select(cmp, t, f)
483}
484
485pub(crate) fn translate_unop(
486 op: &UnOp,
487 builder: &mut FunctionBuilder,
488 v: Value,
489 runtime_refs: &HashMap<String, FuncRef>,
490) -> Value {
491 match op {
492 UnOp::Ref | UnOp::Deref => v,
493 UnOp::Neg => emit_f64_or_runtime(
494 builder,
495 v,
496 v,
497 "__ling_neg",
498 |b, a, _| b.ins().fneg(a),
499 runtime_refs,
500 ),
501 UnOp::Not => {
502 let is_num = emit_is_number(builder, v);
503 let block_num = builder.create_block();
504 let block_tag = builder.create_block();
505 let block_merge = builder.create_block();
506 let res_var = builder.declare_var(types::I64);
507
508 builder.ins().brif(is_num, block_num, &[], block_tag, &[]);
509
510 builder.switch_to_block(block_num);
511 let f = i64_as_f64(builder, v);
512 let zero_f = builder.ins().f64const(0.0);
513 let eq_zero = builder.ins().fcmp(FloatCC::Equal, f, zero_f);
514 let one = int_one(builder);
515 let zero = int_zero(builder);
516 let sel = builder.ins().select(eq_zero, one, zero);
517 builder.def_var(res_var, sel);
518 builder.ins().jump(block_merge, &[]);
519 builder.seal_block(block_num);
520
521 builder.switch_to_block(block_tag);
522 let rt_ret = emit_runtime_call1(builder, "__ling_not", v, runtime_refs);
523 builder.def_var(res_var, rt_ret);
524 builder.ins().jump(block_merge, &[]);
525 builder.seal_block(block_tag);
526
527 builder.switch_to_block(block_merge);
528 builder.seal_block(block_merge);
529 builder.use_var(res_var)
530 },
531 }
532}
533
534pub(crate) fn i64_as_f64(builder: &mut FunctionBuilder, v: Value) -> Value {
535 builder.ins().bitcast(types::F64, MemFlags::new(), v)
536}
537
538pub(crate) fn f64_as_i64(builder: &mut FunctionBuilder, v: Value) -> Value {
539 builder.ins().bitcast(types::I64, MemFlags::new(), v)
540}
541
542pub(crate) fn emit_f64_or_runtime(
543 builder: &mut FunctionBuilder,
544 a: Value,
545 b: Value,
546 runtime_fn: &str,
547 f64_op: impl FnOnce(&mut FunctionBuilder, Value, Value) -> Value,
548 runtime_refs: &HashMap<String, FuncRef>,
549) -> Value {
550 let is_a_num = emit_is_number(builder, a);
551 let is_b_num = emit_is_number(builder, b);
552 let both_num = builder.ins().band(is_a_num, is_b_num);
553 let block_fast = builder.create_block();
554 let block_rt = builder.create_block();
555 let block_merge = builder.create_block();
556 let res_var = builder.declare_var(types::I64);
557
558 builder.ins().brif(both_num, block_fast, &[], block_rt, &[]);
559
560 builder.switch_to_block(block_fast);
561 let fa = i64_as_f64(builder, a);
562 let fb = i64_as_f64(builder, b);
563 let fres = f64_op(builder, fa, fb);
564 let if64 = f64_as_i64(builder, fres);
565 builder.def_var(res_var, if64);
566 builder.ins().jump(block_merge, &[]);
567 builder.seal_block(block_fast);
568
569 builder.switch_to_block(block_rt);
570 let rt_ret = emit_runtime_call2(builder, runtime_fn, a, b, runtime_refs);
571 builder.def_var(res_var, rt_ret);
572 builder.ins().jump(block_merge, &[]);
573 builder.seal_block(block_rt);
574
575 builder.switch_to_block(block_merge);
576 builder.seal_block(block_merge);
577 builder.use_var(res_var)
578}
579
580pub(crate) fn emit_f64_cmp_or_runtime(
581 builder: &mut FunctionBuilder,
582 a: Value,
583 b: Value,
584 runtime_fn: &str,
585 cc: FloatCC,
586 runtime_refs: &HashMap<String, FuncRef>,
587) -> Value {
588 let is_a_num = emit_is_number(builder, a);
589 let is_b_num = emit_is_number(builder, b);
590 let both_num = builder.ins().band(is_a_num, is_b_num);
591 let block_fast = builder.create_block();
592 let block_rt = builder.create_block();
593 let block_merge = builder.create_block();
594 let res_var = builder.declare_var(types::I64);
595
596 builder.ins().brif(both_num, block_fast, &[], block_rt, &[]);
597
598 builder.switch_to_block(block_fast);
599 let fa = i64_as_f64(builder, a);
600 let fb = i64_as_f64(builder, b);
601 let cmp = builder.ins().fcmp(cc, fa, fb);
602 let t = builder.ins().iconst(types::I64, runtime::TAG_TRUE as i64);
603 let f = builder.ins().iconst(types::I64, runtime::TAG_FALSE as i64);
604 let sel = builder.ins().select(cmp, t, f);
605 builder.def_var(res_var, sel);
606 builder.ins().jump(block_merge, &[]);
607 builder.seal_block(block_fast);
608
609 builder.switch_to_block(block_rt);
610 let rt_ret = emit_runtime_call2(builder, runtime_fn, a, b, runtime_refs);
611 builder.def_var(res_var, rt_ret);
612 builder.ins().jump(block_merge, &[]);
613 builder.seal_block(block_rt);
614
615 builder.switch_to_block(block_merge);
616 builder.seal_block(block_merge);
617 builder.use_var(res_var)
618}
619
620pub(crate) fn truthy_of(
623 builder: &mut FunctionBuilder,
624 val: Value,
625 is_bool: bool,
626 runtime_refs: &HashMap<String, FuncRef>,
627) -> Value {
628 if is_bool {
629 builder
630 .ins()
631 .icmp_imm(IntCC::Equal, val, runtime::TAG_TRUE as i64)
632 } else {
633 emit_is_truthy(builder, val, runtime_refs)
634 }
635}
636
637pub(crate) fn emit_short_circuit_and(
638 builder: &mut FunctionBuilder,
639 lv: Value,
640 rv: Value,
641 l_bool: bool,
642 r_bool: bool,
643 runtime_refs: &HashMap<String, FuncRef>,
644) -> Value {
645 let l_is_truthy = truthy_of(builder, lv, l_bool, runtime_refs);
646 let block_false = builder.create_block();
647 let block_true = builder.create_block();
648 let block_merge = builder.create_block();
649 let res_var = builder.declare_var(types::I64);
650
651 builder
652 .ins()
653 .brif(l_is_truthy, block_true, &[], block_false, &[]);
654
655 builder.switch_to_block(block_false);
656 let f = builder.ins().iconst(types::I64, runtime::TAG_FALSE as i64);
657 builder.def_var(res_var, f);
658 builder.ins().jump(block_merge, &[]);
659 builder.seal_block(block_false);
660
661 builder.switch_to_block(block_true);
662 let r_is_truthy = truthy_of(builder, rv, r_bool, runtime_refs);
663 let t = builder.ins().iconst(types::I64, runtime::TAG_TRUE as i64);
664 let f2 = builder.ins().iconst(types::I64, runtime::TAG_FALSE as i64);
665 let sel = builder.ins().select(r_is_truthy, t, f2);
666 builder.def_var(res_var, sel);
667 builder.ins().jump(block_merge, &[]);
668 builder.seal_block(block_true);
669
670 builder.switch_to_block(block_merge);
671 builder.seal_block(block_merge);
672 builder.use_var(res_var)
673}
674
675pub(crate) fn emit_short_circuit_or(
676 builder: &mut FunctionBuilder,
677 lv: Value,
678 rv: Value,
679 l_bool: bool,
680 r_bool: bool,
681 runtime_refs: &HashMap<String, FuncRef>,
682) -> Value {
683 let l_is_truthy = truthy_of(builder, lv, l_bool, runtime_refs);
684 let block_true = builder.create_block();
685 let block_false = builder.create_block();
686 let block_merge = builder.create_block();
687 let res_var = builder.declare_var(types::I64);
688
689 builder
690 .ins()
691 .brif(l_is_truthy, block_true, &[], block_false, &[]);
692
693 builder.switch_to_block(block_true);
694 let t = builder.ins().iconst(types::I64, runtime::TAG_TRUE as i64);
695 builder.def_var(res_var, t);
696 builder.ins().jump(block_merge, &[]);
697 builder.seal_block(block_true);
698
699 builder.switch_to_block(block_false);
700 let r_is_truthy = truthy_of(builder, rv, r_bool, runtime_refs);
701 let t2 = builder.ins().iconst(types::I64, runtime::TAG_TRUE as i64);
702 let f = builder.ins().iconst(types::I64, runtime::TAG_FALSE as i64);
703 let sel = builder.ins().select(r_is_truthy, t2, f);
704 builder.def_var(res_var, sel);
705 builder.ins().jump(block_merge, &[]);
706 builder.seal_block(block_false);
707
708 builder.switch_to_block(block_merge);
709 builder.seal_block(block_merge);
710 builder.use_var(res_var)
711}
712
713pub(crate) fn emit_is_number(builder: &mut FunctionBuilder, val: Value) -> Value {
714 let shifted = builder.ins().ushr_imm(val, 56);
715 let tag = builder.ins().iconst(types::I64, 0x7F);
716 builder.ins().icmp(IntCC::NotEqual, shifted, tag)
717}
718
719pub(crate) fn emit_is_truthy(
720 builder: &mut FunctionBuilder,
721 val: Value,
722 _runtime_refs: &HashMap<String, FuncRef>,
723) -> Value {
724 let is_num = emit_is_number(builder, val);
725 let block_num = builder.create_block();
726 let block_tag = builder.create_block();
727 let block_merge = builder.create_block();
728 let res_var = builder.declare_var(types::I64);
729
730 builder.ins().brif(is_num, block_num, &[], block_tag, &[]);
731
732 builder.switch_to_block(block_num);
733 let f = i64_as_f64(builder, val);
734 let zero = builder.ins().f64const(0.0);
735 let is_nonzero = builder.ins().fcmp(FloatCC::NotEqual, f, zero);
736 let one = int_one(builder);
737 let zero2 = int_zero(builder);
738 let sel = builder.ins().select(is_nonzero, one, zero2);
739 builder.def_var(res_var, sel);
740 builder.ins().jump(block_merge, &[]);
741 builder.seal_block(block_num);
742
743 builder.switch_to_block(block_tag);
744 let is_true = builder
745 .ins()
746 .icmp_imm(IntCC::Equal, val, runtime::TAG_TRUE as i64);
747 let is_false = builder
748 .ins()
749 .icmp_imm(IntCC::Equal, val, runtime::TAG_FALSE as i64);
750 let is_unit = builder
751 .ins()
752 .icmp_imm(IntCC::Equal, val, runtime::TAG_UNIT as i64);
753 let is_false_or_unit = builder.ins().bor(is_false, is_unit);
755 let one_i64 = int_one(builder);
756 let zero_i64 = int_zero(builder);
757 let is_non_nil = builder.ins().select(is_false_or_unit, zero_i64, one_i64);
758 let is_true_i64 = builder.ins().select(is_true, one_i64, zero_i64);
759 let result_i64 = builder.ins().bor(is_true_i64, is_non_nil);
760 builder.def_var(res_var, result_i64);
761 builder.ins().jump(block_merge, &[]);
762 builder.seal_block(block_tag);
763
764 builder.switch_to_block(block_merge);
765 builder.seal_block(block_merge);
766 builder.use_var(res_var)
767}
768
769pub(crate) fn emit_runtime_call0(
770 builder: &mut FunctionBuilder,
771 name: &str,
772 runtime_refs: &HashMap<String, FuncRef>,
773) -> Value {
774 let fr = *runtime_refs
775 .get(name)
776 .unwrap_or_else(|| panic!("runtime fn not found: {}", name));
777 let inst = builder.ins().call(fr, &[]);
778 builder.inst_results(inst)[0]
779}
780
781pub(crate) fn emit_runtime_call1(
782 builder: &mut FunctionBuilder,
783 name: &str,
784 a: Value,
785 runtime_refs: &HashMap<String, FuncRef>,
786) -> Value {
787 let fr = *runtime_refs
788 .get(name)
789 .unwrap_or_else(|| panic!("runtime fn not found: {}", name));
790 let inst = builder.ins().call(fr, &[a]);
791 builder.inst_results(inst)[0]
792}
793
794pub(crate) fn emit_runtime_call2(
795 builder: &mut FunctionBuilder,
796 name: &str,
797 a: Value,
798 b: Value,
799 runtime_refs: &HashMap<String, FuncRef>,
800) -> Value {
801 let fr = *runtime_refs
802 .get(name)
803 .unwrap_or_else(|| panic!("runtime fn not found: {}", name));
804 let inst = builder.ins().call(fr, &[a, b]);
805 builder.inst_results(inst)[0]
806}
807
808pub(crate) fn emit_runtime_call4(
809 builder: &mut FunctionBuilder,
810 name: &str,
811 a: Value,
812 b: Value,
813 c: Value,
814 d: Value,
815 runtime_refs: &HashMap<String, FuncRef>,
816) -> Value {
817 let fr = *runtime_refs
818 .get(name)
819 .unwrap_or_else(|| panic!("runtime fn not found: {}", name));
820 let inst = builder.ins().call(fr, &[a, b, c, d]);
821 builder.inst_results(inst)[0]
822}
823
824pub(crate) fn emit_builtin_call(
825 name: String,
826 args: Vec<Value>,
827 builder: &mut FunctionBuilder,
828 builtin_gvs: &HashMap<String, GlobalValue>,
829 runtime_refs: &HashMap<String, FuncRef>,
830) -> Value {
831 match name.as_str() {
833 "print" | "println" | "พิมพ์" | "印" | "打印" | "印刷" => {
834 if !args.is_empty() {
835 for arg in &args[..args.len() - 1] {
836 emit_runtime_call1(builder, "__ling_print_val", *arg, runtime_refs);
837 }
838 emit_runtime_call1(
839 builder,
840 "__ling_print_val",
841 args[args.len() - 1],
842 runtime_refs,
843 );
844 }
845 return emit_runtime_call0(builder, "__ling_print_newline", runtime_refs);
846 },
847 "sin" => return unbox_f64_or_call(builder, args, "__ling_sin", runtime_refs),
848 "cos" => return unbox_f64_or_call(builder, args, "__ling_cos", runtime_refs),
849 "sqrt" => return unbox_f64_or_call(builder, args, "__ling_sqrt", runtime_refs),
850 "abs" => return unbox_f64_or_call(builder, args, "__ling_abs", runtime_refs),
851 "floor" => return unbox_f64_or_call(builder, args, "__ling_floor", runtime_refs),
852 "ceil" => return unbox_f64_or_call(builder, args, "__ling_ceil", runtime_refs),
853 "round" => return unbox_f64_or_call(builder, args, "__ling_round", runtime_refs),
854 "time_now" | "เวลาปัจจุบัน" | "当前时间" | "経過時間" | "현재시간" =>
855 {
856 return emit_runtime_call0(builder, "__ling_time_now", runtime_refs);
857 },
858 "len" | "str_len" | "ความยาว" | "长度" | "長さ" | "길이" => {
859 if !args.is_empty() {
860 return emit_runtime_call1(builder, "__ling_str_len", args[0], runtime_refs);
861 } else {
862 return builder.ins().iconst(types::I64, runtime::TAG_UNIT as i64);
863 }
864 },
865 _ => {},
866 }
867 if let Some(&name_gv) = builtin_gvs.get(&name) {
869 let name_ptr = builder.ins().symbol_value(types::I64, name_gv);
870 let name_len = builder.ins().iconst(types::I64, name.len() as i64);
871 let num_args = args.len();
872 let slot_size = std::cmp::max(num_args * 8, 8) as u32;
874 let args_slot = builder.create_sized_stack_slot(StackSlotData::new(
875 StackSlotKind::ExplicitSlot,
876 slot_size,
877 8,
878 ));
879 let args_ptr = builder.ins().stack_addr(types::I64, args_slot, 0);
880 for (i, arg) in args.iter().enumerate() {
881 let off = builder.ins().iconst(types::I64, (i * 8) as i64);
882 let elem_ptr = builder.ins().iadd(args_ptr, off);
883 builder.ins().store(MemFlags::new(), *arg, elem_ptr, 0);
884 }
885 let args_len = builder.ins().iconst(types::I64, num_args as i64);
886 emit_runtime_call4(
887 builder,
888 "__ling_builtin",
889 name_ptr,
890 name_len,
891 args_ptr,
892 args_len,
893 runtime_refs,
894 )
895 } else {
896 builder.ins().iconst(types::I64, runtime::TAG_UNIT as i64)
897 }
898}
899
900pub(crate) fn unbox_f64_or_call(
901 builder: &mut FunctionBuilder,
902 args: Vec<Value>,
903 runtime_fn: &str,
904 runtime_refs: &HashMap<String, FuncRef>,
905) -> Value {
906 if args.is_empty() {
907 return builder.ins().iconst(types::I64, runtime::TAG_UNIT as i64);
908 }
909 let val = args[0];
910 let is_num = emit_is_number(builder, val);
911 let block_fast = builder.create_block();
912 let block_slow = builder.create_block();
913 let block_merge = builder.create_block();
914 let res_var = builder.declare_var(types::I64);
915
916 builder.ins().brif(is_num, block_fast, &[], block_slow, &[]);
917
918 builder.switch_to_block(block_fast);
919 let f = i64_as_f64(builder, val);
920 let fr = *runtime_refs
921 .get(runtime_fn)
922 .unwrap_or_else(|| panic!("runtime fn not found: {}", runtime_fn));
923 let inst = builder.ins().call(fr, &[f]);
924 let f_result = builder.inst_results(inst)[0];
925 let if64 = f64_as_i64(builder, f_result);
926 builder.def_var(res_var, if64);
927 builder.ins().jump(block_merge, &[]);
928 builder.seal_block(block_fast);
929
930 builder.switch_to_block(block_slow);
931 builder.def_var(res_var, val);
932 builder.ins().jump(block_merge, &[]);
933 builder.seal_block(block_slow);
934
935 builder.switch_to_block(block_merge);
936 builder.seal_block(block_merge);
937 builder.use_var(res_var)
938}
939
940pub(crate) fn translate_terminator(
941 term: &Terminator,
942 builder: &mut FunctionBuilder,
943 blocks: &[Block],
944 ctx: &TransCtx,
945) {
946 match &term.kind {
947 TerminatorKind::Goto { target } => {
948 builder.ins().jump(blocks[target.0], &[]);
949 },
950 TerminatorKind::SwitchInt { discr, targets, otherwise } => {
951 let val = translate_op(discr, builder, ctx);
952 let is_truthy = if ctx.nt.operand_is_bool(ctx.fname, discr) {
955 builder
956 .ins()
957 .icmp_imm(IntCC::Equal, val, runtime::TAG_TRUE as i64)
958 } else {
959 emit_is_truthy(builder, val, ctx.runtime_refs)
960 };
961 let mut true_target = otherwise.0;
962 let mut false_target = otherwise.0;
963 for (const_val, target_block) in targets {
964 if *const_val == 1 {
965 true_target = target_block.0;
966 } else if *const_val == 0 {
967 false_target = target_block.0;
968 }
969 }
970 if true_target != otherwise.0 && false_target != otherwise.0 {
971 builder.ins().brif(
972 is_truthy,
973 blocks[true_target],
974 &[],
975 blocks[false_target],
976 &[],
977 );
978 } else if true_target != otherwise.0 {
979 builder.ins().brif(
980 is_truthy,
981 blocks[true_target],
982 &[],
983 blocks[otherwise.0],
984 &[],
985 );
986 } else {
987 builder.ins().jump(blocks[otherwise.0], &[]);
988 }
989 },
990 TerminatorKind::Return => {
991 let ret = builder.use_var(ctx.vars[&Local(0)]);
992 builder.ins().return_(&[ret]);
993 },
994 TerminatorKind::Unreachable => {
995 builder.ins().trap(TrapCode::INTEGER_OVERFLOW);
996 },
997 }
998}