方舟编译器包含了一系列优化措施,并以phase的形式进行管理。本文将以中端的优化为例,介绍phase的设计和使用,以及如何自定义phase。
中端主要包含两大类phase:ModulePhase和MeFuncPhase,都继承自Phase类。phase类最重要的是Run方法,根据是否要做分析分为两个重载。
virtual AnalysisResult *Run(MeFunction *ir, MeFuncResultMgr *frm) {
return nullptr;
}
// By default mrm will not be used because most ME phases do not need
// IPA result. For those will use IPA result, this function will be overrode.
virtual AnalysisResult *Run(MeFunction *ir, MeFuncResultMgr *frm,
ModuleResultMgr *mrm) {
return Run(ir, frm);
}
所以,当添加一个新的phase的时候,必须要实现其中至少一个Run方法,并重写PhaseName方法返回名字。以rclowering作为一个例子:
class MeDoRCLowering : public MeFuncPhase {
public:
MeDoRCLowering(MePhaseID id) : MeFuncPhase(id) {}
virtual ~MeDoRCLowering() = default;
AnalysisResult *Run(MeFunction*, MeFuncResultMgr*, ModuleResultMgr*) override;
const std::string PhaseName() const override {
return "rclowering";
}
};
AnalysisResult *MeDoRCLowering::Run(MeFunction *func, MeFuncResultMgr *m,
ModuleResultMgr *mrm) {
KlassHierarchy *kh =
static_cast<KlassHierarchy*>(mrm->GetAnalysisResult(MoPhase_CHA,
&func->GetMIRModule()));
DASSERT(kh != nullptr, "KlassHierarchy has problem");
MeIRMap *hmap = static_cast<MeIRMap*>(m->GetAnalysisResult(MeFuncPhase_IRMAP,
func));
DASSERT(hmap != nullptr, "hssamap has problem");
RCLowering rclowering(func, kh);
MIRFunction *mirfunction = func->GetMirFunc();
DASSERT(mirfunction->GetModule()->CurFunction() == mirfunction,
"unexpected CurFunction");
string funcname = mirfunction->GetName();
if (DEBUGFUNC(func)) {
LogInfo::MapleLogger() << "Handling function " << funcname << std::endl;
}
...
PhaseManager负责phase的创建、管理和运行。与phase对应,有ModulePhaseManager和MeFuncPhaseManager两类。 PhaseManager首先注册其所有支持的phase,然后使用者就可以根据需要通过add phase接口添加期望使用的phase。
1.注册phase
以MeFuncPhaseManager为例,其通过RegisterFuncPhases方法来注册。注册的phase通过registeredPhases这个map来管理。
void MeFuncPhaseManager::RegisterFuncPhases() {
// register all Funcphases defined in mephases.def
#define FUNCTPHASE(id, mephase) \
do { \
void *buf = GetMemAllocator()->GetMemPool()->Malloc(sizeof(mephase(id))); \
ASSERT(buf != nullptr, "null ptr check"); \
RegisterPhase(id, (new (buf) mephase(id))); \
} while (0);
#define FUNCAPHASE(id, mephase)
do { \
void *buf = GetMemAllocator()->GetMemPool()->Malloc(sizeof(mephase(id))); \
ASSERT(buf != nullptr, "null ptr check"); \
RegisterPhase(id, (new (buf) mephase(id))); \
arFuncManager.AddAnalysisPhase(id,(static_cast<MeFuncPhase*>(GetPhase(id))));\
} while (0);
#include "mephases.def"
#undef FUNCTPHASE
#undef FUNCAPHASE
}
void RegisterPhase(PhaseId id, Phase *p) {
registeredPhases[id] = p;
}
这里使用了宏的机制来实现注册,便于管理需要注册的phase,只需编辑对应的def文件即可。mephases.def部分内容如下,第一个参数是id,第二个是phase类名。
FUNCAPHASE(MeFuncPhase_SSATAB, MeDoSSATab)
FUNCAPHASE(MeFuncPhase_ALIASCLASS, MeDoAliasClass)
FUNCAPHASE(MeFuncPhase_SSA, MeDoSSA)
对于上面举例的rclowering phase,支持它只需添加如下一行即可:
FUNCTPHASE(MeFuncPhase_RCLOWERING, MeDoRCLowering)
2.添加phase
子类phase manager都提供了各自添加phase的接口,这些接口对输入进行处理后最终会调用基类PhaseManager的AddPhase方法。
void MeFuncPhaseManager::AddPhasesNoDefault(std::vector<std::string> &phases) {
for (unsigned i = 0; i < phases.size(); i++) {
PhaseManager::AddPhase(phases[i].c_str());
}
DASSERT(phases.size() == GetphaseSeq()->size(), "invalid phase name");
}
void AddPhase(const std::string &pname) {
for (auto it = RegPhaseBegin(); it != RegPhaseEnd(); it++) {
if (GetPhaseName(it) == pname) {
phaseSequences.push_back(GetPhaseId(it));
phaseTimers.push_back(0);
return;
}
}
...
添加的phase通过MapleVector来进行管理。
使用者除了可以使用上面的方式自行添加phase外,还可以借助InterleavedManager和DriverRunner组成的框架对phase进行更有效的管理。
1.InterleavedManager
InterleavedManager负责phase manager的创建、管理和运行。通过调用AddPhases接口,它将创建一个对应类型的phase manager并添加进MapleVector中, 同时该phase manager相应的phase注册、添加也会自动被触发。
void InterleavedManager::AddPhases(vector<string> &phases, bool isModulePhase,
bool timephases, bool genmpl) {
ModuleResultMgr *mrm = nullptr;
if (!phaseManagers.empty()) {
// ModuleResult such class hierarchy need to be carried on
ModulePhaseManager *mpm =
dynamic_cast<ModulePhaseManager*>(phaseManagers[phaseManagers.size()-1]);
MeFuncPhaseManager *mepm =
dynamic_cast<MeFuncPhaseManager*>(phaseManagers[phaseManagers.size()-1]);
if (mpm != nullptr) {
mrm = mpm->GetModResultMgr();
} else if (mepm != nullptr) {
mrm = mepm->GetModResultMgr();
}
}
if (isModulePhase) {
ModulePhaseManager *mpm =
GetMempool()->New<ModulePhaseManager>(GetMempool(), &mirmodule, mrm);
mpm->RegisterModulePhases();
mpm->AddModulePhases(phases);
if (timephases) {
mpm->SetTimePhases(true);
}
phaseManagers.push_back(mpm);
...
InterleavedManager的Run方法将依次运行所有管理的phase manager。
void InterleavedManager::Run() {
for (PhaseManager *const &pm : phaseManagers) {
if (dynamic_cast<MeFuncPhaseManager*>(pm)) {
MeFuncPhaseManager *fpm = static_cast<MeFuncPhaseManager*>(pm);
unsigned long rangeNum = 0;
MapleVector<MIRFunction*> *compList;
if (!mirmodule.GetCompilationList().empty()) {
...
2.DriverRunner
DriverRunner包含了从一个mpl文件到优化结果文件的所有过程。ParseInput方法负责解析mpl文件。ProcessMpl2mplAndMePhases方法通过InterleavedManager负责phase的管理和运行。
DriverRunner也是通过宏的方式来集中管理phase,在phases.def文件里添加phase,然后通过InitPhases接口来遍历所有的phase并创建对应的phase manager。
phases.def内容如下:
// Phase arguments are: name, condition. By default, all phases are required, so
// the condition value is 'true'.
// You can use condition to control these phases and your custom phases. E.g.
// ADD_PHASE("custom_phase", option1 == value1 [more conditions...]).
ADD_PHASE("classhierarchy", true)
ADD_PHASE("vtableanalysis", true)
ADD_PHASE("reflectionanalysis", true)
ADD_PHASE("gencheckcast", true)
ADD_PHASE("javaintrnlowering", true)
// mephase begin
ADD_PHASE("ssatab", true)
ADD_PHASE("aliasclass", true)
ADD_PHASE("ssa", true)
ADD_PHASE("analyzerc", true)
ADD_PHASE("rclowering", true)
ADD_PHASE("emit", true)
// mephase end
ADD_PHASE("GenNativeStubFunc", true)
ADD_PHASE("clinit", true)
ADD_PHASE("VtableImpl", true)
ADD_PHASE("javaehlower", true)
ADD_PHASE("MUIDReplacement", true)
第一个参数是phase名字,第二个参数是条件。现有的phase默认都是enable的,对于自定义的phase可以自行添加控制条件。
在ProcessMpl2mplAndMePhases里将该phases.def文件include进来,并通过宏添加进vector里。
#include "../defs/phases.def"
#define ADD_PHASE(name, condition) \
if ((condition)) { \
phases.push_back(string(name)); \
}
InitPhases方法会将添加的phase拆解到InterleavedManager的phase manager集合里。
void DriverRunner::InitPhases(InterleavedManager &mgr, vector<string> &phases) const {
if (phases.empty()) {
return;
}
const PhaseManager *curManager = nullptr;
vector<string> curPhases;
for (string phase : phases) {
auto temp = mgr.GetSupportPhaseManager(phase);
if (temp != nullptr) {
if (temp != curManager) {
AddPhases(mgr, curPhases, curManager);
curManager = temp;
curPhases.clear();
}
AddPhase(curPhases, phase, curManager);
}
}
AddPhases(mgr, curPhases, curManager);
}
GetSupportPhaseManager用来获取当前phase对应的phase manager。
总结一下,phase涉及到的几个关键类如下:
- Phase类及其两个主要的子类ModulePhase和MeFuncPhase,通过扩展他们新增自定义phase
- PhaseManager类及其两个主要子类ModulePhaseManager和MeFuncPhaseManager,管理phase的注册和添加
- InterleavedManager类负责phase manager的创建、管理和运行
- DriverRunner类包含了从一个mpl文件到优化结果文件的所有过程。 ParseInput方法负责解析mpl文件。 ProcessMpl2mplAndMePhases方法通过InterleavedManager负责phase的管理和运行。
通过以上的框架,自定义phase只需完成如下三步便可应用到系统中: