后端Pass简介——GlobalMergeFunctions
GlobalMergeFunctions
600 行
GlobalMergeFunc 是 LLVM 中的一个 ModulePass,旨在识别并合并在模块或跨模块范围内功能等价或高度相似的函数,从而去重并减小生成代码体积。它通过结构化哈希算法对函数进行比较,忽略可参数化的常量操作数,然后为差异化的常量生成额外参数,最终创建单一的合并函数并用 thunk 保持原始接口不变。该过程既支持本地合并,也能借助 CGData 在 LTO 阶段执行跨模块的乐观合并。
- thunk:Thunk(有时也直译为“馅饼”或“跳板”)是一个轻量级的包装函数,它本身不做实际业务逻辑,而是把调用“转发”(forward)给另一个目标函数。
- 结构化 hash:结构化哈希是一种对函数(或指令序列)结构进行“指纹”提取的算法,它考虑==指令的种类、控制流、操作数==类型等结构信息,而不是简单地对字节码或源代码做哈希。
STATISTIC(NumMergedFunctions,
"Number of functions that are actually merged using function hash");
STATISTIC(NumAnalyzedModules, "Number of modules that are analyzed");
STATISTIC(NumAnalyzedFunctions, "Number of functions that are analyzed");
STATISTIC(NumEligibleFunctions, "Number of functions that are eligible");
核心函数为:
bool GlobalMergeFunc::run(Module &M) {
initializeMergerMode(M);
const StableFunctionMap *FuncMap;
if (MergerMode == HashFunctionMode::UsingHashFunction) {
// Use the prior CG data to optimistically create global merge candidates.
FuncMap = cgdata::getStableFunctionMap();
} else {
analyze(M);
// Emit the local function map to the custom section, __llvm_merge before
// finalizing it. if (MergerMode == HashFunctionMode::BuildingHashFuncion)
emitFunctionMap(M);
LocalFunctionMap->finalize();
FuncMap = LocalFunctionMap.get();
}
return merge(M, FuncMap);
}
核心处理函数 merge 主要承担了以下职能:
- 收集同哈希的函数
根据前面 analyze 阶段或 CGData 提供的哈希映射,把模块中所有结构哈希相同的函数归到同一组(HashToFuncs)。 - 过滤与匹配
对每组函数,先用指令数和可忽略常量位置做快速过滤,然后再用 checkConstHashCompatible 和 checkConstLocationCompatible 做更严格的校验,确保这些函数在逻辑上可合并。 - 计算常量参数化信息
一旦确认了一组可合并的函数,就调用 computeParamInfo,根据各函数在相同指令位置上不同的常量,生成一组“参数化位置”。 - 创建合并函数
对每个待合并函数,调用 createMergedFunction,生成那个带 .Tgm 后缀的新函数(把原函数体整体搬过去,并在最后追加那些常量作为新参数)。 - 生成 Thunk
再调用 createThunk,把原函数体改成一个简单的“包装”——把原来的参数和常量参数一并传给新函数,然后转发返回。 - 统计与返回
每合并一次就更新 NumMergedFunctions 统计,最终返回是否有任何改动。
因此,merge 函数就是将“结构哈希分桶 + 常量参数化 + 合并 + Thunk 转发”串联起来的主流程。其余几个函数(analyze、createMergedFunction、createThunk、各种检查函数)都是为它服务的辅助模块。
评论