Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Always create the destination branch argument for the sentinel value when looking for the value definition in the predecessors #66

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
65 changes: 11 additions & 54 deletions frontend-wasm/src/ssa.rs
Original file line number Diff line number Diff line change
Expand Up @@ -134,12 +134,6 @@ enum Call {
FinishPredecessorsLookup(Value, Block),
}

/// Emit instructions to produce a zero value in the given type.
fn emit_zero(_ty: &Type, //, mut cur: FuncCursor
) -> Value {
todo!("emit zero value at the beginning of a block")
}

/// The following methods are the API of the SSA builder. Here is how it should be used when
/// translating to Miden IR:
///
Expand Down Expand Up @@ -461,55 +455,18 @@ impl SSABuilder {
let num_predecessors = self.predecessors(dest_block).len();
// When this `Drain` is dropped, these elements will get truncated.
let results = self.results.drain(self.results.len() - num_predecessors..);

let pred_val = {
let mut iter = results.as_slice().iter().filter(|&val| val != &sentinel);
if let Some(val) = iter.next() {
// This variable has at least one non-temporary definition. If they're all the same
// value, we can remove the block parameter and reference that value instead.
if iter.all(|other| other == val) {
Some(*val)
} else {
None
}
} else {
// The variable is used but never defined before. This is an irregularity in the
// code, but rather than throwing an error we silently initialize the variable to
// 0. This will have no effect since this situation happens in unreachable code.
if !dfg.is_block_inserted(dest_block) {
dfg.append_block(dest_block);
}
self.side_effects
.instructions_added_to_blocks
.push(dest_block);
let zero = emit_zero(
dfg.value_type(sentinel),
// FuncCursor::new(func).at_first_insertion_point(dest_block),
);
Some(zero)
}
};

if let Some(pred_val) = pred_val {
// Here all the predecessors use a single value to represent our variable
// so we don't need to have it as a block argument.
dfg.remove_block_param(sentinel);
pred_val
} else {
// There is disagreement in the predecessors on which value to use so we have
// to keep the block argument.
let mut preds = self.ssa_blocks[dest_block].predecessors;
for (idx, &val) in results.as_slice().iter().enumerate() {
let pred = preds.get_mut(idx, &mut self.inst_pool).unwrap();
let branch = *pred;
assert!(
dfg.insts[branch].opcode().is_branch(),
"you have declared a non-branch instruction as a predecessor to a block!"
);
dfg.append_branch_destination_argument(branch, dest_block, val);
}
sentinel
// Keep the block argument.
let mut preds = self.ssa_blocks[dest_block].predecessors;
for (idx, &val) in results.as_slice().iter().enumerate() {
let pred = preds.get_mut(idx, &mut self.inst_pool).unwrap();
let branch = *pred;
assert!(
dfg.insts[branch].opcode().is_branch(),
"you have declared a non-branch instruction as a predecessor to a block!"
);
dfg.append_branch_destination_argument(branch, dest_block, val);
}
sentinel
}

/// Returns the list of `Block`s that have been declared as predecessors of the argument.
Expand Down
31 changes: 25 additions & 6 deletions tests/integration/expected/fib.hir
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,29 @@ global external @gv2 : i32 = $0 { id = 2 };

pub fn fib(i32) -> i32 {
block0(v0: i32):
v2 = const.i32 1000 : i32;
v3 = cast v0 : u32;
v4 = cast v2 : u32;
v5 = lt v3, v4 : i1;
v6 = cast v5 : i32;
ret v6;
br block2(v0);

block1(v1: i32):

block2(v3: i32):
v4 = const.i32 3 : i32;
v5 = cast v3 : u32;
v6 = cast v4 : u32;
v7 = gt v5, v6 : i1;
v8 = cast v7 : i32;
v9 = neq v8, 0 : i1;
condbr v9, block4, block5;

block3(v2: i32):

block4:
v10 = const.i32 3 : i32;
v11 = cast v3 : u32;
v12 = cast v10 : u32;
v13 = div.checked v11, v12 : u32;
v14 = cast v13 : i32;
br block2(v14);

block5:
ret v3;
}
45 changes: 43 additions & 2 deletions tests/integration/expected/fib.masm
Original file line number Diff line number Diff line change
Expand Up @@ -667,18 +667,59 @@ export.load_dw
end

export.fib
dup.0
dup.0
push.2147483648
u32.and
eq.2147483648
assertz
push.1000
push.3
dup.0
push.2147483648
u32.and
eq.2147483648
assertz
u32.lt.checked
u32.gt.checked
u32.neq.0
push.1
while.true
if.true
dup.0
push.2147483648
u32.and
eq.2147483648
assertz
push.3
dup.0
push.2147483648
u32.and
eq.2147483648
assertz
u32.div.checked
dup.0
push.2147483648
u32.and
eq.2147483648
assertz
dup.0
dup.0
push.2147483648
u32.and
eq.2147483648
assertz
push.3
dup.0
push.2147483648
u32.and
eq.2147483648
assertz
u32.gt.checked
u32.neq.0
push.1
else
push.0
end
end

end
begin
Expand Down
18 changes: 15 additions & 3 deletions tests/integration/expected/fib.wat
Original file line number Diff line number Diff line change
@@ -1,9 +1,21 @@
(module
(type (;0;) (func (param i32) (result i32)))
(func $fib (;0;) (type 0) (param i32) (result i32)
local.get 0
i32.const 1000
i32.lt_u
loop (result i32) ;; label = @1
block ;; label = @2
local.get 0
i32.const 3
i32.gt_u
br_if 0 (;@2;)
local.get 0
return
end
local.get 0
i32.const 3
i32.div_u
local.set 0
br 0 (;@1;)
end
)
(table (;0;) 1 1 funcref)
(memory (;0;) 16)
Expand Down
8 changes: 4 additions & 4 deletions tests/rust-apps/fib/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ pub fn fib(n: u32) -> u32 {
// }
// a

if n < 1000 {
1
} else {
0
let mut a = n;
while a > 3 {
a = a / 3;
}
a
}
Loading