Promote the BasicBlock tuple to a real struct;
It makes reading code that uses it easier to understand.
This commit is contained in:
committed by
Dan Gohman
parent
ce177d643e
commit
f72ff791b4
@@ -2,7 +2,7 @@
|
||||
|
||||
use std::fmt::{Display, Formatter, Result, Write};
|
||||
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use ir::instructions::BranchInfo;
|
||||
use ir::Function;
|
||||
|
||||
@@ -61,7 +61,7 @@ impl<'a> CFGPrinter<'a> {
|
||||
|
||||
fn cfg_connections(&self, w: &mut Write) -> Result {
|
||||
for ebb in &self.func.layout {
|
||||
for (parent, inst) in self.cfg.pred_iter(ebb) {
|
||||
for BasicBlock { ebb: parent, inst } in self.cfg.pred_iter(ebb) {
|
||||
writeln!(w, " {}:{} -> {}", parent, inst, ebb)?;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -177,19 +177,19 @@ impl DominatorTree {
|
||||
layout: &Layout,
|
||||
) -> BasicBlock {
|
||||
loop {
|
||||
match self.rpo_cmp_ebb(a.0, b.0) {
|
||||
match self.rpo_cmp_ebb(a.ebb, b.ebb) {
|
||||
Ordering::Less => {
|
||||
// `a` comes before `b` in the RPO. Move `b` up.
|
||||
let idom = self.nodes[b.0].idom.expect("Unreachable basic block?");
|
||||
b = (
|
||||
let idom = self.nodes[b.ebb].idom.expect("Unreachable basic block?");
|
||||
b = BasicBlock::new(
|
||||
layout.inst_ebb(idom).expect("Dangling idom instruction"),
|
||||
idom,
|
||||
);
|
||||
}
|
||||
Ordering::Greater => {
|
||||
// `b` comes before `a` in the RPO. Move `a` up.
|
||||
let idom = self.nodes[a.0].idom.expect("Unreachable basic block?");
|
||||
a = (
|
||||
let idom = self.nodes[a.ebb].idom.expect("Unreachable basic block?");
|
||||
a = BasicBlock::new(
|
||||
layout.inst_ebb(idom).expect("Dangling idom instruction"),
|
||||
idom,
|
||||
);
|
||||
@@ -198,10 +198,13 @@ impl DominatorTree {
|
||||
}
|
||||
}
|
||||
|
||||
debug_assert_eq!(a.0, b.0, "Unreachable block passed to common_dominator?");
|
||||
debug_assert_eq!(
|
||||
a.ebb, b.ebb,
|
||||
"Unreachable block passed to common_dominator?"
|
||||
);
|
||||
|
||||
// We're in the same EBB. The common dominator is the earlier instruction.
|
||||
if layout.cmp(a.1, b.1) == Ordering::Less {
|
||||
if layout.cmp(a.inst, b.inst) == Ordering::Less {
|
||||
a
|
||||
} else {
|
||||
b
|
||||
@@ -420,7 +423,7 @@ impl DominatorTree {
|
||||
// Note that during the first pass, `rpo_number` is 1 for reachable blocks that haven't
|
||||
// been visited yet, 0 for unreachable blocks.
|
||||
let mut reachable_preds = cfg.pred_iter(ebb)
|
||||
.filter(|&(pred, _)| self.nodes[pred].rpo_number > 1);
|
||||
.filter(|&BasicBlock { ebb: pred, .. }| self.nodes[pred].rpo_number > 1);
|
||||
|
||||
// The RPO must visit at least one predecessor before this node.
|
||||
let mut idom = reachable_preds
|
||||
@@ -431,7 +434,7 @@ impl DominatorTree {
|
||||
idom = self.common_dominator(idom, pred, layout);
|
||||
}
|
||||
|
||||
idom.1
|
||||
idom.inst
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,20 @@ use std::mem;
|
||||
use timing;
|
||||
|
||||
/// A basic block denoted by its enclosing Ebb and last instruction.
|
||||
pub type BasicBlock = (Ebb, Inst);
|
||||
#[derive(PartialEq, Eq)]
|
||||
pub struct BasicBlock {
|
||||
/// Enclosing Ebb key.
|
||||
pub ebb: Ebb,
|
||||
/// Last instruction in the basic block.
|
||||
pub inst: Inst,
|
||||
}
|
||||
|
||||
impl BasicBlock {
|
||||
/// Convenient method to construct new BasicBlock.
|
||||
pub fn new(ebb: Ebb, inst: Inst) -> Self {
|
||||
Self { ebb, inst }
|
||||
}
|
||||
}
|
||||
|
||||
/// A container for the successors and predecessors of some Ebb.
|
||||
#[derive(Clone, Default)]
|
||||
@@ -110,11 +123,11 @@ impl ControlFlowGraph {
|
||||
for inst in func.layout.ebb_insts(ebb) {
|
||||
match func.dfg.analyze_branch(inst) {
|
||||
BranchInfo::SingleDest(dest, _) => {
|
||||
self.add_edge((ebb, inst), dest);
|
||||
self.add_edge(BasicBlock::new(ebb, inst), dest);
|
||||
}
|
||||
BranchInfo::Table(jt) => {
|
||||
for (_, dest) in func.jump_tables[jt].entries() {
|
||||
self.add_edge((ebb, inst), dest);
|
||||
self.add_edge(BasicBlock::new(ebb, inst), dest);
|
||||
}
|
||||
}
|
||||
BranchInfo::NotABranch => {}
|
||||
@@ -148,12 +161,12 @@ impl ControlFlowGraph {
|
||||
}
|
||||
|
||||
fn add_edge(&mut self, from: BasicBlock, to: Ebb) {
|
||||
self.data[from.0]
|
||||
self.data[from.ebb]
|
||||
.successors
|
||||
.insert(to, &mut self.succ_forest, &());
|
||||
self.data[to]
|
||||
.predecessors
|
||||
.insert(from.1, from.0, &mut self.pred_forest, &());
|
||||
.insert(from.inst, from.ebb, &mut self.pred_forest, &());
|
||||
}
|
||||
|
||||
/// Get an iterator over the CFG predecessors to `ebb`.
|
||||
@@ -186,7 +199,7 @@ impl<'a> Iterator for PredIter<'a> {
|
||||
type Item = BasicBlock;
|
||||
|
||||
fn next(&mut self) -> Option<BasicBlock> {
|
||||
self.0.next().map(|(i, e)| (e, i))
|
||||
self.0.next().map(|(i, e)| BasicBlock::new(e, i))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,10 +281,22 @@ mod tests {
|
||||
assert_eq!(ebb1_predecessors.len(), 2);
|
||||
assert_eq!(ebb2_predecessors.len(), 2);
|
||||
|
||||
assert_eq!(ebb1_predecessors.contains(&(ebb0, jmp_ebb0_ebb1)), true);
|
||||
assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
|
||||
assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), true);
|
||||
assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);
|
||||
assert_eq!(
|
||||
ebb1_predecessors.contains(&BasicBlock::new(ebb0, jmp_ebb0_ebb1)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb1_predecessors.contains(&BasicBlock::new(ebb1, br_ebb1_ebb1)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb2_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb2)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb2_predecessors.contains(&BasicBlock::new(ebb1, jmp_ebb1_ebb2)),
|
||||
true
|
||||
);
|
||||
|
||||
assert_eq!(ebb0_successors, [ebb1, ebb2]);
|
||||
assert_eq!(ebb1_successors, [ebb1, ebb2]);
|
||||
@@ -297,10 +322,22 @@ mod tests {
|
||||
assert_eq!(ebb1_predecessors.len(), 2);
|
||||
assert_eq!(ebb2_predecessors.len(), 1);
|
||||
|
||||
assert_eq!(ebb1_predecessors.contains(&(ebb0, br_ebb0_ebb1)), true);
|
||||
assert_eq!(ebb1_predecessors.contains(&(ebb1, br_ebb1_ebb1)), true);
|
||||
assert_eq!(ebb2_predecessors.contains(&(ebb0, br_ebb0_ebb2)), false);
|
||||
assert_eq!(ebb2_predecessors.contains(&(ebb1, jmp_ebb1_ebb2)), true);
|
||||
assert_eq!(
|
||||
ebb1_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb1)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb1_predecessors.contains(&BasicBlock::new(ebb1, br_ebb1_ebb1)),
|
||||
true
|
||||
);
|
||||
assert_eq!(
|
||||
ebb2_predecessors.contains(&BasicBlock::new(ebb0, br_ebb0_ebb2)),
|
||||
false
|
||||
);
|
||||
assert_eq!(
|
||||
ebb2_predecessors.contains(&BasicBlock::new(ebb1, jmp_ebb1_ebb2)),
|
||||
true
|
||||
);
|
||||
|
||||
assert_eq!(ebb0_successors.collect::<Vec<_>>(), [ebb1]);
|
||||
assert_eq!(ebb1_successors.collect::<Vec<_>>(), [ebb1, ebb2]);
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
//! instructions. These loops will remain in the program.
|
||||
|
||||
use cursor::{Cursor, CursorPosition, FuncCursor};
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use ir::{self, Ebb, Inst, InstBuilder, InstructionData, Opcode, Type, Value, ValueDef};
|
||||
use std::iter;
|
||||
use std::vec::Vec;
|
||||
@@ -126,7 +126,7 @@ fn split_any(
|
||||
|
||||
// We have split the value requested, and now we may need to fix some EBB predecessors.
|
||||
while let Some(repair) = repairs.pop() {
|
||||
for (_, inst) in cfg.pred_iter(repair.ebb) {
|
||||
for BasicBlock { inst, .. } in cfg.pred_iter(repair.ebb) {
|
||||
let branch_opc = pos.func.dfg[inst].opcode();
|
||||
debug_assert!(
|
||||
branch_opc.is_branch(),
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
use cursor::{Cursor, FuncCursor};
|
||||
use dominator_tree::DominatorTree;
|
||||
use entity::{EntityList, ListPool};
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use fx::FxHashSet;
|
||||
use ir::{DataFlowGraph, Ebb, Function, Inst, InstBuilder, Layout, Opcode, Type, Value};
|
||||
use loop_analysis::{Loop, LoopAnalysis};
|
||||
@@ -77,7 +77,10 @@ fn create_pre_header(
|
||||
for typ in header_args_types {
|
||||
pre_header_args_value.push(func.dfg.append_ebb_param(pre_header, typ), pool);
|
||||
}
|
||||
for (_, last_inst) in cfg.pred_iter(header) {
|
||||
for BasicBlock {
|
||||
inst: last_inst, ..
|
||||
} in cfg.pred_iter(header)
|
||||
{
|
||||
// We only follow normal edges (not the back edges)
|
||||
if !domtree.dominates(header, last_inst, &func.layout) {
|
||||
change_branch_jump_destination(last_inst, pre_header, func);
|
||||
@@ -106,7 +109,11 @@ fn has_pre_header(
|
||||
) -> Option<(Ebb, Inst)> {
|
||||
let mut result = None;
|
||||
let mut found = false;
|
||||
for (pred_ebb, last_inst) in cfg.pred_iter(header) {
|
||||
for BasicBlock {
|
||||
ebb: pred_ebb,
|
||||
inst: last_inst,
|
||||
} in cfg.pred_iter(header)
|
||||
{
|
||||
// We only count normal edges (not the back edges)
|
||||
if !domtree.dominates(header, last_inst, layout) {
|
||||
if found {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use dominator_tree::DominatorTree;
|
||||
use entity::EntityMap;
|
||||
use entity::{Keys, PrimaryMap};
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use ir::{Ebb, Function, Layout};
|
||||
use packed_option::PackedOption;
|
||||
use std::vec::Vec;
|
||||
@@ -137,7 +137,10 @@ impl LoopAnalysis {
|
||||
) {
|
||||
// We traverse the CFG in reverse postorder
|
||||
for &ebb in domtree.cfg_postorder().iter().rev() {
|
||||
for (_, pred_inst) in cfg.pred_iter(ebb) {
|
||||
for BasicBlock {
|
||||
inst: pred_inst, ..
|
||||
} in cfg.pred_iter(ebb)
|
||||
{
|
||||
// If the ebb dominates one of its predecessors it is a back edge
|
||||
if domtree.dominates(ebb, pred_inst, layout) {
|
||||
// This ebb is a loop header, so we create its associated loop
|
||||
@@ -163,7 +166,11 @@ impl LoopAnalysis {
|
||||
// We handle each loop header in reverse order, corresponding to a pseudo postorder
|
||||
// traversal of the graph.
|
||||
for lp in self.loops().rev() {
|
||||
for (pred, pred_inst) in cfg.pred_iter(self.loops[lp].header) {
|
||||
for BasicBlock {
|
||||
ebb: pred,
|
||||
inst: pred_inst,
|
||||
} in cfg.pred_iter(self.loops[lp].header)
|
||||
{
|
||||
// We follow the back edges
|
||||
if domtree.dominates(self.loops[lp].header, pred_inst, layout) {
|
||||
stack.push(pred);
|
||||
@@ -213,7 +220,7 @@ impl LoopAnalysis {
|
||||
// Now we have handled the popped node and need to continue the DFS by adding the
|
||||
// predecessors of that node
|
||||
if let Some(continue_dfs) = continue_dfs {
|
||||
for (pred, _) in cfg.pred_iter(continue_dfs) {
|
||||
for BasicBlock { ebb: pred, .. } in cfg.pred_iter(continue_dfs) {
|
||||
stack.push(pred)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -9,7 +9,7 @@ use cursor::{Cursor, EncCursor};
|
||||
#[cfg(feature = "std")]
|
||||
use dbg::DisplayList;
|
||||
use dominator_tree::{DominatorTree, DominatorTreePreorder};
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use fx::FxHashMap;
|
||||
use ir::{self, InstBuilder, ProgramOrder};
|
||||
use ir::{Ebb, ExpandedProgramPoint, Function, Inst, Value};
|
||||
@@ -174,7 +174,11 @@ impl<'a> Context<'a> {
|
||||
debug_assert_eq!(num_params, self.func.dfg.num_ebb_params(ebb));
|
||||
// The only way a parameter value can interfere with a predecessor branch is if the EBB is
|
||||
// dominating the predecessor branch. That is, we are looking for loop back-edges.
|
||||
for (pred_ebb, pred_inst) in self.cfg.pred_iter(ebb) {
|
||||
for BasicBlock {
|
||||
ebb: pred_ebb,
|
||||
inst: pred_inst,
|
||||
} in self.cfg.pred_iter(ebb)
|
||||
{
|
||||
// The quick pre-order dominance check is accurate because the EBB parameter is defined
|
||||
// at the top of the EBB before any branches.
|
||||
if !self.preorder.dominates(ebb, pred_ebb) {
|
||||
@@ -211,7 +215,11 @@ impl<'a> Context<'a> {
|
||||
fn union_pred_args(&mut self, ebb: Ebb, argnum: usize) {
|
||||
let param = self.func.dfg.ebb_params(ebb)[argnum];
|
||||
|
||||
for (pred_ebb, pred_inst) in self.cfg.pred_iter(ebb) {
|
||||
for BasicBlock {
|
||||
ebb: pred_ebb,
|
||||
inst: pred_inst,
|
||||
} in self.cfg.pred_iter(ebb)
|
||||
{
|
||||
let arg = self.func.dfg.inst_variable_args(pred_inst)[argnum];
|
||||
|
||||
// Never coalesce incoming function parameters on the stack. These parameters are
|
||||
@@ -484,7 +492,11 @@ impl<'a> Context<'a> {
|
||||
// not loop backedges.
|
||||
debug_assert!(self.predecessors.is_empty());
|
||||
debug_assert!(self.backedges.is_empty());
|
||||
for (pred_ebb, pred_inst) in self.cfg.pred_iter(ebb) {
|
||||
for BasicBlock {
|
||||
ebb: pred_ebb,
|
||||
inst: pred_inst,
|
||||
} in self.cfg.pred_iter(ebb)
|
||||
{
|
||||
if self.preorder.dominates(ebb, pred_ebb) {
|
||||
self.backedges.push(pred_inst);
|
||||
} else {
|
||||
@@ -915,7 +927,10 @@ impl VirtualCopies {
|
||||
}
|
||||
|
||||
// This EBB hasn't been seen before.
|
||||
for (_, pred_inst) in cfg.pred_iter(ebb) {
|
||||
for BasicBlock {
|
||||
inst: pred_inst, ..
|
||||
} in cfg.pred_iter(ebb)
|
||||
{
|
||||
self.branches.push((pred_inst, ebb));
|
||||
}
|
||||
last_ebb = Some(ebb);
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
//! There is some room for improvement.
|
||||
|
||||
use entity::SparseMap;
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use ir::dfg::ValueDef;
|
||||
use ir::{Ebb, Function, Inst, Layout, ProgramPoint, Value};
|
||||
use isa::{EncInfo, OperandConstraint, TargetIsa};
|
||||
@@ -272,7 +272,11 @@ fn extend_to_use(
|
||||
while let Some(livein) = worklist.pop() {
|
||||
// We've learned that the value needs to be live-in to the `livein` EBB.
|
||||
// Make sure it is also live at all predecessor branches to `livein`.
|
||||
for (pred, branch) in cfg.pred_iter(livein) {
|
||||
for BasicBlock {
|
||||
ebb: pred,
|
||||
inst: branch,
|
||||
} in cfg.pred_iter(livein)
|
||||
{
|
||||
if lr.extend_in_ebb(pred, branch, &func.layout, forest) {
|
||||
// This predecessor EBB also became live-in. We need to process it later.
|
||||
worklist.push(pred);
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
use dbg::DisplayList;
|
||||
use dominator_tree::{DominatorTree, DominatorTreePreorder};
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use ir::{ExpandedProgramPoint, Function};
|
||||
use regalloc::liveness::Liveness;
|
||||
use regalloc::virtregs::VirtRegs;
|
||||
@@ -138,7 +138,7 @@ impl<'a> CssaVerifier<'a> {
|
||||
fn check_cssa(&self) -> VerifierResult<()> {
|
||||
for ebb in self.func.layout.ebbs() {
|
||||
let ebb_params = self.func.dfg.ebb_params(ebb);
|
||||
for (_, pred) in self.cfg.pred_iter(ebb) {
|
||||
for BasicBlock { inst: pred, .. } in self.cfg.pred_iter(ebb) {
|
||||
let pred_args = self.func.dfg.inst_variable_args(pred);
|
||||
// This should have been caught by an earlier verifier pass.
|
||||
assert_eq!(
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//! Verify CPU flags values.
|
||||
|
||||
use entity::{EntityMap, SparseSet};
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use ir;
|
||||
use ir::instructions::BranchInfo;
|
||||
use isa;
|
||||
@@ -61,7 +61,7 @@ impl<'a> FlagsVerifier<'a> {
|
||||
// Revisit any predecessor blocks the first time we see a live-in for `ebb`.
|
||||
None => {
|
||||
self.livein[ebb] = value.into();
|
||||
for (pred, _) in self.cfg.pred_iter(ebb) {
|
||||
for BasicBlock { ebb: pred, .. } in self.cfg.pred_iter(ebb) {
|
||||
worklist.insert(pred);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//! Liveness verifier.
|
||||
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use ir::entities::AnyEntity;
|
||||
use ir::{ExpandedProgramPoint, Function, Inst, ProgramOrder, ProgramPoint, Value};
|
||||
use isa::TargetIsa;
|
||||
@@ -194,7 +194,7 @@ impl<'a> LivenessVerifier<'a> {
|
||||
// Check all the EBBs in the interval independently.
|
||||
loop {
|
||||
// If `val` is live-in at `ebb`, it must be live at all the predecessors.
|
||||
for (_, pred) in self.cfg.pred_iter(ebb) {
|
||||
for BasicBlock { inst: pred, .. } in self.cfg.pred_iter(ebb) {
|
||||
if !self.live_at_use(lr, pred) {
|
||||
return err!(
|
||||
pred,
|
||||
|
||||
@@ -60,7 +60,7 @@ use self::flags::verify_flags;
|
||||
use dbg::DisplayList;
|
||||
use dominator_tree::DominatorTree;
|
||||
use entity::SparseSet;
|
||||
use flowgraph::ControlFlowGraph;
|
||||
use flowgraph::{BasicBlock, ControlFlowGraph};
|
||||
use ir;
|
||||
use ir::entities::AnyEntity;
|
||||
use ir::instructions::{BranchInfo, CallInfo, InstructionFormat, ResolvedConstraint};
|
||||
@@ -990,8 +990,12 @@ impl<'a> Verifier<'a> {
|
||||
return err!(ebb, "cfg had unexpected successor(s) {:?}", excess_succs);
|
||||
}
|
||||
|
||||
expected_preds.extend(self.expected_cfg.pred_iter(ebb).map(|(_, inst)| inst));
|
||||
got_preds.extend(cfg.pred_iter(ebb).map(|(_, inst)| inst));
|
||||
expected_preds.extend(
|
||||
self.expected_cfg
|
||||
.pred_iter(ebb)
|
||||
.map(|BasicBlock { inst, .. }| inst),
|
||||
);
|
||||
got_preds.extend(cfg.pred_iter(ebb).map(|BasicBlock { inst, .. }| inst));
|
||||
|
||||
let missing_preds: Vec<Inst> = expected_preds.difference(&got_preds).cloned().collect();
|
||||
if !missing_preds.is_empty() {
|
||||
|
||||
Reference in New Issue
Block a user