Path: blob/main/cranelift/filetests/src/test_domtree.rs
3068 views
//! Test command for verifying dominator trees.1//!2//! The `test domtree` test command looks for annotations on instructions like this:3//!4//! ```clif5//! jump block3 ; dominates: block36//! ```7//!8//! This annotation means that the jump instruction is expected to be the immediate dominator of9//! `block3`.10//!11//! We verify that the dominator tree annotations are complete and correct.12//!1314use crate::match_directive::match_directive;15use crate::subtest::{Context, SubTest, run_filecheck};16use cranelift_codegen::dominator_tree::DominatorTree;17use cranelift_codegen::flowgraph::ControlFlowGraph;18use cranelift_codegen::ir::Function;19use cranelift_codegen::ir::entities::AnyEntity;20use cranelift_reader::TestCommand;21use std::borrow::{Borrow, Cow};22use std::collections::HashMap;23use std::fmt::{self, Write};2425struct TestDomtree;2627pub fn subtest(parsed: &TestCommand) -> anyhow::Result<Box<dyn SubTest>> {28assert_eq!(parsed.command, "domtree");29if !parsed.options.is_empty() {30anyhow::bail!("No options allowed on {parsed}")31}32Ok(Box::new(TestDomtree))33}3435impl SubTest for TestDomtree {36fn name(&self) -> &'static str {37"domtree"38}3940// Extract our own dominator tree from41fn run(&self, func: Cow<Function>, context: &Context) -> anyhow::Result<()> {42let func = func.borrow();43let cfg = ControlFlowGraph::with_function(func);44let domtree = DominatorTree::with_function(func, &cfg);4546// Build an expected domtree from the source annotations.47let mut expected = HashMap::new();48for comment in &context.details.comments {49if let Some(tail) = match_directive(comment.text, "dominates:") {50let inst = match comment.entity {51AnyEntity::Inst(inst) => inst,52_ => {53anyhow::bail!(54"annotation on non-inst {}: {}",55comment.entity,56comment.text57);58}59};6061let expected_block = match func.layout.inst_block(inst) {62Some(expected_block) => expected_block,63_ => anyhow::bail!("instruction {inst} is not in layout"),64};65for src_block in tail.split_whitespace() {66let block = match context.details.map.lookup_str(src_block) {67Some(AnyEntity::Block(block)) => block,68_ => anyhow::bail!("expected defined block, got {src_block}"),69};7071// Annotations say that `expected_block` is the idom of `block`.72if expected.insert(block, expected_block).is_some() {73anyhow::bail!("multiple dominators for {src_block}");74}7576// Compare to computed domtree.77match domtree.idom(block) {78Some(got_block) if got_block != expected_block => {79anyhow::bail!(80"mismatching idoms for {src_block}:\n\81want: {inst}, got: {got_block}"82);83}84None => {85anyhow::bail!(86"mismatching idoms for {src_block}:\n\87want: {inst}, got: unreachable"88);89}90_ => {}91}92}93}94}9596// Now we know that everything in `expected` is consistent with `domtree`.97// All other block's should be either unreachable or the entry block.98for block in func99.layout100.blocks()101.skip(1)102.filter(|block| !expected.contains_key(block))103{104if let Some(got_block) = domtree.idom(block) {105anyhow::bail!(106"mismatching idoms for renumbered {block}:\n\107want: unreachable, got: {got_block}"108);109}110}111112let text = filecheck_text(func, &domtree).expect("formatting error");113run_filecheck(&text, context)114}115}116117// Generate some output for filecheck testing118fn filecheck_text(func: &Function, domtree: &DominatorTree) -> Result<String, fmt::Error> {119let mut s = String::new();120121write!(s, "cfg_postorder:")?;122for &block in domtree.cfg_postorder() {123write!(s, " {block}")?;124}125writeln!(s)?;126127// Compute and print out a pre-order of the dominator tree.128writeln!(s, "domtree_preorder {{")?;129let mut stack = Vec::new();130stack.extend(func.layout.entry_block());131while let Some(block) = stack.pop() {132write!(s, " {block}:")?;133let i = stack.len();134for ch in domtree.children(block) {135write!(s, " {ch}")?;136stack.push(ch);137}138writeln!(s)?;139// Reverse the children we just pushed so we'll pop them in order.140stack[i..].reverse();141}142writeln!(s, "}}")?;143144Ok(s)145}146147148