2021SC@SDUSC
历时好久的me_ir部分终于结束了,我也松了一口气,下面该换新内容了。
前文分析过,在MeFuncPhase类别的phase执行之前,要进行一系列的准备工作,其中有一部分工作就是和MeFunction的CFG有关。MeFunction的CFG实现,主要是通过MeCFG类来进行的实现,本文将对MeCFG的实现及使用进行一个简单的分析。
MeCFG的定义和实现是在文件src/maple_me/include/me_cfg.h 和 src/maple_me/src/me_cfg.cpp之中。
MeCFG只有两个成员变量:
private:
MeFunction &func;
bool hasDoWhile = false;
func用于将MeCFG对应到一个具体的MeFunction。hasDoWhile用于表示是否有DoWhile,从目前已经公开的代码来看,属于冗余的成员变量,并没有被使用。
MeCFG的成员函数主要有:
void BuildMirCFG();
void FixMirCFG();
void ConvertPhis2IdentityAssigns(BB &meBB) const;
void UnreachCodeAnalysis(bool updatePhi = false);
void WontExitAnalysis();
void Verify() const;
void VerifyLabels() const;
void Dump() const;
void DumpToFile(const std::string &prefix, bool dumpInStrs = false) const;
bool FindExprUse(const BaseNode &expr, StIdx stIdx) const;
bool FindUse(const StmtNode &stmt, StIdx stIdx) const;
bool FindDef(const StmtNode &stmt, StIdx stIdx) const;
bool HasNoOccBetween(StmtNode &from, const StmtNode &to, StIdx stIdx) const;
- BuildMirCFG构建MIR的控制流图;
- FixMirCFG是修复MIR的控制流图;
- ConvertPhis2IdentityAssigns将phi指令转化为明确的赋值(identify assignment);
- UnreachCodeAnalysis未到达代码分析,主要分析从函数入口无法到达的BB,然后删除它们;
- WontExitAnalysis分析查找不会到达函数退出位置的BB,然后为其添加不会退出标记,并为其创建可以到达comment_exit_bb的路径;
- Verify检验MeFunction中的BB的属性和CFG属性都正常;
- VerifyLabels检验Lable是否正确;
- Dump和DumpToFile都是要dump出信息,只是方式不同;
- FindExprUse查找表达式是否使用,具体来说就是stIdx(符号)是否在expr中使用;
- FindUse查找stIdx(符号)是否在stmt之中使用;
- FindDef查找stIdx(符号)是否在stmt之中定义;
- HasNoOccBetween查找stIdx(符号)没有from到to中使用或者定义,没有的话返回true;这个成员函数要调用FindUse和FindDef来实现。
MeCFG在代码之中只在MeFunction之中使用。共有两个部分使用,第一个部分:
src/maple_me/include/me_function.h
MeCFG *GetTheCfg() {
return theCFG;
}
void SetTheCfg(MeCFG *currTheCfg) {
theCFG = currTheCfg;
}
获取或者设置MeFunction的MeCFG*类型的成员变量theCFG ,成员变量定义如下:
MeCFG *theCFG = nullptr;
MeCFG在MeFunction之中使用的第二个部分就是我们前面提到的为MeFunctionPhase运行做准备的过程之中,构建CFG:
src/maple_me/src/me_function.cpp
void MeFunction::Prepare(unsigned long rangeNum) {
if (!MeOption::quiet) {
LogInfo::MapleLogger() << "---Preparing Function < " << CurFunction()->GetName() << " > [" << rangeNum
<< "] ---\n";
}
/* lower first */
MIRLower mirLowerer(mirModule, CurFunction());
mirLowerer.Init();
mirLowerer.SetLowerME();
mirLowerer.SetLowerExpandArray();
ASSERT(CurFunction() != nullptr, "nullptr check");
mirLowerer.LowerFunc(*CurFunction());
CreateBasicBlocks();
if (NumBBs() == 0) {
/* there's no basicblock generated */
return;
}
RemoveEhEdgesInSyncRegion();
theCFG = memPool->New<MeCFG>(*this);
theCFG->BuildMirCFG();
theCFG->FixMirCFG();
theCFG->VerifyLabels();
theCFG->UnreachCodeAnalysis();
theCFG->WontExitAnalysis();
theCFG->Verify();
}
其中主要执行了这几步:
theCFG = memPool->New<MeCFG>(*this);
theCFG->BuildMirCFG();
theCFG->FixMirCFG();
theCFG->VerifyLabels();
theCFG->UnreachCodeAnalysis();
theCFG->WontExitAnalysis();
theCFG->Verify();
其中第一条语句为theCFG 新建对象并申请空间,后续的操作我们在3中进行过介绍,主要是新建控制流图,然后各种分析和验证的过程。
值得注意的是,这个使用CFG的流程,就是方舟中CFG使用的标准流程。因为目前开源的地方,对于CFG的使用就此一处,我们就要以这个官方顺序为标准。后续源码全部开放,可以调试分析的时候可以再hack这里的验证顺序是否可以调整。