1、在社区commit 2813acb7d1将m_Undef同时能识别undefs and poisons后,CSE 中SimplifyICmpInst就能对这些Undef比较的指令进行简化
注意:要求所有向量元素均是undefs 或者 poisons,详见上述patch中的undef_match
// icmp X, X -> true/false
// icmp X, undef -> true/false because undef could be X.
if (LHS == RHS || Q.isUndefValue(RHS))
return ConstantInt::get(ITy, CmpInst::isTrueWhenEqual(Pred));
2、PRE 包括CSE和LICM, 基于GVN分析进行优化 .PRE is considered to be a powerful transformation because it subsumes a (full redundancy elimination) transformation like common subexpression elimination (CSE) and loop invariant code motion (LICM) [5].参考https://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.96.4443&rep=rep1&type=pdf
3、PRE和向量化存在冲突,因为Pre创建了反向跨迭代依赖阻止了向量化 (向量化中循环结点不允许存在IV之外的PHI结点) 参考[loop vectorize] failure to vectorize after GVN load-pre · Issue #38583 · llvm/llvm-project · GitHub
4、在 commit bcdcf984cc 中切换默认的GVN方法,Use '-passes=newgvn' instead of '-basic-aa -newgvn'
5、不变量外提需要考虑寄存器压力,因此一些mov类指令会被认为增加寄存器压力而不外提,详见MachineLICM.cpp:IsProfitableToHoist. 但事实上,寄存器压力评估是不准确的,比如的寄存器压力实际并不大[optimization] use vector register to init const float value · Issue #53651 · llvm/llvm-project · GitHub
6、gvn-hoist需要阻止不同类型的loads (same source pointer)进行合并,参考D122521
7、 MachineSinking::isProfitableToSinkTo 中决定指令是否需要sink?106268 – [suboptimal] Remove unnecessary loops releated to fortran compare to ifort
8、在LICM中,会根据MSSA、AAResult分析相关指令的alias信息,进而实现循环中store指令的外提, 参考collectPromotionCandidates
循环不变量外提需要依靠MemorySSA的分析结果,而MemorySSA分析也需要借助AliasAnalysis的结果。
buildMemorySSA( ) -> 生成默认MemoryUse(value) -> optimizeUsesInBlock( ) (更新MemoryUse(value)的value值)-> ... -> instructionClobbersQuery( ) (调用AliasAnalysis获取信息查询指令的Clobber)
MemoryUse(XX)对应的MemoryDef(XX)是初始默认的Def
9、增强不变量属性invariant的分析,commit 8d0383eb(非必须), 但并不意味着会外提?需要确保外提后没有寄存器压力的问题commit 645bdd4b69
SU(6): t62: nxv2f64,ch = LD1RD_IMM<Mem:(dereferenceable invariant load (s64)
注意:能外提的指令,显然是要求没有副作用hasUnmodeledSideEffects(),在isSafeToMove中判断(注:默认属性仅对signle pattern tablegen起效,参考D139637)
10、利用sink巧妙的解决vacale指令合并时跨BB不能优化的问题,钩子 shouldSinkOperands,参考PR70304;
11、在后端允许特定的指令hoist, 比如copy指令在寄存器分配时可能评估不合适,需要在寄存器分配后进行调整,参考PR71403
12、在https://github.com/llvm/llvm-project/pull/72187上有个启示,也就是对于循环不变量,并不一定能够自然外提。生成指令时需要插在合适的位置
13、一些类似指令合并的工作也可能在sink处理,因为可以额外考虑寄存器压力,参考D152828
// add Xa, Xn, Wm, {s,u}xtw #N
// ldr Xd, [Xa] -- offset 使用1个寄存器
// ->
// ldr Xd, [Xn, Wm, {s,u}xtw #N]
14、找cse处理alias时, CallValue::canHandle 会处理read-only call
a) 通过isSameMemGeneration判断,如果和之前相同的访存操作是同一个CurrentGeneration则可以优化;
b) 通过AvailableCalls.insert(&Inst, std::make_pair(&Inst, CurrentGeneration))为指令标识合适的CurrentGeneration,从而实现流敏感的实现
c) fabs不涉及errno, 在EarlyCSE能优化重复的load; 但exp存在errno,即使增加tbaa信息(PR96025),也不会再此pass优化,而是在InstCombinePass中优化