Mass rename Ebb and relatives to Block (#1365)
* Manually rename BasicBlock to BlockPredecessor BasicBlock is a pair of (Ebb, Inst) that is used to represent the basic block subcomponent of an Ebb that is a predecessor to an Ebb. Eventually we will be able to remove this struct, but for now it makes sense to give it a non-conflicting name so that we can start to transition Ebb to represent a basic block. I have not updated any comments that refer to BasicBlock, as eventually we will remove BlockPredecessor and replace with Block, which is a basic block, so the comments will become correct. * Manually rename SSABuilder block types to avoid conflict SSABuilder has its own Block and BlockData types. These along with associated identifier will cause conflicts in a later commit, so they are renamed to be more verbose here. * Automatically rename 'Ebb' to 'Block' in *.rs * Automatically rename 'EBB' to 'block' in *.rs * Automatically rename 'ebb' to 'block' in *.rs * Automatically rename 'extended basic block' to 'basic block' in *.rs * Automatically rename 'an basic block' to 'a basic block' in *.rs * Manually update comment for `Block` `Block`'s wikipedia article required an update. * Automatically rename 'an `Block`' to 'a `Block`' in *.rs * Automatically rename 'extended_basic_block' to 'basic_block' in *.rs * Automatically rename 'ebb' to 'block' in *.clif * Manually rename clif constant that contains 'ebb' as substring to avoid conflict * Automatically rename filecheck uses of 'EBB' to 'BB' 'regex: EBB' -> 'regex: BB' '$EBB' -> '$BB' * Automatically rename 'EBB' 'Ebb' to 'block' in *.clif * Automatically rename 'an block' to 'a block' in *.clif * Fix broken testcase when function name length increases Test function names are limited to 16 characters. This causes the new longer name to be truncated and fail a filecheck test. An outdated comment was also fixed.
This commit is contained in:
@@ -26,7 +26,7 @@ use super::{hash_map, HashMap};
|
||||
use crate::environ::{FuncEnvironment, GlobalVariable, ReturnMode, WasmResult};
|
||||
use crate::state::{ControlStackFrame, ElseData, FuncTranslationState, ModuleTranslationState};
|
||||
use crate::translation_utils::{
|
||||
blocktype_params_results, ebb_with_params, f32_translation, f64_translation,
|
||||
block_with_params, blocktype_params_results, f32_translation, f64_translation,
|
||||
};
|
||||
use crate::translation_utils::{FuncIndex, GlobalIndex, MemoryIndex, SignatureIndex, TableIndex};
|
||||
use crate::wasm_unsupported;
|
||||
@@ -147,32 +147,34 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
state.reachable = false;
|
||||
}
|
||||
/***************************** Control flow blocks **********************************
|
||||
* When starting a control flow block, we create a new `Ebb` that will hold the code
|
||||
* When starting a control flow block, we create a new `Block` that will hold the code
|
||||
* after the block, and we push a frame on the control stack. Depending on the type
|
||||
* of block, we create a new `Ebb` for the body of the block with an associated
|
||||
* of block, we create a new `Block` for the body of the block with an associated
|
||||
* jump instruction.
|
||||
*
|
||||
* The `End` instruction pops the last control frame from the control stack, seals
|
||||
* the destination block (since `br` instructions targeting it only appear inside the
|
||||
* block and have already been translated) and modify the value stack to use the
|
||||
* possible `Ebb`'s arguments values.
|
||||
* possible `Block`'s arguments values.
|
||||
***********************************************************************************/
|
||||
Operator::Block { ty } => {
|
||||
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
|
||||
let next = ebb_with_params(builder, results, environ)?;
|
||||
let next = block_with_params(builder, results, environ)?;
|
||||
state.push_block(next, params.len(), results.len());
|
||||
}
|
||||
Operator::Loop { ty } => {
|
||||
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
|
||||
let loop_body = ebb_with_params(builder, params, environ)?;
|
||||
let next = ebb_with_params(builder, results, environ)?;
|
||||
let loop_body = block_with_params(builder, params, environ)?;
|
||||
let next = block_with_params(builder, results, environ)?;
|
||||
builder.ins().jump(loop_body, state.peekn(params.len()));
|
||||
state.push_loop(loop_body, next, params.len(), results.len());
|
||||
|
||||
// Pop the initial `Ebb` actuals and replace them with the `Ebb`'s
|
||||
// Pop the initial `Block` actuals and replace them with the `Block`'s
|
||||
// params since control flow joins at the top of the loop.
|
||||
state.popn(params.len());
|
||||
state.stack.extend_from_slice(builder.ebb_params(loop_body));
|
||||
state
|
||||
.stack
|
||||
.extend_from_slice(builder.block_params(loop_body));
|
||||
|
||||
builder.switch_to_block(loop_body);
|
||||
environ.translate_loop_header(builder.cursor())?;
|
||||
@@ -183,12 +185,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
let (params, results) = blocktype_params_results(module_translation_state, *ty)?;
|
||||
let (destination, else_data) = if params == results {
|
||||
// It is possible there is no `else` block, so we will only
|
||||
// allocate an ebb for it if/when we find the `else`. For now,
|
||||
// allocate an block for it if/when we find the `else`. For now,
|
||||
// we if the condition isn't true, then we jump directly to the
|
||||
// destination ebb following the whole `if...end`. If we do end
|
||||
// up discovering an `else`, then we will allocate an ebb for it
|
||||
// destination block following the whole `if...end`. If we do end
|
||||
// up discovering an `else`, then we will allocate an block for it
|
||||
// and go back and patch the jump.
|
||||
let destination = ebb_with_params(builder, results, environ)?;
|
||||
let destination = block_with_params(builder, results, environ)?;
|
||||
let branch_inst = builder
|
||||
.ins()
|
||||
.brz(val, destination, state.peekn(params.len()));
|
||||
@@ -196,8 +198,8 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
} else {
|
||||
// The `if` type signature is not valid without an `else` block,
|
||||
// so we eagerly allocate the `else` block here.
|
||||
let destination = ebb_with_params(builder, results, environ)?;
|
||||
let else_block = ebb_with_params(builder, params, environ)?;
|
||||
let destination = block_with_params(builder, results, environ)?;
|
||||
let else_block = block_with_params(builder, params, environ)?;
|
||||
builder
|
||||
.ins()
|
||||
.brz(val, else_block, state.peekn(params.len()));
|
||||
@@ -205,12 +207,12 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
(destination, ElseData::WithElse { else_block })
|
||||
};
|
||||
|
||||
let next_ebb = builder.create_ebb();
|
||||
builder.ins().jump(next_ebb, &[]);
|
||||
builder.seal_block(next_ebb); // Only predecessor is the current block.
|
||||
builder.switch_to_block(next_ebb);
|
||||
let next_block = builder.create_block();
|
||||
builder.ins().jump(next_block, &[]);
|
||||
builder.seal_block(next_block); // Only predecessor is the current block.
|
||||
builder.switch_to_block(next_block);
|
||||
|
||||
// Here we append an argument to an Ebb targeted by an argumentless jump instruction
|
||||
// Here we append an argument to an Block targeted by an argumentless jump instruction
|
||||
// But in fact there are two cases:
|
||||
// - either the If does not have a Else clause, in that case ty = EmptyBlock
|
||||
// and we add nothing;
|
||||
@@ -239,20 +241,20 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
// We have a branch from the head of the `if` to the `else`.
|
||||
state.reachable = true;
|
||||
|
||||
// Ensure we have an ebb for the `else` block (it may have
|
||||
// Ensure we have an block for the `else` block (it may have
|
||||
// already been pre-allocated, see `ElseData` for details).
|
||||
let else_ebb = match *else_data {
|
||||
let else_block = match *else_data {
|
||||
ElseData::NoElse { branch_inst } => {
|
||||
let (params, _results) =
|
||||
blocktype_params_results(module_translation_state, blocktype)?;
|
||||
debug_assert_eq!(params.len(), num_return_values);
|
||||
let else_ebb = ebb_with_params(builder, params, environ)?;
|
||||
let else_block = block_with_params(builder, params, environ)?;
|
||||
builder.ins().jump(destination, state.peekn(params.len()));
|
||||
state.popn(params.len());
|
||||
|
||||
builder.change_jump_destination(branch_inst, else_ebb);
|
||||
builder.seal_block(else_ebb);
|
||||
else_ebb
|
||||
builder.change_jump_destination(branch_inst, else_block);
|
||||
builder.seal_block(else_block);
|
||||
else_block
|
||||
}
|
||||
ElseData::WithElse { else_block } => {
|
||||
builder
|
||||
@@ -273,7 +275,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
// `if` so that we wouldn't have to save the parameters in the
|
||||
// `ControlStackFrame` as another `Vec` allocation.
|
||||
|
||||
builder.switch_to_block(else_ebb);
|
||||
builder.switch_to_block(else_block);
|
||||
|
||||
// We don't bother updating the control frame's `ElseData`
|
||||
// to `WithElse` because nothing else will read it.
|
||||
@@ -284,13 +286,13 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
}
|
||||
Operator::End => {
|
||||
let frame = state.control_stack.pop().unwrap();
|
||||
let next_ebb = frame.following_code();
|
||||
let next_block = frame.following_code();
|
||||
|
||||
if !builder.is_unreachable() || !builder.is_pristine() {
|
||||
let return_count = frame.num_return_values();
|
||||
let return_args = state.peekn_mut(return_count);
|
||||
let next_ebb_types = builder.func.dfg.ebb_param_types(next_ebb);
|
||||
bitcast_arguments(return_args, &next_ebb_types, builder);
|
||||
let next_block_types = builder.func.dfg.block_param_types(next_block);
|
||||
bitcast_arguments(return_args, &next_block_types, builder);
|
||||
builder.ins().jump(frame.following_code(), return_args);
|
||||
// You might expect that if we just finished an `if` block that
|
||||
// didn't have a corresponding `else` block, then we would clean
|
||||
@@ -299,33 +301,35 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
// since we truncate the stack back to the original height
|
||||
// below.
|
||||
}
|
||||
builder.switch_to_block(next_ebb);
|
||||
builder.seal_block(next_ebb);
|
||||
builder.switch_to_block(next_block);
|
||||
builder.seal_block(next_block);
|
||||
// If it is a loop we also have to seal the body loop block
|
||||
if let ControlStackFrame::Loop { header, .. } = frame {
|
||||
builder.seal_block(header)
|
||||
}
|
||||
state.stack.truncate(frame.original_stack_size());
|
||||
state.stack.extend_from_slice(builder.ebb_params(next_ebb));
|
||||
state
|
||||
.stack
|
||||
.extend_from_slice(builder.block_params(next_block));
|
||||
}
|
||||
/**************************** Branch instructions *********************************
|
||||
* The branch instructions all have as arguments a target nesting level, which
|
||||
* corresponds to how many control stack frames do we have to pop to get the
|
||||
* destination `Ebb`.
|
||||
* destination `Block`.
|
||||
*
|
||||
* Once the destination `Ebb` is found, we sometimes have to declare a certain depth
|
||||
* Once the destination `Block` is found, we sometimes have to declare a certain depth
|
||||
* of the stack unreachable, because some branch instructions are terminator.
|
||||
*
|
||||
* The `br_table` case is much more complicated because Cranelift's `br_table` instruction
|
||||
* does not support jump arguments like all the other branch instructions. That is why, in
|
||||
* the case where we would use jump arguments for every other branch instructions, we
|
||||
* need to split the critical edges leaving the `br_tables` by creating one `Ebb` per
|
||||
* table destination; the `br_table` will point to these newly created `Ebbs` and these
|
||||
* `Ebb`s contain only a jump instruction pointing to the final destination, this time with
|
||||
* need to split the critical edges leaving the `br_tables` by creating one `Block` per
|
||||
* table destination; the `br_table` will point to these newly created `Blocks` and these
|
||||
* `Block`s contain only a jump instruction pointing to the final destination, this time with
|
||||
* jump arguments.
|
||||
*
|
||||
* This system is also implemented in Cranelift's SSA construction algorithm, because
|
||||
* `use_var` located in a destination `Ebb` of a `br_table` might trigger the addition
|
||||
* `use_var` located in a destination `Block` of a `br_table` might trigger the addition
|
||||
* of jump arguments in each predecessor branch instruction, one of which might be a
|
||||
* `br_table`.
|
||||
***********************************************************************************/
|
||||
@@ -345,7 +349,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
|
||||
// Bitcast any vector arguments to their default type, I8X16, before jumping.
|
||||
let destination_args = state.peekn_mut(return_count);
|
||||
let destination_types = builder.func.dfg.ebb_param_types(br_destination);
|
||||
let destination_types = builder.func.dfg.block_param_types(br_destination);
|
||||
bitcast_arguments(
|
||||
destination_args,
|
||||
&destination_types[..return_count],
|
||||
@@ -379,53 +383,53 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
if jump_args_count == 0 {
|
||||
// No jump arguments
|
||||
for depth in &*depths {
|
||||
let ebb = {
|
||||
let block = {
|
||||
let i = state.control_stack.len() - 1 - (*depth as usize);
|
||||
let frame = &mut state.control_stack[i];
|
||||
frame.set_branched_to_exit();
|
||||
frame.br_destination()
|
||||
};
|
||||
data.push_entry(ebb);
|
||||
data.push_entry(block);
|
||||
}
|
||||
let jt = builder.create_jump_table(data);
|
||||
let ebb = {
|
||||
let block = {
|
||||
let i = state.control_stack.len() - 1 - (default as usize);
|
||||
let frame = &mut state.control_stack[i];
|
||||
frame.set_branched_to_exit();
|
||||
frame.br_destination()
|
||||
};
|
||||
builder.ins().br_table(val, ebb, jt);
|
||||
builder.ins().br_table(val, block, jt);
|
||||
} else {
|
||||
// Here we have jump arguments, but Cranelift's br_table doesn't support them
|
||||
// We then proceed to split the edges going out of the br_table
|
||||
let return_count = jump_args_count;
|
||||
let mut dest_ebb_sequence = vec![];
|
||||
let mut dest_ebb_map = HashMap::new();
|
||||
let mut dest_block_sequence = vec![];
|
||||
let mut dest_block_map = HashMap::new();
|
||||
for depth in &*depths {
|
||||
let branch_ebb = match dest_ebb_map.entry(*depth as usize) {
|
||||
let branch_block = match dest_block_map.entry(*depth as usize) {
|
||||
hash_map::Entry::Occupied(entry) => *entry.get(),
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let ebb = builder.create_ebb();
|
||||
dest_ebb_sequence.push((*depth as usize, ebb));
|
||||
*entry.insert(ebb)
|
||||
let block = builder.create_block();
|
||||
dest_block_sequence.push((*depth as usize, block));
|
||||
*entry.insert(block)
|
||||
}
|
||||
};
|
||||
data.push_entry(branch_ebb);
|
||||
data.push_entry(branch_block);
|
||||
}
|
||||
let default_branch_ebb = match dest_ebb_map.entry(default as usize) {
|
||||
let default_branch_block = match dest_block_map.entry(default as usize) {
|
||||
hash_map::Entry::Occupied(entry) => *entry.get(),
|
||||
hash_map::Entry::Vacant(entry) => {
|
||||
let ebb = builder.create_ebb();
|
||||
dest_ebb_sequence.push((default as usize, ebb));
|
||||
*entry.insert(ebb)
|
||||
let block = builder.create_block();
|
||||
dest_block_sequence.push((default as usize, block));
|
||||
*entry.insert(block)
|
||||
}
|
||||
};
|
||||
let jt = builder.create_jump_table(data);
|
||||
builder.ins().br_table(val, default_branch_ebb, jt);
|
||||
for (depth, dest_ebb) in dest_ebb_sequence {
|
||||
builder.switch_to_block(dest_ebb);
|
||||
builder.seal_block(dest_ebb);
|
||||
let real_dest_ebb = {
|
||||
builder.ins().br_table(val, default_branch_block, jt);
|
||||
for (depth, dest_block) in dest_block_sequence {
|
||||
builder.switch_to_block(dest_block);
|
||||
builder.seal_block(dest_block);
|
||||
let real_dest_block = {
|
||||
let i = state.control_stack.len() - 1 - depth;
|
||||
let frame = &mut state.control_stack[i];
|
||||
frame.set_branched_to_exit();
|
||||
@@ -434,14 +438,14 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
|
||||
|
||||
// Bitcast any vector arguments to their default type, I8X16, before jumping.
|
||||
let destination_args = state.peekn_mut(return_count);
|
||||
let destination_types = builder.func.dfg.ebb_param_types(real_dest_ebb);
|
||||
let destination_types = builder.func.dfg.block_param_types(real_dest_block);
|
||||
bitcast_arguments(
|
||||
destination_args,
|
||||
&destination_types[..return_count],
|
||||
builder,
|
||||
);
|
||||
|
||||
builder.ins().jump(real_dest_ebb, destination_args);
|
||||
builder.ins().jump(real_dest_block, destination_args);
|
||||
}
|
||||
state.popn(return_count);
|
||||
}
|
||||
@@ -1498,7 +1502,7 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
|
||||
// Push a placeholder control stack entry. The if isn't reachable,
|
||||
// so we don't have any branches anywhere.
|
||||
state.push_if(
|
||||
ir::Ebb::reserved_value(),
|
||||
ir::Block::reserved_value(),
|
||||
ElseData::NoElse {
|
||||
branch_inst: ir::Inst::reserved_value(),
|
||||
},
|
||||
@@ -1508,7 +1512,7 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
|
||||
);
|
||||
}
|
||||
Operator::Loop { ty: _ } | Operator::Block { ty: _ } => {
|
||||
state.push_block(ir::Ebb::reserved_value(), 0, 0);
|
||||
state.push_block(ir::Block::reserved_value(), 0, 0);
|
||||
}
|
||||
Operator::Else => {
|
||||
let i = state.control_stack.len() - 1;
|
||||
@@ -1527,21 +1531,21 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
|
||||
// We have a branch from the head of the `if` to the `else`.
|
||||
state.reachable = true;
|
||||
|
||||
let else_ebb = match *else_data {
|
||||
let else_block = match *else_data {
|
||||
ElseData::NoElse { branch_inst } => {
|
||||
let (params, _results) =
|
||||
blocktype_params_results(module_translation_state, blocktype)?;
|
||||
let else_ebb = ebb_with_params(builder, params, environ)?;
|
||||
let else_block = block_with_params(builder, params, environ)?;
|
||||
|
||||
// We change the target of the branch instruction.
|
||||
builder.change_jump_destination(branch_inst, else_ebb);
|
||||
builder.seal_block(else_ebb);
|
||||
else_ebb
|
||||
builder.change_jump_destination(branch_inst, else_block);
|
||||
builder.seal_block(else_block);
|
||||
else_block
|
||||
}
|
||||
ElseData::WithElse { else_block } => else_block,
|
||||
};
|
||||
|
||||
builder.switch_to_block(else_ebb);
|
||||
builder.switch_to_block(else_block);
|
||||
|
||||
// Again, no need to push the parameters for the `else`,
|
||||
// since we already did when we saw the original `if`. See
|
||||
@@ -1596,7 +1600,7 @@ fn translate_unreachable_operator<FE: FuncEnvironment + ?Sized>(
|
||||
|
||||
// And add the return values of the block but only if the next block is reachable
|
||||
// (which corresponds to testing if the stack depth is 1)
|
||||
stack.extend_from_slice(builder.ebb_params(frame.following_code()));
|
||||
stack.extend_from_slice(builder.block_params(frame.following_code()));
|
||||
state.reachable = true;
|
||||
}
|
||||
}
|
||||
@@ -1736,21 +1740,21 @@ fn translate_br_if(
|
||||
let (br_destination, inputs) = translate_br_if_args(relative_depth, state);
|
||||
|
||||
// Bitcast any vector arguments to their default type, I8X16, before jumping.
|
||||
let destination_types = builder.func.dfg.ebb_param_types(br_destination);
|
||||
let destination_types = builder.func.dfg.block_param_types(br_destination);
|
||||
bitcast_arguments(inputs, &destination_types[..inputs.len()], builder);
|
||||
|
||||
builder.ins().brnz(val, br_destination, inputs);
|
||||
|
||||
let next_ebb = builder.create_ebb();
|
||||
builder.ins().jump(next_ebb, &[]);
|
||||
builder.seal_block(next_ebb); // The only predecessor is the current block.
|
||||
builder.switch_to_block(next_ebb);
|
||||
let next_block = builder.create_block();
|
||||
builder.ins().jump(next_block, &[]);
|
||||
builder.seal_block(next_block); // The only predecessor is the current block.
|
||||
builder.switch_to_block(next_block);
|
||||
}
|
||||
|
||||
fn translate_br_if_args(
|
||||
relative_depth: u32,
|
||||
state: &mut FuncTranslationState,
|
||||
) -> (ir::Ebb, &mut [ir::Value]) {
|
||||
) -> (ir::Block, &mut [ir::Value]) {
|
||||
let i = state.control_stack.len() - 1 - (relative_depth as usize);
|
||||
let (return_count, br_destination) = {
|
||||
let frame = &mut state.control_stack[i];
|
||||
@@ -1973,7 +1977,7 @@ fn pop2_with_bitcast(
|
||||
/// A helper for bitcasting a sequence of values (e.g. function arguments). If a value is a
|
||||
/// vector type that does not match its expected type, this will modify the value in place to point
|
||||
/// to the result of a `raw_bitcast`. This conversion is necessary to translate Wasm code that
|
||||
/// uses `V128` as function parameters (or implicitly in EBB parameters) and still use specific
|
||||
/// uses `V128` as function parameters (or implicitly in block parameters) and still use specific
|
||||
/// CLIF types (e.g. `I32X4`) in the function body.
|
||||
pub fn bitcast_arguments(
|
||||
arguments: &mut [Value],
|
||||
|
||||
Reference in New Issue
Block a user