Dominator analysis interface clean.

Remove the CFG requirement when querying a dominator/post-dominator from an IRContext.

Updated all uses of the function and tests.
This commit is contained in:
Victor Lomuller 2018-04-20 17:28:40 +01:00 committed by Diego Novillo
parent 48802bad72
commit efc5061929
26 changed files with 65 additions and 100 deletions

View File

@ -166,7 +166,7 @@ bool CopyPropagateArrays::HasValidReferencesOnly(ir::Instruction* ptr_inst,
ir::Instruction* store_inst) {
ir::BasicBlock* store_block = context()->get_instr_block(store_inst);
opt::DominatorAnalysis* dominator_analysis =
context()->GetDominatorAnalysis(store_block->GetParent(), *cfg());
context()->GetDominatorAnalysis(store_block->GetParent());
return get_def_use_mgr()->WhileEachUser(
ptr_inst,

View File

@ -30,9 +30,7 @@ class DominatorAnalysisBase {
explicit DominatorAnalysisBase(bool is_post_dom) : tree_(is_post_dom) {}
// Calculates the dominator (or postdominator) tree for given function |f|.
inline void InitializeTree(const ir::Function* f, const ir::CFG& cfg) {
tree_.InitializeTree(f, cfg);
}
inline void InitializeTree(const ir::Function* f) { tree_.InitializeTree(f); }
// Returns true if BasicBlock |a| dominates BasicBlock |b|.
inline bool Dominates(const ir::BasicBlock* a,

View File

@ -18,6 +18,7 @@
#include "cfa.h"
#include "dominator_tree.h"
#include "ir_context.h"
using namespace spvtools;
using namespace spvtools::opt;
@ -324,13 +325,14 @@ void DominatorTree::GetDominatorEdges(
CFA<ir::BasicBlock>::CalculateDominators(postorder, predecessor_functor);
}
void DominatorTree::InitializeTree(const ir::Function* f, const ir::CFG& cfg) {
void DominatorTree::InitializeTree(const ir::Function* f) {
ClearTree();
// Skip over empty functions.
if (f->cbegin() == f->cend()) {
return;
}
const ir::CFG& cfg = *f->context()->cfg();
const ir::BasicBlock* dummy_start_node =
postdominator_ ? cfg.pseudo_exit_block() : cfg.pseudo_entry_block();

View File

@ -158,7 +158,7 @@ class DominatorTree {
// Build the (post-)dominator tree for the function |f|
// Any existing data will be overwritten
void InitializeTree(const ir::Function* f, const ir::CFG& cfg);
void InitializeTree(const ir::Function* f);
// Check if the basic block |a| dominates the basic block |b|.
bool Dominates(const ir::BasicBlock* a, const ir::BasicBlock* b) const;

View File

@ -23,8 +23,7 @@ Pass::Status IfConversion::Process(ir::IRContext* c) {
bool modified = false;
std::vector<ir::Instruction*> to_kill;
for (auto& func : *get_module()) {
DominatorAnalysis* dominators =
context()->GetDominatorAnalysis(&func, *cfg());
DominatorAnalysis* dominators = context()->GetDominatorAnalysis(&func);
for (auto& block : func) {
// Check if it is possible for |block| to have phis that can be
// transformed.

View File

@ -564,14 +564,13 @@ ir::LoopDescriptor* IRContext::GetLoopDescriptor(const ir::Function* f) {
}
// Gets the dominator analysis for function |f|.
opt::DominatorAnalysis* IRContext::GetDominatorAnalysis(const ir::Function* f,
const ir::CFG& in_cfg) {
opt::DominatorAnalysis* IRContext::GetDominatorAnalysis(const ir::Function* f) {
if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
ResetDominatorAnalysis();
}
if (dominator_trees_.find(f) == dominator_trees_.end()) {
dominator_trees_[f].InitializeTree(f, in_cfg);
dominator_trees_[f].InitializeTree(f);
}
return &dominator_trees_[f];
@ -579,13 +578,13 @@ opt::DominatorAnalysis* IRContext::GetDominatorAnalysis(const ir::Function* f,
// Gets the postdominator analysis for function |f|.
opt::PostDominatorAnalysis* IRContext::GetPostDominatorAnalysis(
const ir::Function* f, const ir::CFG& in_cfg) {
const ir::Function* f) {
if (!AreAnalysesValid(kAnalysisDominatorAnalysis)) {
ResetDominatorAnalysis();
}
if (post_dominator_trees_.find(f) == post_dominator_trees_.end()) {
post_dominator_trees_[f].InitializeTree(f, in_cfg);
post_dominator_trees_[f].InitializeTree(f);
}
return &post_dominator_trees_[f];

View File

@ -402,22 +402,10 @@ class IRContext {
ir::LoopDescriptor* GetLoopDescriptor(const ir::Function* f);
// Gets the dominator analysis for function |f|.
opt::DominatorAnalysis* GetDominatorAnalysis(const ir::Function* f,
const ir::CFG&);
// Gets the dominator analysis for function |f|.
opt::DominatorAnalysis* GetDominatorAnalysis(const ir::Function* f) {
return GetDominatorAnalysis(f, *cfg());
}
opt::DominatorAnalysis* GetDominatorAnalysis(const ir::Function* f);
// Gets the postdominator analysis for function |f|.
opt::PostDominatorAnalysis* GetPostDominatorAnalysis(const ir::Function* f,
const ir::CFG&);
// Gets the postdominator analysis for function |f|.
opt::PostDominatorAnalysis* GetPostDominatorAnalysis(const ir::Function* f) {
return GetPostDominatorAnalysis(f, *cfg());
}
opt::PostDominatorAnalysis* GetPostDominatorAnalysis(const ir::Function* f);
// Remove the dominator tree of |f| from the cache.
inline void RemoveDominatorAnalysis(const ir::Function* f) {

View File

@ -95,8 +95,7 @@ bool LICMPass::AnalyseAndHoistFromBB(ir::Loop* loop, ir::Function* f,
bb->ForEachInst(hoist_inst, false);
}
opt::DominatorAnalysis* dom_analysis =
context()->GetDominatorAnalysis(f, *cfg());
opt::DominatorAnalysis* dom_analysis = context()->GetDominatorAnalysis(f);
opt::DominatorTree& dom_tree = dom_analysis->GetDomTree();
for (opt::DominatorTreeNode* child_dom_tree_node :

View File

@ -219,7 +219,7 @@ bool LocalSingleStoreElimPass::RewriteLoads(
ir::Instruction* store_inst, const std::vector<ir::Instruction*>& uses) {
ir::BasicBlock* store_block = context()->get_instr_block(store_inst);
opt::DominatorAnalysis* dominator_analysis =
context()->GetDominatorAnalysis(store_block->GetParent(), *cfg());
context()->GetDominatorAnalysis(store_block->GetParent());
uint32_t stored_id;
if (store_inst->opcode() == SpvOpStore)

View File

@ -264,7 +264,7 @@ bool Loop::IsInsideLoop(Instruction* inst) const {
bool Loop::IsBasicBlockInLoopSlow(const BasicBlock* bb) {
assert(bb->GetParent() && "The basic block does not belong to a function");
opt::DominatorAnalysis* dom_analysis =
context_->GetDominatorAnalysis(bb->GetParent(), *context_->cfg());
context_->GetDominatorAnalysis(bb->GetParent());
if (dom_analysis->IsReachable(bb) &&
!dom_analysis->Dominates(GetHeaderBlock(), bb))
return false;
@ -472,8 +472,7 @@ LoopDescriptor::~LoopDescriptor() { ClearLoops(); }
void LoopDescriptor::PopulateList(const Function* f) {
IRContext* context = f->GetParent()->context();
opt::DominatorAnalysis* dom_analysis =
context->GetDominatorAnalysis(f, *context->cfg());
opt::DominatorAnalysis* dom_analysis = context->GetDominatorAnalysis(f);
ClearLoops();

View File

@ -282,7 +282,7 @@ void LoopPeeling::GetIteratingExitValues() {
});
} else {
DominatorTree* dom_tree =
&context_->GetDominatorAnalysis(loop_utils_.GetFunction(), cfg)
&context_->GetDominatorAnalysis(loop_utils_.GetFunction())
->GetDomTree();
ir::BasicBlock* condition_block = cfg.block(condition_block_id);

View File

@ -118,8 +118,7 @@ class LoopUnswitch {
ir::CFG& cfg = *context_->cfg();
DominatorTree* dom_tree =
&context_->GetDominatorAnalysis(function_, *context_->cfg())
->GetDomTree();
&context_->GetDominatorAnalysis(function_)->GetDomTree();
analysis::DefUseManager* def_use_mgr = context_->get_def_use_mgr();
LoopUtils loop_utils(context_, loop_);
@ -849,8 +848,7 @@ class LoopUnswitch {
return !loop_->IsInsideLoop(condition) &&
IsDynamicallyUniform(
condition, function_->entry().get(),
context_->GetPostDominatorAnalysis(function_, *context_->cfg())
->GetDomTree());
context_->GetPostDominatorAnalysis(function_)->GetDomTree());
}
};

View File

@ -280,7 +280,7 @@ inline void MakeSetClosedSSA(ir::IRContext* context, ir::Function* function,
LCSSARewriter* lcssa_rewriter) {
ir::CFG& cfg = *context->cfg();
opt::DominatorTree& dom_tree =
context->GetDominatorAnalysis(function, cfg)->GetDomTree();
context->GetDominatorAnalysis(function)->GetDomTree();
opt::analysis::DefUseManager* def_use_manager = context->get_def_use_mgr();
for (uint32_t bb_id : blocks) {
@ -444,7 +444,7 @@ void LoopUtils::MakeLoopClosedSSA() {
ir::Function* function = loop_->GetHeaderBlock()->GetParent();
ir::CFG& cfg = *context_->cfg();
opt::DominatorTree& dom_tree =
context_->GetDominatorAnalysis(function, cfg)->GetDomTree();
context_->GetDominatorAnalysis(function)->GetDomTree();
std::unordered_set<ir::BasicBlock*> exit_bb;
{

View File

@ -193,7 +193,7 @@ void MergeReturnPass::CreatePhiNodesForInst(ir::BasicBlock* merge_block,
uint32_t predecessor,
ir::Instruction& inst) {
opt::DominatorAnalysis* dom_tree =
context()->GetDominatorAnalysis(merge_block->GetParent(), *cfg());
context()->GetDominatorAnalysis(merge_block->GetParent());
ir::BasicBlock* inst_bb = context()->get_instr_block(&inst);
if (inst.result_id() != 0) {
@ -625,8 +625,7 @@ void MergeReturnPass::MergeReturnBlocks(
}
void MergeReturnPass::AddNewPhiNodes() {
opt::DominatorAnalysis* dom_tree =
context()->GetDominatorAnalysis(function_, *cfg());
opt::DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function_);
std::list<ir::BasicBlock*> order;
cfg()->ComputeStructuredOrder(function_, &*function_->begin(), &order);
@ -638,8 +637,7 @@ void MergeReturnPass::AddNewPhiNodes() {
void MergeReturnPass::AddNewPhiNodes(ir::BasicBlock* bb, ir::BasicBlock* pred,
uint32_t header_id) {
opt::DominatorAnalysis* dom_tree =
context()->GetDominatorAnalysis(function_, *cfg());
opt::DominatorAnalysis* dom_tree = context()->GetDominatorAnalysis(function_);
// Insert as a stopping point. We do not have to add anything in the block or
// above because the header dominates |bb|.

View File

@ -29,7 +29,7 @@ Pass::Status RedundancyEliminationPass::Process(ir::IRContext* c) {
// Build the dominator tree for this function. It is how the code is
// traversed.
opt::DominatorTree& dom_tree =
context()->GetDominatorAnalysis(&func, *context()->cfg())->GetDomTree();
context()->GetDominatorAnalysis(&func)->GetDomTree();
// Keeps track of all ids that contain a given value number. We keep
// track of multiple values because they could have the same value, but

View File

@ -69,9 +69,8 @@ TEST(CommonDominatorsTest, SameBlock) {
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
EXPECT_NE(nullptr, context);
ir::CFG cfg(context->module());
opt::DominatorAnalysis* analysis =
context->GetDominatorAnalysis(&*context->module()->begin(), cfg);
context->GetDominatorAnalysis(&*context->module()->begin());
for (auto& block : *context->module()->begin()) {
EXPECT_EQ(&block, analysis->CommonDominator(&block, &block));
@ -84,9 +83,8 @@ TEST(CommonDominatorsTest, ParentAndChild) {
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
EXPECT_NE(nullptr, context);
ir::CFG cfg(context->module());
opt::DominatorAnalysis* analysis =
context->GetDominatorAnalysis(&*context->module()->begin(), cfg);
context->GetDominatorAnalysis(&*context->module()->begin());
EXPECT_EQ(
GetBlock(1u, context),
@ -105,9 +103,8 @@ TEST(CommonDominatorsTest, BranchSplit) {
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
EXPECT_NE(nullptr, context);
ir::CFG cfg(context->module());
opt::DominatorAnalysis* analysis =
context->GetDominatorAnalysis(&*context->module()->begin(), cfg);
context->GetDominatorAnalysis(&*context->module()->begin());
EXPECT_EQ(
GetBlock(3u, context),
@ -123,9 +120,8 @@ TEST(CommonDominatorsTest, LoopContinueAndMerge) {
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
EXPECT_NE(nullptr, context);
ir::CFG cfg(context->module());
opt::DominatorAnalysis* analysis =
context->GetDominatorAnalysis(&*context->module()->begin(), cfg);
context->GetDominatorAnalysis(&*context->module()->begin());
EXPECT_EQ(
GetBlock(5u, context),
@ -138,9 +134,8 @@ TEST(CommonDominatorsTest, NoCommonDominator) {
SPV_TEXT_TO_BINARY_OPTION_PRESERVE_NUMERIC_IDS);
EXPECT_NE(nullptr, context);
ir::CFG cfg(context->module());
opt::DominatorAnalysis* analysis =
context->GetDominatorAnalysis(&*context->module()->begin(), cfg);
context->GetDominatorAnalysis(&*context->module()->begin());
EXPECT_EQ(nullptr, analysis->CommonDominator(GetBlock(10u, context),
GetBlock(11u, context)));

View File

@ -122,8 +122,8 @@ TEST_F(PassClassTest, DominatorSimpleCFG) {
// Test normal dominator tree
{
opt::DominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -187,8 +187,8 @@ TEST_F(PassClassTest, DominatorSimpleCFG) {
// Test post dominator tree
{
opt::PostDominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -289,8 +289,8 @@ TEST_F(PassClassTest, DominatorIrreducibleCFG) {
// Check normal dominator tree
{
opt::DominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -331,8 +331,8 @@ TEST_F(PassClassTest, DominatorIrreducibleCFG) {
// Check post dominator tree
{
opt::PostDominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -410,8 +410,8 @@ TEST_F(PassClassTest, DominatorLoopToSelf) {
// Check normal dominator tree
{
opt::DominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -492,8 +492,8 @@ TEST_F(PassClassTest, DominatorLoopToSelf) {
// Check post dominator tree
{
opt::PostDominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -617,8 +617,8 @@ TEST_F(PassClassTest, DominatorUnreachableInLoop) {
// Check normal dominator tree
{
opt::DominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -668,8 +668,8 @@ TEST_F(PassClassTest, DominatorUnreachableInLoop) {
// Check post dominator tree.
{
opt::PostDominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// (strict) dominance checks.
for (uint32_t id : {10, 11, 12, 13, 14, 15})
@ -747,8 +747,8 @@ TEST_F(PassClassTest, DominatorInfinitLoop) {
// Check normal dominator tree
{
opt::DominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -782,8 +782,8 @@ TEST_F(PassClassTest, DominatorInfinitLoop) {
// Check post dominator tree
{
opt::PostDominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
@ -852,8 +852,8 @@ TEST_F(PassClassTest, DominatorUnreachableFromEntry) {
// Check dominator tree
{
opt::DominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();
EXPECT_EQ(tree.GetRoot()->bb_, cfg.pseudo_entry_block());
@ -880,8 +880,8 @@ TEST_F(PassClassTest, DominatorUnreachableFromEntry) {
// Check post dominator tree
{
opt::PostDominatorAnalysis dom_tree;
ir::CFG cfg(module);
dom_tree.InitializeTree(fn, cfg);
dom_tree.InitializeTree(fn);
const ir::CFG& cfg = *context->cfg();
// Inspect the actual tree
opt::DominatorTree& tree = dom_tree.GetDomTree();

View File

@ -119,8 +119,7 @@ TEST_F(PassClassTest, UnreachableNestedIfs) {
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f, cfg);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f);
EXPECT_TRUE(analysis->Dominates(5, 8));
EXPECT_TRUE(analysis->Dominates(5, 9));

View File

@ -119,9 +119,7 @@ TEST_F(PassClassTest, UnreachableNestedIfs) {
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::PostDominatorAnalysis* analysis =
context->GetPostDominatorAnalysis(f, cfg);
opt::PostDominatorAnalysis* analysis = context->GetPostDominatorAnalysis(f);
EXPECT_TRUE(analysis->Dominates(5, 5));
EXPECT_TRUE(analysis->Dominates(8, 8));

View File

@ -359,8 +359,7 @@ TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f, cfg);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f);
EXPECT_TRUE(analysis->Dominates(5, 10));
EXPECT_TRUE(analysis->Dominates(5, 46));

View File

@ -287,8 +287,7 @@ TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f, cfg);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f);
EXPECT_TRUE(analysis->Dominates(5, 10));
EXPECT_TRUE(analysis->Dominates(5, 14));

View File

@ -148,8 +148,7 @@ TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::PostDominatorAnalysis* analysis =
context->GetPostDominatorAnalysis(f, cfg);
opt::PostDominatorAnalysis* analysis = context->GetPostDominatorAnalysis(f);
EXPECT_TRUE(analysis->Dominates(19, 18));
EXPECT_TRUE(analysis->Dominates(19, 5));

View File

@ -147,8 +147,8 @@ TEST_F(PassClassTest, BasicVisitFromEntryPoint) {
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f, cfg);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f);
const ir::CFG& cfg = *context->cfg();
opt::DominatorTree& tree = analysis->GetDomTree();

View File

@ -138,8 +138,7 @@ TEST_F(PassClassTest, UnreachableNestedIfs) {
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f, cfg);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f);
EXPECT_TRUE(analysis->Dominates(5, 5));
EXPECT_TRUE(analysis->Dominates(5, 17));

View File

@ -89,8 +89,7 @@ TEST_F(PassClassTest, UnreachableNestedIfs) {
<< text << std::endl;
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f, cfg);
opt::DominatorAnalysis* analysis = context->GetDominatorAnalysis(f);
EXPECT_TRUE(analysis->Dominates(5, 5));
EXPECT_TRUE(analysis->Dominates(5, 10));
EXPECT_TRUE(analysis->Dominates(5, 14));

View File

@ -90,9 +90,7 @@ TEST_F(PassClassTest, UnreachableNestedIfs) {
const ir::Function* f = spvtest::GetFunction(module, 4);
ir::CFG cfg(module);
opt::PostDominatorAnalysis* analysis =
context->GetPostDominatorAnalysis(f, cfg);
opt::PostDominatorAnalysis* analysis = context->GetPostDominatorAnalysis(f);
EXPECT_TRUE(analysis->Dominates(12, 12));
EXPECT_TRUE(analysis->Dominates(12, 14));