1use crate::{ir::prelude::*, opt::prelude::*};
6
7pub struct ProcessLowering;
11
12impl Pass for ProcessLowering {
13 fn run_on_cfg(ctx: &PassContext, unit: &mut UnitBuilder) -> bool {
14 if !unit.is_process() || !is_suitable(ctx, &unit) {
15 return false;
16 }
17 info!("ProcLower [{}]", unit.name());
18 unit.data().kind = UnitKind::Entity;
19 unit.delete_inst(unit.terminator(unit.entry()));
20 unit.insert_at_end();
21 unit.ins().halt();
22 true
23 }
24}
25
26fn is_suitable(_ctx: &PassContext, unit: &Unit) -> bool {
28 if unit.blocks().count() != 1 {
30 trace!("Skipping {} (not just one block)", unit.name());
31 return false;
32 }
33 let bb = unit.entry();
34
35 let term = unit.terminator(bb);
37 match unit[term].opcode() {
38 Opcode::Wait | Opcode::WaitTime | Opcode::Halt => (),
39 op => {
40 trace!("Skipping {} (wrong terminator {})", unit.name(), op);
41 return false;
42 }
43 }
44
45 for inst in unit.insts(bb) {
47 if inst == term {
48 continue;
49 }
50 if !unit[inst].opcode().valid_in_entity() {
51 trace!(
52 "Skipping {} ({} not allowed in entity)",
53 unit.name(),
54 inst.dump(&unit)
55 );
56 return false;
57 }
58 }
59
60 match unit[term].opcode() {
63 Opcode::Wait | Opcode::WaitTime => {
64 for arg in unit.sig().inputs() {
65 let value = unit.arg_value(arg);
66 if unit.has_uses(value) && !unit[term].args().contains(&value) {
67 trace!(
68 "Skipping {} ({} not in wait sensitivity list)",
69 unit.name(),
70 value.dump(&unit)
71 );
72 return false;
73 }
74 }
75 }
76 _ => (),
77 }
78
79 true
80}