Replace Results with assertions in invariant cases.
It seems reasonable that certain non-recoverable errors during the building of the CFG should crash.
This commit is contained in:
@@ -43,76 +43,42 @@ impl ControlFlowGraph {
|
||||
/// During initialization mappings will be generated for any existing
|
||||
/// blocks within the CFG's associated function. Basic sanity checks will
|
||||
/// also be performed to ensure that the blocks are well formed.
|
||||
pub fn new(func: &Function) -> Result<ControlFlowGraph, String> {
|
||||
pub fn new(func: &Function) -> ControlFlowGraph {
|
||||
let mut cfg = ControlFlowGraph { data: BTreeMap::new() };
|
||||
|
||||
// Even ebbs without predecessors should show up in the CFG, albeit
|
||||
// with no entires.
|
||||
for ebb in func.ebbs_numerically() {
|
||||
try!(cfg.init_ebb(ebb));
|
||||
cfg.init_ebb(ebb);
|
||||
}
|
||||
|
||||
for ebb in func.ebbs_numerically() {
|
||||
// Flips to true when a terminating instruction is seen. So that if additional
|
||||
// instructions occur an error may be returned.
|
||||
let mut terminated = false;
|
||||
for inst in func.ebb_insts(ebb) {
|
||||
if terminated {
|
||||
return Err(format!("{} contains unreachable instructions.", ebb));
|
||||
}
|
||||
|
||||
match func[inst] {
|
||||
InstructionData::Branch { ty: _, opcode: _, ref data } => {
|
||||
try!(cfg.add_predecessor(data.destination, (ebb, inst)));
|
||||
cfg.add_predecessor(data.destination, (ebb, inst));
|
||||
}
|
||||
InstructionData::Jump { ty: _, opcode: _, ref data } => {
|
||||
try!(cfg.add_predecessor(data.destination, (ebb, inst)));
|
||||
terminated = true;
|
||||
}
|
||||
InstructionData::Return { ty: _, opcode: _, data: _ } => {
|
||||
terminated = true;
|
||||
}
|
||||
InstructionData::Nullary { ty: _, opcode: _ } => {
|
||||
terminated = true;
|
||||
cfg.add_predecessor(data.destination, (ebb, inst));
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
}
|
||||
Ok(cfg)
|
||||
cfg
|
||||
}
|
||||
|
||||
/// Initializes a predecessor set for some ebb. If an ebb already has an
|
||||
/// entry it will be clobbered.
|
||||
pub fn init_ebb(&mut self, ebb: Ebb) -> Result<&mut PredecessorSet, &'static str> {
|
||||
pub fn init_ebb(&mut self, ebb: Ebb) -> &mut PredecessorSet {
|
||||
self.data.insert(ebb, BTreeSet::new());
|
||||
match self.data.get_mut(&ebb) {
|
||||
Some(predecessors) => Ok(predecessors),
|
||||
None => Err("Ebb initialization failed."),
|
||||
}
|
||||
self.data.get_mut(&ebb).unwrap()
|
||||
}
|
||||
|
||||
/// Attempts to add a predecessor for some ebb, attempting to initialize
|
||||
/// any ebb which has no entry.
|
||||
pub fn add_predecessor(&mut self,
|
||||
ebb: Ebb,
|
||||
predecessor: Predecessor)
|
||||
-> Result<(), &'static str> {
|
||||
let success = match self.data.get_mut(&ebb) {
|
||||
Some(predecessors) => predecessors.insert(predecessor),
|
||||
None => false,
|
||||
};
|
||||
|
||||
if success {
|
||||
Ok(())
|
||||
} else {
|
||||
let mut predecessors = try!(self.init_ebb(ebb));
|
||||
if predecessors.insert(predecessor) {
|
||||
return Ok(());
|
||||
}
|
||||
Err("Predecessor insertion failed.")
|
||||
}
|
||||
|
||||
pub fn add_predecessor(&mut self, ebb: Ebb, predecessor: Predecessor) {
|
||||
self.data.get_mut(&ebb).unwrap().insert(predecessor);
|
||||
}
|
||||
|
||||
/// Returns all of the predecessors for some ebb, if it has an entry.
|
||||
@@ -136,13 +102,6 @@ mod tests {
|
||||
|
||||
// Some instructions will be re-used in several tests.
|
||||
|
||||
fn nullary(func: &mut Function) -> Inst {
|
||||
func.make_inst(InstructionData::Nullary {
|
||||
opcode: Opcode::Iconst,
|
||||
ty: types::I32,
|
||||
})
|
||||
}
|
||||
|
||||
fn jump(func: &mut Function, dest: Ebb) -> Inst {
|
||||
func.make_inst(InstructionData::Jump {
|
||||
opcode: Opcode::Jump,
|
||||
@@ -169,7 +128,7 @@ mod tests {
|
||||
#[test]
|
||||
fn empty() {
|
||||
let func = Function::new();
|
||||
let cfg = ControlFlowGraph::new(&func).unwrap();
|
||||
let cfg = ControlFlowGraph::new(&func);
|
||||
assert_eq!(None, cfg.iter().next());
|
||||
}
|
||||
|
||||
@@ -179,7 +138,7 @@ mod tests {
|
||||
func.make_ebb();
|
||||
func.make_ebb();
|
||||
func.make_ebb();
|
||||
let cfg = ControlFlowGraph::new(&func).unwrap();
|
||||
let cfg = ControlFlowGraph::new(&func);
|
||||
let nodes = cfg.iter().collect::<Vec<_>>();
|
||||
assert_eq!(nodes.len(), 3);
|
||||
|
||||
@@ -190,48 +149,6 @@ mod tests {
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "instructions")]
|
||||
fn nullable_before_branch() {
|
||||
// Ensure that branching after a nullary, within an ebb, triggers an error.
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.make_ebb();
|
||||
let ebb1_malformed = func.make_ebb();
|
||||
let ebb2 = func.make_ebb();
|
||||
|
||||
let nullary_inst = nullary(&mut func);
|
||||
func.append_inst(ebb1_malformed, nullary_inst);
|
||||
|
||||
let jmp_ebb1_ebb0 = jump(&mut func, ebb0);
|
||||
func.append_inst(ebb1_malformed, jmp_ebb1_ebb0);
|
||||
|
||||
let jmp_ebb0_ebb2 = jump(&mut func, ebb2);
|
||||
func.append_inst(ebb0, jmp_ebb0_ebb2);
|
||||
|
||||
ControlFlowGraph::new(&func).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
#[should_panic(expected = "instructions")]
|
||||
fn jump_before_branch() {
|
||||
// Ensure that branching after a jump, within an ebb, triggers an error.
|
||||
let mut func = Function::new();
|
||||
let ebb0 = func.make_ebb();
|
||||
let ebb1_malformed = func.make_ebb();
|
||||
let ebb2 = func.make_ebb();
|
||||
|
||||
let jmp_ebb0_ebb1 = jump(&mut func, ebb2);
|
||||
func.append_inst(ebb0, jmp_ebb0_ebb1);
|
||||
|
||||
let jmp_ebb1_ebb2 = jump(&mut func, ebb2);
|
||||
func.append_inst(ebb1_malformed, jmp_ebb1_ebb2);
|
||||
|
||||
let br_ebb1_ebb0 = branch(&mut func, ebb0);
|
||||
func.append_inst(ebb1_malformed, br_ebb1_ebb0);
|
||||
|
||||
ControlFlowGraph::new(&func).unwrap();
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn branches_and_jumps() {
|
||||
let mut func = Function::new();
|
||||
@@ -251,7 +168,7 @@ mod tests {
|
||||
let jmp_ebb1_ebb2 = jump(&mut func, ebb2);
|
||||
func.append_inst(ebb1, jmp_ebb1_ebb2);
|
||||
|
||||
let cfg = ControlFlowGraph::new(&func).unwrap();
|
||||
let cfg = ControlFlowGraph::new(&func);
|
||||
let ebb0_predecessors = cfg.get_predecessors(ebb0).unwrap();
|
||||
let ebb1_predecessors = cfg.get_predecessors(ebb1).unwrap();
|
||||
let ebb2_predecessors = cfg.get_predecessors(ebb2).unwrap();
|
||||
|
||||
Reference in New Issue
Block a user