Add an analyze_branch method to InstructionData.
Rather than switching on instruction formats to discover the destination of a branch, use the analyze_branch method which returns a BranchInfo enum with just the relevant information. This makes CFG algorithms independent of future instruction formats for branches. Only analyze_branch needs to be updated when adding a new format.
This commit is contained in:
@@ -24,7 +24,7 @@
|
||||
|
||||
use ir::Function;
|
||||
use ir::entities::{Inst, Ebb};
|
||||
use ir::instructions::InstructionData;
|
||||
use ir::instructions::BranchInfo;
|
||||
use entity_map::EntityMap;
|
||||
|
||||
/// A basic block denoted by its enclosing Ebb and last instruction.
|
||||
@@ -68,16 +68,18 @@ impl ControlFlowGraph {
|
||||
|
||||
for ebb in &func.layout {
|
||||
for inst in func.layout.ebb_insts(ebb) {
|
||||
match func.dfg[inst] {
|
||||
InstructionData::Branch { ty: _, opcode: _, ref data } => {
|
||||
cfg.add_successor(ebb, data.destination);
|
||||
cfg.add_predecessor(data.destination, (ebb, inst));
|
||||
match func.dfg[inst].analyze_branch() {
|
||||
BranchInfo::SingleDest(dest, _) => {
|
||||
cfg.add_successor(ebb, dest);
|
||||
cfg.add_predecessor(dest, (ebb, inst));
|
||||
}
|
||||
InstructionData::Jump { ty: _, opcode: _, ref data } => {
|
||||
cfg.add_successor(ebb, data.destination);
|
||||
cfg.add_predecessor(data.destination, (ebb, inst));
|
||||
BranchInfo::Table(jt) => {
|
||||
for (_, dest) in func.jump_tables[jt].entries() {
|
||||
cfg.add_successor(ebb, dest);
|
||||
cfg.add_predecessor(dest, (ebb, inst));
|
||||
}
|
||||
}
|
||||
_ => (),
|
||||
BranchInfo::NotABranch => {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -344,6 +344,42 @@ impl InstructionData {
|
||||
}
|
||||
}
|
||||
|
||||
/// Analyzing an instruction.
|
||||
///
|
||||
/// Avoid large matches on instruction formats by using the methods efined here to examine
|
||||
/// instructions.
|
||||
impl InstructionData {
|
||||
/// Return information about the destination of a branch or jump instruction.
|
||||
///
|
||||
/// Any instruction that can transfer control to another EBB reveals its possible destinations
|
||||
/// here.
|
||||
pub fn analyze_branch<'a>(&'a self) -> BranchInfo<'a> {
|
||||
match self {
|
||||
&InstructionData::Jump { ref data, .. } => {
|
||||
BranchInfo::SingleDest(data.destination, &data.arguments)
|
||||
}
|
||||
&InstructionData::Branch { ref data, .. } => {
|
||||
BranchInfo::SingleDest(data.destination, &data.arguments)
|
||||
}
|
||||
&InstructionData::BranchTable { table, .. } => BranchInfo::Table(table),
|
||||
_ => BranchInfo::NotABranch,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Information about branch and jump instructions.
|
||||
pub enum BranchInfo<'a> {
|
||||
/// This is not a branch or jump instruction.
|
||||
/// This instruction will not transfer control to another EBB in the function, but it may still
|
||||
/// affect control flow by returning or trapping.
|
||||
NotABranch,
|
||||
|
||||
/// This is a branch or jump to a single destination EBB, possibly taking value arguments.
|
||||
SingleDest(Ebb, &'a [Value]),
|
||||
|
||||
/// This is a jump table branch which can have many destination EBBs.
|
||||
Table(JumpTable),
|
||||
}
|
||||
|
||||
/// Value type constraints for a given opcode.
|
||||
///
|
||||
|
||||
Reference in New Issue
Block a user