Visit all successors of a block with a given visitor closure. The closure arguments are the branch instruction that is used to reach the successor, the successor block itself, and a flag indicating whether the block is branched to via a table entry.
(
f: &Function,
block: Block,
mut visit: F,
)
| 167 | /// the successor block itself, and a flag indicating whether the block is |
| 168 | /// branched to via a table entry. |
| 169 | pub(crate) fn visit_block_succs<F: FnMut(Inst, Block, bool)>( |
| 170 | f: &Function, |
| 171 | block: Block, |
| 172 | mut visit: F, |
| 173 | ) { |
| 174 | if let Some(inst) = f.layout.last_inst(block) { |
| 175 | match &f.dfg.insts[inst] { |
| 176 | ir::InstructionData::Jump { |
| 177 | destination: dest, .. |
| 178 | } => { |
| 179 | visit(inst, dest.block(&f.dfg.value_lists), false); |
| 180 | } |
| 181 | |
| 182 | ir::InstructionData::Brif { |
| 183 | blocks: [block_then, block_else], |
| 184 | .. |
| 185 | } => { |
| 186 | visit(inst, block_then.block(&f.dfg.value_lists), false); |
| 187 | visit(inst, block_else.block(&f.dfg.value_lists), false); |
| 188 | } |
| 189 | |
| 190 | ir::InstructionData::BranchTable { table, .. } => { |
| 191 | let pool = &f.dfg.value_lists; |
| 192 | let table = &f.stencil.dfg.jump_tables[*table]; |
| 193 | |
| 194 | // The default block is reached via a direct conditional branch, |
| 195 | // so it is not part of the table. We visit the default block |
| 196 | // first explicitly, to mirror the traversal order of |
| 197 | // `JumpTableData::all_branches`, and transitively the order of |
| 198 | // `InstructionData::branch_destination`. |
| 199 | // |
| 200 | // Additionally, this case is why we are unable to replace this |
| 201 | // whole function with a loop over `branch_destination`: we need |
| 202 | // to report which branch targets come from the table vs the |
| 203 | // default. |
| 204 | visit(inst, table.default_block().block(pool), false); |
| 205 | |
| 206 | for dest in table.as_slice() { |
| 207 | visit(inst, dest.block(pool), true); |
| 208 | } |
| 209 | } |
| 210 | |
| 211 | ir::InstructionData::TryCall { exception, .. } |
| 212 | | ir::InstructionData::TryCallIndirect { exception, .. } => { |
| 213 | let pool = &f.dfg.value_lists; |
| 214 | let exdata = &f.stencil.dfg.exception_tables[*exception]; |
| 215 | |
| 216 | for dest in exdata.all_branches() { |
| 217 | visit(inst, dest.block(pool), false); |
| 218 | } |
| 219 | } |
| 220 | |
| 221 | inst => debug_assert!(!inst.opcode().is_branch()), |
| 222 | } |
| 223 | } |
| 224 | } |
no test coverage detected