llhd/pass/
proclower.rs

1// Copyright (c) 2017-2021 Fabian Schuiki
2
3//! Process Lowering
4
5use crate::{ir::prelude::*, opt::prelude::*};
6
7/// Process Lowering
8///
9/// This pass implements lowering of suitable processes to entities.
10pub 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
26/// Check if a process is suitable for lowering to an entity.
27fn is_suitable(_ctx: &PassContext, unit: &Unit) -> bool {
28    // Ensure that there is only one basic block.
29    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    // Ensure that the terminator instruction is a wait/halt.
36    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    // Ensure that all other instructions are allowed in an entity.
46    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    // Ensure that all input arguments that are used are also contained in the
61    // wait instruction's sensitivity list.
62    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}