|
|
@ -292,6 +292,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>( |
|
|
|
Operator::If { blockty } => { |
|
|
|
let val = state.pop1(); |
|
|
|
|
|
|
|
let next_block = builder.create_block(); |
|
|
|
let (params, results) = blocktype_params_results(validator, *blockty)?; |
|
|
|
let (destination, else_data) = if params.clone().eq(results.clone()) { |
|
|
|
// It is possible there is no `else` block, so we will only
|
|
|
@ -301,21 +302,38 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>( |
|
|
|
// up discovering an `else`, then we will allocate a block for it
|
|
|
|
// and go back and patch the jump.
|
|
|
|
let destination = block_with_params(builder, results.clone(), environ)?; |
|
|
|
let branch_inst = |
|
|
|
canonicalise_then_brz(builder, val, destination, state.peekn(params.len())); |
|
|
|
(destination, ElseData::NoElse { branch_inst }) |
|
|
|
let branch_inst = canonicalise_brif( |
|
|
|
builder, |
|
|
|
val, |
|
|
|
next_block, |
|
|
|
&[], |
|
|
|
destination, |
|
|
|
state.peekn(params.len()), |
|
|
|
); |
|
|
|
( |
|
|
|
destination, |
|
|
|
ElseData::NoElse { |
|
|
|
branch_inst, |
|
|
|
placeholder: destination, |
|
|
|
}, |
|
|
|
) |
|
|
|
} else { |
|
|
|
// The `if` type signature is not valid without an `else` block,
|
|
|
|
// so we eagerly allocate the `else` block here.
|
|
|
|
let destination = block_with_params(builder, results.clone(), environ)?; |
|
|
|
let else_block = block_with_params(builder, params.clone(), environ)?; |
|
|
|
canonicalise_then_brz(builder, val, else_block, state.peekn(params.len())); |
|
|
|
canonicalise_brif( |
|
|
|
builder, |
|
|
|
val, |
|
|
|
next_block, |
|
|
|
&[], |
|
|
|
else_block, |
|
|
|
state.peekn(params.len()), |
|
|
|
); |
|
|
|
builder.seal_block(else_block); |
|
|
|
(destination, ElseData::WithElse { else_block }) |
|
|
|
}; |
|
|
|
|
|
|
|
let next_block = builder.create_block(); |
|
|
|
canonicalise_then_jump(builder, next_block, &[]); |
|
|
|
builder.seal_block(next_block); // Only predecessor is the current block.
|
|
|
|
builder.switch_to_block(next_block); |
|
|
|
|
|
|
@ -357,7 +375,10 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>( |
|
|
|
// Ensure we have a block for the `else` block (it may have
|
|
|
|
// already been pre-allocated, see `ElseData` for details).
|
|
|
|
let else_block = match *else_data { |
|
|
|
ElseData::NoElse { branch_inst } => { |
|
|
|
ElseData::NoElse { |
|
|
|
branch_inst, |
|
|
|
placeholder, |
|
|
|
} => { |
|
|
|
let (params, _results) = |
|
|
|
blocktype_params_results(validator, blocktype)?; |
|
|
|
debug_assert_eq!(params.len(), num_return_values); |
|
|
@ -370,7 +391,11 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>( |
|
|
|
); |
|
|
|
state.popn(params.len()); |
|
|
|
|
|
|
|
builder.change_jump_destination(branch_inst, else_block); |
|
|
|
builder.change_jump_destination( |
|
|
|
branch_inst, |
|
|
|
placeholder, |
|
|
|
else_block, |
|
|
|
); |
|
|
|
builder.seal_block(else_block); |
|
|
|
else_block |
|
|
|
} |
|
|
@ -2171,6 +2196,7 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>( |
|
|
|
ir::Block::reserved_value(), |
|
|
|
ElseData::NoElse { |
|
|
|
branch_inst: ir::Inst::reserved_value(), |
|
|
|
placeholder: ir::Block::reserved_value(), |
|
|
|
}, |
|
|
|
0, |
|
|
|
0, |
|
|
@ -2198,7 +2224,10 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>( |
|
|
|
state.reachable = true; |
|
|
|
|
|
|
|
let else_block = match *else_data { |
|
|
|
ElseData::NoElse { branch_inst } => { |
|
|
|
ElseData::NoElse { |
|
|
|
branch_inst, |
|
|
|
placeholder, |
|
|
|
} => { |
|
|
|
let (params, _results) = |
|
|
|
blocktype_params_results(validator, blocktype)?; |
|
|
|
let else_block = block_with_params(builder, params, environ)?; |
|
|
@ -2206,7 +2235,11 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>( |
|
|
|
frame.truncate_value_stack_to_else_params(&mut state.stack); |
|
|
|
|
|
|
|
// We change the target of the branch instruction.
|
|
|
|
builder.change_jump_destination(branch_inst, else_block); |
|
|
|
builder.change_jump_destination( |
|
|
|
branch_inst, |
|
|
|
placeholder, |
|
|
|
else_block, |
|
|
|
); |
|
|
|
builder.seal_block(else_block); |
|
|
|
else_block |
|
|
|
} |
|
|
@ -2816,10 +2849,9 @@ fn translate_br_if( |
|
|
|
) { |
|
|
|
let val = state.pop1(); |
|
|
|
let (br_destination, inputs) = translate_br_if_args(relative_depth, state); |
|
|
|
canonicalise_then_brnz(builder, val, br_destination, inputs); |
|
|
|
|
|
|
|
let next_block = builder.create_block(); |
|
|
|
canonicalise_then_jump(builder, next_block, &[]); |
|
|
|
canonicalise_brif(builder, val, br_destination, inputs, next_block, &[]); |
|
|
|
|
|
|
|
builder.seal_block(next_block); // The only predecessor is the current block.
|
|
|
|
builder.switch_to_block(next_block); |
|
|
|
} |
|
|
@ -3120,28 +3152,28 @@ fn canonicalise_then_jump( |
|
|
|
builder.ins().jump(destination, canonicalised) |
|
|
|
} |
|
|
|
|
|
|
|
/// The same but for a `brz` instruction.
|
|
|
|
fn canonicalise_then_brz( |
|
|
|
/// The same but for a `brif` instruction.
|
|
|
|
fn canonicalise_brif( |
|
|
|
builder: &mut FunctionBuilder, |
|
|
|
cond: ir::Value, |
|
|
|
destination: ir::Block, |
|
|
|
params: &[Value], |
|
|
|
block_then: ir::Block, |
|
|
|
params_then: &[ir::Value], |
|
|
|
block_else: ir::Block, |
|
|
|
params_else: &[ir::Value], |
|
|
|
) -> ir::Inst { |
|
|
|
let mut tmp_canonicalised = SmallVec::<[ir::Value; 16]>::new(); |
|
|
|
let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params); |
|
|
|
builder.ins().brz(cond, destination, canonicalised) |
|
|
|
} |
|
|
|
|
|
|
|
/// The same but for a `brnz` instruction.
|
|
|
|
fn canonicalise_then_brnz( |
|
|
|
builder: &mut FunctionBuilder, |
|
|
|
cond: ir::Value, |
|
|
|
destination: ir::Block, |
|
|
|
params: &[Value], |
|
|
|
) -> ir::Inst { |
|
|
|
let mut tmp_canonicalised = SmallVec::<[ir::Value; 16]>::new(); |
|
|
|
let canonicalised = canonicalise_v128_values(&mut tmp_canonicalised, builder, params); |
|
|
|
builder.ins().brnz(cond, destination, canonicalised) |
|
|
|
let mut tmp_canonicalised_then = SmallVec::<[ir::Value; 16]>::new(); |
|
|
|
let canonicalised_then = |
|
|
|
canonicalise_v128_values(&mut tmp_canonicalised_then, builder, params_then); |
|
|
|
let mut tmp_canonicalised_else = SmallVec::<[ir::Value; 16]>::new(); |
|
|
|
let canonicalised_else = |
|
|
|
canonicalise_v128_values(&mut tmp_canonicalised_else, builder, params_else); |
|
|
|
builder.ins().brif( |
|
|
|
cond, |
|
|
|
block_then, |
|
|
|
canonicalised_then, |
|
|
|
block_else, |
|
|
|
canonicalised_else, |
|
|
|
) |
|
|
|
} |
|
|
|
|
|
|
|
/// A helper for popping and bitcasting a single value; since SIMD values can lose their type by
|
|
|
|