Skip to content

Commit

Permalink
Adding a pass that combines pointer increments.
Browse files Browse the repository at this point in the history
This is redundant, but helps us produce better debugging info.
  • Loading branch information
Wilfred committed Dec 11, 2015
1 parent 6d85bb5 commit bfe59b0
Show file tree
Hide file tree
Showing 2 changed files with 35 additions and 4 deletions.
30 changes: 26 additions & 4 deletions src/peephole.rs
Expand Up @@ -25,7 +25,8 @@ pub fn optimize(instrs: Vec<Instruction>) -> Vec<Instruction> {

/// Apply all our peephole optimisations once and return the result.
fn optimize_once(instrs: Vec<Instruction>) -> Vec<Instruction> {
let combined = combine_increments(instrs);
fn optimize_once(instrs: Vec<Instruction>) -> (Vec<Instruction>, Option<Warning>) {
let combined = combine_ptr_increments(combine_increments(instrs));
let annotated = annotate_known_zero(combined);
let extracted = extract_multiply(annotated);
let simplified = remove_dead_loops(combine_set_and_increments(simplify_loops(extracted)));
Expand Down Expand Up @@ -185,6 +186,30 @@ pub fn combine_increments(instrs: Vec<Instruction>) -> Vec<Instruction> {
.map_loops(combine_increments)
}

pub fn combine_ptr_increments(instrs: Vec<Instruction>) -> Vec<Instruction> {
instrs.into_iter()
.coalesce(|prev_instr, instr| {
// Collapse consecutive increments.
if let &PointerIncrement { amount: prev_amount, position: prev_pos } = &prev_instr {
if let &PointerIncrement { amount, position } = &instr {
return Ok(PointerIncrement {
amount: amount + prev_amount,
position: prev_pos.combine(position),
});
}
}
Err((prev_instr, instr))
})
.filter(|instr| {
// Remove any pointer increments of 0.
if let &PointerIncrement { amount: 0, .. } = instr {
return false;
}
true
})
.map_loops(combine_ptr_increments)
}

pub fn combine_before_read(instrs: Vec<Instruction>) -> Vec<Instruction> {
let mut redundant_instr_positions = HashSet::new();

Expand Down Expand Up @@ -304,9 +329,6 @@ fn ordered_values<K: Ord + Hash + Eq, V>(map: HashMap<K, V>) -> Vec<V> {

/// Given a BF program, combine sets/increments using offsets so we
/// have single PointerIncrement at the end.
// TODO: it would be nice to have a separate pass for combining
// adjacent instructions, as we can track those positions more
// accurately. Here, we cannot combine, as instructions may not be adjacent.
pub fn sort_sequence_by_offset(instrs: Vec<Instruction>) -> Vec<Instruction> {
let mut instrs_by_offset: HashMap<isize, Vec<Instruction>> = HashMap::new();
let mut current_offset = 0;
Expand Down
9 changes: 9 additions & 0 deletions src/peephole_tests.rs
Expand Up @@ -131,6 +131,15 @@ fn combine_increment_sum_to_zero() {
assert_eq!(combine_increments(initial), vec![]);
}

#[test]
fn should_combine_ptr_increments() {
let initial = parse(">>").unwrap();
let expected = vec![
PointerIncrement { amount: 2, position: Some(Position { start: 0, end: 1 })}
];
assert_eq!(combine_ptr_increments(initial), expected);
}

#[test]
fn combine_set_sum_to_zero() {
let initial = vec![Set { amount: Wrapping(-1), offset: 0, position: Some(Position { start: 0, end: 0 }) },
Expand Down

0 comments on commit bfe59b0

Please sign in to comment.