1use crate::bitset::BitSet;
17use crate::cursor::{Cursor, FuncCursor};
18use crate::flowgraph::ControlFlowGraph;
19use crate::ir::types::{I32, I64};
20use crate::ir::{self, InstBuilder, MemFlags};
21use crate::isa::TargetIsa;
22use crate::predicates;
23use crate::timing;
24use alloc::collections::BTreeSet;
25use alloc::vec::Vec;
26
27mod boundary;
28mod call;
29mod globalvalue;
30mod heap;
31mod libcall;
32mod split;
33mod table;
34
35use self::call::expand_call;
36use self::globalvalue::expand_global_value;
37use self::heap::expand_heap_addr;
38use self::libcall::expand_as_libcall;
39use self::table::expand_table_addr;
40
41enum LegalizeInstResult {
42 Done,
43 Legalized,
44 SplitLegalizePending,
45}
46
47fn legalize_inst(
49 inst: ir::Inst,
50 pos: &mut FuncCursor,
51 cfg: &mut ControlFlowGraph,
52 isa: &dyn TargetIsa,
53) -> LegalizeInstResult {
54 let opcode = pos.func.dfg[inst].opcode();
55
56 if opcode.is_call() {
58 if boundary::handle_call_abi(isa, inst, pos.func, cfg) {
59 return LegalizeInstResult::Legalized;
60 }
61 } else if opcode.is_return() {
62 if boundary::handle_return_abi(inst, pos.func, cfg) {
63 return LegalizeInstResult::Legalized;
64 }
65 } else if opcode.is_branch() {
66 split::simplify_branch_arguments(&mut pos.func.dfg, inst);
67 } else if opcode == ir::Opcode::Isplit {
68 pos.use_srcloc(inst);
69
70 let arg = match pos.func.dfg[inst] {
71 ir::InstructionData::Unary { arg, .. } => pos.func.dfg.resolve_aliases(arg),
72 _ => panic!("Expected isplit: {}", pos.func.dfg.display_inst(inst, None)),
73 };
74
75 match pos.func.dfg.value_def(arg) {
76 ir::ValueDef::Result(inst, _num) => {
77 if let ir::InstructionData::Binary {
78 opcode: ir::Opcode::Iconcat,
79 ..
80 } = pos.func.dfg[inst]
81 {
82 } else {
84 return LegalizeInstResult::SplitLegalizePending;
88 }
89 }
90 ir::ValueDef::Param(_ebb, _num) => {}
91 }
92
93 let res = pos.func.dfg.inst_results(inst).to_vec();
94 assert_eq!(res.len(), 2);
95 let (resl, resh) = (res[0], res[1]); pos.func.dfg.clear_results(inst);
99 pos.remove_inst();
100
101 let curpos = pos.position();
102 let srcloc = pos.srcloc();
103 let (xl, xh) = split::isplit(pos.func, cfg, curpos, srcloc, arg);
104
105 pos.func.dfg.change_to_alias(resl, xl);
106 pos.func.dfg.change_to_alias(resh, xh);
107
108 return LegalizeInstResult::Legalized;
109 }
110
111 match pos.func.update_encoding(inst, isa) {
112 Ok(()) => LegalizeInstResult::Done,
113 Err(action) => {
114 if action(inst, pos.func, cfg, isa) {
121 return LegalizeInstResult::Legalized;
122 }
123
124 if expand_as_libcall(inst, pos.func, isa) {
127 LegalizeInstResult::Legalized
128 } else {
129 LegalizeInstResult::Done
130 }
131 }
132 }
133}
134
135pub fn legalize_function(func: &mut ir::Function, cfg: &mut ControlFlowGraph, isa: &dyn TargetIsa) {
141 let _tt = timing::legalize();
142 debug_assert!(cfg.is_valid());
143
144 boundary::legalize_signatures(func, isa);
145
146 func.encodings.resize(func.dfg.num_insts());
147
148 let mut pos = FuncCursor::new(func);
149 let func_begin = pos.position();
150
151 while let Some(ebb) = pos.next_ebb() {
154 split::split_ebb_params(pos.func, cfg, ebb);
155 }
156
157 pos.set_position(func_begin);
158
159 let mut pending_splits = BTreeSet::new();
161
162 while let Some(_ebb) = pos.next_ebb() {
165 let mut prev_pos = pos.position();
168
169 while let Some(inst) = pos.next_inst() {
170 match legalize_inst(inst, &mut pos, cfg, isa) {
171 LegalizeInstResult::Done => prev_pos = pos.position(),
173
174 LegalizeInstResult::Legalized => pos.set_position(prev_pos),
176
177 LegalizeInstResult::SplitLegalizePending => {
181 pending_splits.insert(inst);
182 }
183 }
184 }
185 }
186
187 for inst in pending_splits {
189 pos.goto_inst(inst);
190 legalize_inst(inst, &mut pos, cfg, isa);
191 }
192
193 if !isa.flags().jump_tables_enabled() {
195 pos.func.jump_tables.clear();
196 }
197}
198
199include!(concat!(env!("OUT_DIR"), "/legalizer.rs"));
204
205fn expand_cond_trap(
208 inst: ir::Inst,
209 func: &mut ir::Function,
210 cfg: &mut ControlFlowGraph,
211 _isa: &dyn TargetIsa,
212) {
213 let trapz;
215 let (arg, code) = match func.dfg[inst] {
216 ir::InstructionData::CondTrap { opcode, arg, code } => {
217 trapz = match opcode {
219 ir::Opcode::Trapz => true,
220 ir::Opcode::Trapnz => false,
221 _ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)),
222 };
223 (arg, code)
224 }
225 _ => panic!("Expected cond trap: {}", func.dfg.display_inst(inst, None)),
226 };
227
228 let old_ebb = func.layout.pp_ebb(inst);
244 let new_ebb_trap = func.dfg.make_ebb();
245 let new_ebb_resume = func.dfg.make_ebb();
246
247 if trapz {
249 func.dfg.replace(inst).brnz(arg, new_ebb_resume, &[]);
250 } else {
251 func.dfg.replace(inst).brz(arg, new_ebb_resume, &[]);
252 }
253
254 let mut pos = FuncCursor::new(func).after_inst(inst);
256 pos.use_srcloc(inst);
257 pos.ins().jump(new_ebb_trap, &[]);
258
259 pos.insert_ebb(new_ebb_trap);
261 pos.ins().trap(code);
262
263 pos.insert_ebb(new_ebb_resume);
265
266 cfg.recompute_ebb(pos.func, old_ebb);
268 cfg.recompute_ebb(pos.func, new_ebb_resume);
269 cfg.recompute_ebb(pos.func, new_ebb_trap);
270}
271
272fn expand_br_table(
274 inst: ir::Inst,
275 func: &mut ir::Function,
276 cfg: &mut ControlFlowGraph,
277 isa: &dyn TargetIsa,
278) {
279 if isa.flags().jump_tables_enabled() {
280 expand_br_table_jt(inst, func, cfg, isa);
281 } else {
282 expand_br_table_conds(inst, func, cfg, isa);
283 }
284}
285
286fn expand_br_table_jt(
288 inst: ir::Inst,
289 func: &mut ir::Function,
290 cfg: &mut ControlFlowGraph,
291 isa: &dyn TargetIsa,
292) {
293 use crate::ir::condcodes::IntCC;
294
295 let (arg, default_ebb, table) = match func.dfg[inst] {
296 ir::InstructionData::BranchTable {
297 opcode: ir::Opcode::BrTable,
298 arg,
299 destination,
300 table,
301 } => (arg, destination, table),
302 _ => panic!("Expected br_table: {}", func.dfg.display_inst(inst, None)),
303 };
304
305 let ebb = func.layout.pp_ebb(inst);
322 let jump_table_ebb = func.dfg.make_ebb();
323
324 let mut pos = FuncCursor::new(func).at_inst(inst);
325 pos.use_srcloc(inst);
326
327 let table_size = pos.func.jump_tables[table].len() as i64;
329 let oob = pos
330 .ins()
331 .icmp_imm(IntCC::UnsignedGreaterThanOrEqual, arg, table_size);
332
333 pos.ins().brnz(oob, default_ebb, &[]);
334 pos.ins().jump(jump_table_ebb, &[]);
335 pos.insert_ebb(jump_table_ebb);
336
337 let addr_ty = isa.pointer_type();
338
339 let arg = if pos.func.dfg.value_type(arg) == addr_ty {
340 arg
341 } else {
342 pos.ins().uextend(addr_ty, arg)
343 };
344
345 let base_addr = pos.ins().jump_table_base(addr_ty, table);
346 let entry = pos
347 .ins()
348 .jump_table_entry(arg, base_addr, I32.bytes() as u8, table);
349
350 let addr = pos.ins().iadd(base_addr, entry);
351 pos.ins().indirect_jump_table_br(addr, table);
352
353 pos.remove_inst();
354 cfg.recompute_ebb(pos.func, ebb);
355 cfg.recompute_ebb(pos.func, jump_table_ebb);
356}
357
358fn expand_br_table_conds(
360 inst: ir::Inst,
361 func: &mut ir::Function,
362 cfg: &mut ControlFlowGraph,
363 _isa: &dyn TargetIsa,
364) {
365 use crate::ir::condcodes::IntCC;
366
367 let (arg, default_ebb, table) = match func.dfg[inst] {
368 ir::InstructionData::BranchTable {
369 opcode: ir::Opcode::BrTable,
370 arg,
371 destination,
372 table,
373 } => (arg, destination, table),
374 _ => panic!("Expected br_table: {}", func.dfg.display_inst(inst, None)),
375 };
376
377 let ebb = func.layout.pp_ebb(inst);
378
379 let table_size = func.jump_tables[table].len();
381 let mut cond_failed_ebb = vec![];
382 if table_size >= 1 {
383 cond_failed_ebb = alloc::vec::Vec::with_capacity(table_size - 1);
384 for _ in 0..table_size - 1 {
385 cond_failed_ebb.push(func.dfg.make_ebb());
386 }
387 }
388
389 let mut pos = FuncCursor::new(func).at_inst(inst);
390 pos.use_srcloc(inst);
391
392 #[allow(clippy::needless_range_loop)]
394 for i in 0..table_size {
395 let dest = pos.func.jump_tables[table].as_slice()[i];
396 let t = pos.ins().icmp_imm(IntCC::Equal, arg, i as i64);
397 pos.ins().brnz(t, dest, &[]);
398 if i < table_size - 1 {
400 let ebb = cond_failed_ebb[i];
401 pos.ins().jump(ebb, &[]);
402 pos.insert_ebb(ebb);
403 }
404 }
405
406 pos.ins().jump(default_ebb, &[]);
408
409 pos.remove_inst();
410 cfg.recompute_ebb(pos.func, ebb);
411 for failed_ebb in cond_failed_ebb.into_iter() {
412 cfg.recompute_ebb(pos.func, failed_ebb);
413 }
414}
415
416fn expand_select(
421 inst: ir::Inst,
422 func: &mut ir::Function,
423 cfg: &mut ControlFlowGraph,
424 _isa: &dyn TargetIsa,
425) {
426 let (ctrl, tval, fval) = match func.dfg[inst] {
427 ir::InstructionData::Ternary {
428 opcode: ir::Opcode::Select,
429 args,
430 } => (args[0], args[1], args[2]),
431 _ => panic!("Expected select: {}", func.dfg.display_inst(inst, None)),
432 };
433
434 let old_ebb = func.layout.pp_ebb(inst);
440 let result = func.dfg.first_result(inst);
441 func.dfg.clear_results(inst);
442 let new_ebb = func.dfg.make_ebb();
443 func.dfg.attach_ebb_param(new_ebb, result);
444
445 func.dfg.replace(inst).brnz(ctrl, new_ebb, &[tval]);
446 let mut pos = FuncCursor::new(func).after_inst(inst);
447 pos.use_srcloc(inst);
448 pos.ins().jump(new_ebb, &[fval]);
449 pos.insert_ebb(new_ebb);
450
451 cfg.recompute_ebb(pos.func, new_ebb);
452 cfg.recompute_ebb(pos.func, old_ebb);
453}
454
455fn expand_br_icmp(
456 inst: ir::Inst,
457 func: &mut ir::Function,
458 cfg: &mut ControlFlowGraph,
459 _isa: &dyn TargetIsa,
460) {
461 let (cond, a, b, destination, ebb_args) = match func.dfg[inst] {
462 ir::InstructionData::BranchIcmp {
463 cond,
464 destination,
465 ref args,
466 ..
467 } => (
468 cond,
469 args.get(0, &func.dfg.value_lists).unwrap(),
470 args.get(1, &func.dfg.value_lists).unwrap(),
471 destination,
472 args.as_slice(&func.dfg.value_lists)[2..].to_vec(),
473 ),
474 _ => panic!("Expected br_icmp {}", func.dfg.display_inst(inst, None)),
475 };
476
477 let old_ebb = func.layout.pp_ebb(inst);
478 func.dfg.clear_results(inst);
479
480 let icmp_res = func.dfg.replace(inst).icmp(cond, a, b);
481 let mut pos = FuncCursor::new(func).after_inst(inst);
482 pos.use_srcloc(inst);
483 pos.ins().brnz(icmp_res, destination, &ebb_args);
484
485 cfg.recompute_ebb(pos.func, destination);
486 cfg.recompute_ebb(pos.func, old_ebb);
487}
488
489fn expand_fconst(
491 inst: ir::Inst,
492 func: &mut ir::Function,
493 _cfg: &mut ControlFlowGraph,
494 _isa: &dyn TargetIsa,
495) {
496 let ty = func.dfg.value_type(func.dfg.first_result(inst));
497 debug_assert!(!ty.is_vector(), "Only scalar fconst supported: {}", ty);
498
499 let mut pos = FuncCursor::new(func).at_inst(inst);
502 pos.use_srcloc(inst);
503 let ival = match pos.func.dfg[inst] {
504 ir::InstructionData::UnaryIeee32 {
505 opcode: ir::Opcode::F32const,
506 imm,
507 } => pos.ins().iconst(ir::types::I32, i64::from(imm.bits())),
508 ir::InstructionData::UnaryIeee64 {
509 opcode: ir::Opcode::F64const,
510 imm,
511 } => pos.ins().iconst(ir::types::I64, imm.bits() as i64),
512 _ => panic!("Expected fconst: {}", pos.func.dfg.display_inst(inst, None)),
513 };
514 pos.func.dfg.replace(inst).bitcast(ty, ival);
515}
516
517fn expand_stack_load(
519 inst: ir::Inst,
520 func: &mut ir::Function,
521 _cfg: &mut ControlFlowGraph,
522 isa: &dyn TargetIsa,
523) {
524 let ty = func.dfg.value_type(func.dfg.first_result(inst));
525 let addr_ty = isa.pointer_type();
526
527 let mut pos = FuncCursor::new(func).at_inst(inst);
528 pos.use_srcloc(inst);
529
530 let (stack_slot, offset) = match pos.func.dfg[inst] {
531 ir::InstructionData::StackLoad {
532 opcode: _opcode,
533 stack_slot,
534 offset,
535 } => (stack_slot, offset),
536 _ => panic!(
537 "Expected stack_load: {}",
538 pos.func.dfg.display_inst(inst, None)
539 ),
540 };
541
542 let addr = pos.ins().stack_addr(addr_ty, stack_slot, offset);
543
544 let mflags = MemFlags::trusted();
546 pos.func.dfg.replace(inst).load(ty, mflags, addr, 0);
547}
548
549fn expand_stack_store(
551 inst: ir::Inst,
552 func: &mut ir::Function,
553 _cfg: &mut ControlFlowGraph,
554 isa: &dyn TargetIsa,
555) {
556 let addr_ty = isa.pointer_type();
557
558 let mut pos = FuncCursor::new(func).at_inst(inst);
559 pos.use_srcloc(inst);
560
561 let (val, stack_slot, offset) = match pos.func.dfg[inst] {
562 ir::InstructionData::StackStore {
563 opcode: _opcode,
564 arg,
565 stack_slot,
566 offset,
567 } => (arg, stack_slot, offset),
568 _ => panic!(
569 "Expected stack_store: {}",
570 pos.func.dfg.display_inst(inst, None)
571 ),
572 };
573
574 let addr = pos.ins().stack_addr(addr_ty, stack_slot, offset);
575
576 let mut mflags = MemFlags::new();
577 mflags.set_notrap();
579 mflags.set_aligned();
580 pos.func.dfg.replace(inst).store(mflags, val, addr, 0);
581}
582
583fn narrow_load(
585 inst: ir::Inst,
586 func: &mut ir::Function,
587 _cfg: &mut ControlFlowGraph,
588 _isa: &dyn TargetIsa,
589) {
590 let mut pos = FuncCursor::new(func).at_inst(inst);
591 pos.use_srcloc(inst);
592
593 let (ptr, offset, flags) = match pos.func.dfg[inst] {
594 ir::InstructionData::Load {
595 opcode: ir::Opcode::Load,
596 arg,
597 offset,
598 flags,
599 } => (arg, offset, flags),
600 _ => panic!("Expected load: {}", pos.func.dfg.display_inst(inst, None)),
601 };
602
603 let res_ty = pos.func.dfg.ctrl_typevar(inst);
604 let small_ty = res_ty.half_width().expect("Can't narrow load");
605
606 let al = pos.ins().load(small_ty, flags, ptr, offset);
607 let ah = pos.ins().load(
608 small_ty,
609 flags,
610 ptr,
611 offset.try_add_i64(8).expect("load offset overflow"),
612 );
613 pos.func.dfg.replace(inst).iconcat(al, ah);
614}
615
616fn narrow_store(
618 inst: ir::Inst,
619 func: &mut ir::Function,
620 _cfg: &mut ControlFlowGraph,
621 _isa: &dyn TargetIsa,
622) {
623 let mut pos = FuncCursor::new(func).at_inst(inst);
624 pos.use_srcloc(inst);
625
626 let (val, ptr, offset, flags) = match pos.func.dfg[inst] {
627 ir::InstructionData::Store {
628 opcode: ir::Opcode::Store,
629 args,
630 offset,
631 flags,
632 } => (args[0], args[1], offset, flags),
633 _ => panic!("Expected store: {}", pos.func.dfg.display_inst(inst, None)),
634 };
635
636 let (al, ah) = pos.ins().isplit(val);
637 pos.ins().store(flags, al, ptr, offset);
638 pos.ins().store(
639 flags,
640 ah,
641 ptr,
642 offset.try_add_i64(8).expect("store offset overflow"),
643 );
644 pos.remove_inst();
645}
646
647fn narrow_iconst(
649 inst: ir::Inst,
650 func: &mut ir::Function,
651 _cfg: &mut ControlFlowGraph,
652 isa: &dyn TargetIsa,
653) {
654 let imm: i64 = if let ir::InstructionData::UnaryImm {
655 opcode: ir::Opcode::Iconst,
656 imm,
657 } = &func.dfg[inst]
658 {
659 (*imm).into()
660 } else {
661 panic!("unexpected instruction in narrow_iconst");
662 };
663
664 let mut pos = FuncCursor::new(func).at_inst(inst);
665 pos.use_srcloc(inst);
666
667 let ty = pos.func.dfg.ctrl_typevar(inst);
668 if isa.pointer_bits() == 32 && ty == I64 {
669 let low = pos.ins().iconst(I32, imm & 0xffffffff);
670 let high = pos.ins().iconst(I32, imm >> 32);
671 pos.func.dfg.replace(inst).iconcat(low, high);
673 return;
674 }
675
676 unimplemented!("missing encoding or legalization for iconst.{:?}", ty);
677}
678
679fn narrow_icmp_imm(
680 inst: ir::Inst,
681 func: &mut ir::Function,
682 _cfg: &mut ControlFlowGraph,
683 _isa: &dyn TargetIsa,
684) {
685 use crate::ir::condcodes::{CondCode, IntCC};
686
687 let (arg, cond, imm): (ir::Value, IntCC, i64) = match func.dfg[inst] {
688 ir::InstructionData::IntCompareImm {
689 opcode: ir::Opcode::IcmpImm,
690 arg,
691 cond,
692 imm,
693 } => (arg, cond, imm.into()),
694 _ => panic!("unexpected instruction in narrow_icmp_imm"),
695 };
696
697 let mut pos = FuncCursor::new(func).at_inst(inst);
698 pos.use_srcloc(inst);
699
700 let ty = pos.func.dfg.ctrl_typevar(inst);
701 let ty_half = ty.half_width().unwrap();
702
703 let imm_low = pos
704 .ins()
705 .iconst(ty_half, imm & (1u128 << (ty_half.bits() - 1)) as i64);
706 let imm_high = pos
707 .ins()
708 .iconst(ty_half, imm.wrapping_shr(ty_half.bits().into()));
709 let (arg_low, arg_high) = pos.ins().isplit(arg);
710
711 match cond {
712 IntCC::Equal => {
713 let res_low = pos.ins().icmp(cond, arg_low, imm_low);
714 let res_high = pos.ins().icmp(cond, arg_high, imm_high);
715 pos.func.dfg.replace(inst).band(res_low, res_high);
716 }
717 IntCC::NotEqual => {
718 let res_low = pos.ins().icmp(cond, arg_low, imm_low);
719 let res_high = pos.ins().icmp(cond, arg_high, imm_high);
720 pos.func.dfg.replace(inst).bor(res_low, res_high);
721 }
722 IntCC::SignedGreaterThan
723 | IntCC::SignedGreaterThanOrEqual
724 | IntCC::SignedLessThan
725 | IntCC::SignedLessThanOrEqual
726 | IntCC::UnsignedGreaterThan
727 | IntCC::UnsignedGreaterThanOrEqual
728 | IntCC::UnsignedLessThan
729 | IntCC::UnsignedLessThanOrEqual => {
730 let b1 = pos.ins().icmp(cond.without_equal(), arg_high, imm_high);
731 let b2 = pos
732 .ins()
733 .icmp(cond.inverse().without_equal(), arg_high, imm_high);
734 let b3 = pos.ins().icmp(cond.unsigned(), arg_low, imm_low);
735 let c1 = pos.ins().bnot(b2);
736 let c2 = pos.ins().band(c1, b3);
737 pos.func.dfg.replace(inst).bor(b1, c2);
738 }
739 _ => unimplemented!("missing legalization for condition {:?}", cond),
740 }
741}