# 支配树（Dominator Tree）

The Φ-function is the most important SSA concept to grasp. It is a special statement, known as a pseudo-assignment function.
The purpose of a Φ-function is to merge from different incoming paths, at control-flow merge points.

It can determine, for each block i, the set of blocks that will need a Φ-function for any definition in block i. Dominance plays a critical role in this computation.

## Dominance

d dom i if all paths from entry to node i include d.

### Dominator Tree

The dominator relationship forms a tree.
Edge from parent to child = parent dominates child.
Note: edges are not same as CFG edges!

### Dominance Frontier

Y is in the dominance frontier of X iff “there exists a path from X to Exit through Y such that Y is the first node not strictly dominated by X

In SSA form, definitions must dominate uses.

Dominance frontier capture the precise places at which we need Φ-function: if the node A defines a certain variable, then that definition and that definition alone(or redefinitions) will reach every node A dominates.

Only when leave these nodes and enter the diminance frontier must we account for other flows bringing in other definitions of the same variable.

## 计算支配树

《Engineering a Compiler》第9章开篇就是介绍的支配性信息的迭代数据流计算方法，将支配问题看作前向数据流分析，数据流方程如下图（盗图）所示：

## A Simple, Fast Dominance Algorithm

• 该方法并没有将每个结点的支配结点定义为全集。对于 entry 结点定义 entry，对于其他结点定义为空（undefined）。
• 该方法并不直接计算结点 n 的支配集合Dom(n)。而是计算结点 n 的直接支配结点 IDom(n)

Keith D.Cooper 就是基于这个思想提出了一种快速计算 dominance 信息的算法 《A Simple, Fast Dominance Algorithm》。该算法简单易懂，效果也不错，算法伪代码如下所示：

## 计算支配边界（dominance frontier）

Cooper在这篇论文中也提出了一种改进的计算支配边界的方法（改进很小），该算法如下所示：

## 实现代码

class DomTreeNode
{
public:
enum class color {WHITE, GRAY, BLACK};
private:
BBPtr TheBB;
int PostNumber;
int DFSInNum, DFSOutNum;
color VisitColor;
DomTreeNodePtr IDom;

std::vector<DomTreeNodePtr> Children;
// Express the predecessor when we depth-first searching of
// the CFG.
// e.g.
//     B1        B2
//      \        /
//       \      /
//          B3
// B1 and B2 both the father of B3, but we only can via one
// node reach B3 when the depth-first searching.
DomTreeNodePtr Father;
public:
DomTreeNode(BBPtr BB = nullptr) :
TheBB(BB), IDom(nullptr), DFSInNum(-1), DFSOutNum(-1),
PostNumber(-1), Father(nullptr) {}

BBPtr getBlock() const { return TheBB; }
DomTreeNodePtr getIDom() const { return IDom; }

const std::vector<DomTreeNodePtr>& getChildren() const
{
return Children;
}

{
Children.push_back(Child);
return Child;
}

std::vector<DomTreeNodePtr> Predecessors;
unsigned getDFSNumIn() const { return DFSInNum; }
unsigned getDFSNumOut() const { return DFSOutNum; }
unsigned getPostOrder() const { return PostNumber; }
bool DominatedBy(DomTreeNodePtr other) const
{
return this->DFSInNum >= other->DFSInNum &&
this->DFSOutNum <= other->DFSOutNum;
}

void setDFSInNum(int InNum) { DFSInNum = InNum; }
void setDFSOutNum(int OutNum) { DFSOutNum = OutNum; }
void setPostNumber(int PostOrder) { PostNumber = PostOrder; }
void setVisitColor(color c) { VisitColor = c; }
void setDFSFather(DomTreeNodePtr DFSFather) { Father = DFSFather; }

color getVisitColor() const { return VisitColor; }
size_t getNumChildren() const { return Children.size(); }
void clearAllChildren() { Children.clear(); }

void setIDom(DomTreeNodePtr NewIDom)
{
IDom = NewIDom;
}
};

//===------------------------------------------------------------===//
// A dominator tree is a tree where each node's children are those
// nodes it immediately dominates.
// Because the immediate dominator is unique, it is a tree. The start
// node is the root of the tree.

