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
|
/// During initialization mappings will be generated for any existing
|
||||||
/// blocks within the CFG's associated function. Basic sanity checks will
|
/// blocks within the CFG's associated function. Basic sanity checks will
|
||||||
/// also be performed to ensure that the blocks are well formed.
|
/// 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() };
|
let mut cfg = ControlFlowGraph { data: BTreeMap::new() };
|
||||||
|
|
||||||
// Even ebbs without predecessors should show up in the CFG, albeit
|
// Even ebbs without predecessors should show up in the CFG, albeit
|
||||||
// with no entires.
|
// with no entires.
|
||||||
for ebb in func.ebbs_numerically() {
|
for ebb in func.ebbs_numerically() {
|
||||||
try!(cfg.init_ebb(ebb));
|
cfg.init_ebb(ebb);
|
||||||
}
|
}
|
||||||
|
|
||||||
for ebb in func.ebbs_numerically() {
|
for ebb in func.ebbs_numerically() {
|
||||||
// Flips to true when a terminating instruction is seen. So that if additional
|
// Flips to true when a terminating instruction is seen. So that if additional
|
||||||
// instructions occur an error may be returned.
|
// instructions occur an error may be returned.
|
||||||
let mut terminated = false;
|
|
||||||
for inst in func.ebb_insts(ebb) {
|
for inst in func.ebb_insts(ebb) {
|
||||||
if terminated {
|
|
||||||
return Err(format!("{} contains unreachable instructions.", ebb));
|
|
||||||
}
|
|
||||||
|
|
||||||
match func[inst] {
|
match func[inst] {
|
||||||
InstructionData::Branch { ty: _, opcode: _, ref data } => {
|
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 } => {
|
InstructionData::Jump { ty: _, opcode: _, ref data } => {
|
||||||
try!(cfg.add_predecessor(data.destination, (ebb, inst)));
|
cfg.add_predecessor(data.destination, (ebb, inst));
|
||||||
terminated = true;
|
|
||||||
}
|
|
||||||
InstructionData::Return { ty: _, opcode: _, data: _ } => {
|
|
||||||
terminated = true;
|
|
||||||
}
|
|
||||||
InstructionData::Nullary { ty: _, opcode: _ } => {
|
|
||||||
terminated = true;
|
|
||||||
}
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(cfg)
|
cfg
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initializes a predecessor set for some ebb. If an ebb already has an
|
/// Initializes a predecessor set for some ebb. If an ebb already has an
|
||||||
/// entry it will be clobbered.
|
/// 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());
|
self.data.insert(ebb, BTreeSet::new());
|
||||||
match self.data.get_mut(&ebb) {
|
self.data.get_mut(&ebb).unwrap()
|
||||||
Some(predecessors) => Ok(predecessors),
|
|
||||||
None => Err("Ebb initialization failed."),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Attempts to add a predecessor for some ebb, attempting to initialize
|
pub fn add_predecessor(&mut self, ebb: Ebb, predecessor: Predecessor) {
|
||||||
/// any ebb which has no entry.
|
self.data.get_mut(&ebb).unwrap().insert(predecessor);
|
||||||
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.")
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all of the predecessors for some ebb, if it has an entry.
|
/// 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.
|
// 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 {
|
fn jump(func: &mut Function, dest: Ebb) -> Inst {
|
||||||
func.make_inst(InstructionData::Jump {
|
func.make_inst(InstructionData::Jump {
|
||||||
opcode: Opcode::Jump,
|
opcode: Opcode::Jump,
|
||||||
@@ -169,7 +128,7 @@ mod tests {
|
|||||||
#[test]
|
#[test]
|
||||||
fn empty() {
|
fn empty() {
|
||||||
let func = Function::new();
|
let func = Function::new();
|
||||||
let cfg = ControlFlowGraph::new(&func).unwrap();
|
let cfg = ControlFlowGraph::new(&func);
|
||||||
assert_eq!(None, cfg.iter().next());
|
assert_eq!(None, cfg.iter().next());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -179,7 +138,7 @@ mod tests {
|
|||||||
func.make_ebb();
|
func.make_ebb();
|
||||||
func.make_ebb();
|
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<_>>();
|
let nodes = cfg.iter().collect::<Vec<_>>();
|
||||||
assert_eq!(nodes.len(), 3);
|
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]
|
#[test]
|
||||||
fn branches_and_jumps() {
|
fn branches_and_jumps() {
|
||||||
let mut func = Function::new();
|
let mut func = Function::new();
|
||||||
@@ -251,7 +168,7 @@ mod tests {
|
|||||||
let jmp_ebb1_ebb2 = jump(&mut func, ebb2);
|
let jmp_ebb1_ebb2 = jump(&mut func, ebb2);
|
||||||
func.append_inst(ebb1, jmp_ebb1_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 ebb0_predecessors = cfg.get_predecessors(ebb0).unwrap();
|
||||||
let ebb1_predecessors = cfg.get_predecessors(ebb1).unwrap();
|
let ebb1_predecessors = cfg.get_predecessors(ebb1).unwrap();
|
||||||
let ebb2_predecessors = cfg.get_predecessors(ebb2).unwrap();
|
let ebb2_predecessors = cfg.get_predecessors(ebb2).unwrap();
|
||||||
|
|||||||
Reference in New Issue
Block a user