// DominatorTree - This represents the forward Dominance.
class DominatorTree
{
using DomTreeNodeMapType = std::map<BBPtr, DomTreeNodePtr>;
DomTreeNodeMapType DomTreeNodes;
DomTreeNodePtr RootNode;

std::vector<DomTreeNodePtr> PostOrder;
std::vector<DomTreeNodePtr> ReversePostOrder;
std::list<BBPtr> Vertex;

std::map<DomTreeNodePtr, std::vector<DomTreeNodePtr>> PredecessorrsOfCFG;

// DominanceFrontier - Represent the forward Dominance Frontier.
std::map<DomTreeNodePtr, std::set<DomTreeNodePtr>> DominanceFrontier;
// JoinPoints - Represent the join point(have more than two predecessors)
// of CFG.
std::vector<DomTreeNodePtr> JoinNodes;
private:
void getPostOrder();
void getReversePostOrder();

// compute the DomTree.
void computeDomTree(BBPtr EntryBlock);
// 获取当前DomNode在CFG中前驱对应的DomTreeNode.
std::vector<DomTreeNodePtr> getDomNodePredsFromCFG(DomTreeNodePtr Node);
// Intersect() - This function only be using to get closest parent of A and B.
DomTreeNodePtr Intersect(DomTreeNodePtr A, DomTreeNodePtr B);

// Insert the frontier.
void InsertFrontier(DomTreeNodePtr Node, DomTreeNodePtr FrontierItem);

// ComputeDomFrontier() - Compute the forward dominance frontier.
void ComputeDomFrontier();
public:
// compute the DomTree of the CFG.
void runOnCFG(std::vector<BBPtr> &BBs);
// compute the DomTree of the Function.
void runOnFunction(FuncPtr F);

void ComputeDomFrontierOnCFG(std::vector<BBPtr> &BBs);
void ComputeDomFrontierOnFunction(FuncPtr F);

DomTreeNodePtr getDomTreeNode(BBPtr BB) const;

// getRootNode - This returns the entry node for the CFG of the function.
DomTreeNodePtr getRootNode() { return RootNode; }
bool properlyDominates(DomTreeNodePtr Node) const;
bool isReachableFromEntry(BBPtr BB) const;
bool dominates(DomTreeNodePtr A, DomTreeNodePtr B) const;

// printIDoms - Convert IDoms to human readable form.
void printIDoms(std::ostream &out) const;

// printDF - Convert Dom Frontier to human readable form.
void printDomFrontier(std::ostream &out) const;

void DFS(DomTreeNodePtr Node);

// Calcuate - compute a dominator tree for the given function.
void Calcuate();

// dominates - Return true if A dominates B. This perform the special
// checks necessary if A and B are in the same basic block.
bool dominates(InstPtr A, InstPtr B) const;
};

void DominatorTree::Calcuate()
{
if (ReversePostOrder.size() == 0)
getReversePostOrder();

// iterate
bool changed = true;
RootNode->setIDom(RootNode);

while (changed)
{
changed = false;
for (auto CurNode : ReversePostOrder)
{
if (CurNode == RootNode)
continue;

// Get the predecessors of current node.
auto PredDomNodeFromCFG = getDomNodePredsFromCFG(CurNode);

// (1) Find the first non-nullptr predecessor.
auto getAvailiablePred =
[this, &PredDomNodeFromCFG]() -> DomTreeNodePtr
{
// 从Preds中找到一个IDom不为空的predecessor.
for (auto pred : PredDomNodeFromCFG)
{
if (pred->getIDom() != nullptr)
return pred;
}
assert(0 && "Unreachable code.");
return nullptr;
};

auto AvailiablePred = getAvailiablePred();
DomTreeNodePtr NewIDom = AvailiablePred;

// (2) Traverse other predecessors.
for (auto pred : PredDomNodeFromCFG)
{
if (pred == NewIDom)
continue;
if (pred->getIDom() != nullptr)
NewIDom = Intersect(NewIDom, pred);
}

// (3) Judge the IDom is changed.
if (CurNode->getIDom() != NewIDom)
{
CurNode->setIDom(NewIDom);
changed = false;
}
}

}
}

void DominatorTree::ComputeDomFrontier()
{
DomTreeNodePtr runner = nullptr;
// Just compute the join points.
for (auto Node : JoinNodes)
{
auto preds = getDomNodePredsFromCFG(Node);
for (auto pred : preds)
{
runner = pred;
while (runner != Node->getIDom())
{
InsertFrontier(runner, Node);
runner = runner->getIDom();
}
}
}
}

//---------------------示例代码--------------------------
var number = 100;
var sum : int;

while(number > 0)
{
sum += number--;
}

var result : bool;
if (sum > 100000)
{
result = true;
while(sum > 0)
{
sum--;
}
}
else
{
result = false;
}
// ----------------------渣到爆的IR---------------------
entry:
%number.addr = alloca int        ; < int* >
%sum.addr = alloca int        ; < int* >
%result.addr = alloca bool        ; < bool* >
store int 100.000000, int* %number.addr        ; < void >
br label %while.cond0

%while.cond0:
%gt.result4 = cmp gt int %3, int 0.000000        ; <  bool >
br bool %gt.result4, label %while.body2, label %while.end1

%while.body2:
%dec6 = add int %5, int -1        ; < int >
store int %dec6, int* %number.addr        ; < void >
br label %while.cond0

%while.end1:
%gt.result14 = cmp gt int %13, int 100000.000000        ; <  bool >
br bool %gt.result14, label %if.then10, label %if.else12

%if.then10:
store bool , bool* %result.addr        ; < void >
br label %while.cond16

%while.cond16:
%gt.result20 = cmp gt int %19, int 0.000000        ; <  bool >
br bool %gt.result20, label %while.body18, label %while.end17

%while.body18:
%dec22 = add int %21, int -1        ; < int >
store int %dec22, int* %sum.addr        ; < void >
br label %while.cond16

%while.end17:
br label %if.end11

%if.else12:
store bool , bool* %result.addr        ; < void >
br label %if.end11

%if.end11:

• 广告
• 抄袭
• 版权
• 政治
• 色情
• 无意义
• 其他

120