@@ -283,6 +283,106 @@ bool shouldPreserveForPureCallLoopCache(CallInst * call)
283283 return true ;
284284}
285285
286+ // / @brief 剥离 GEP 链获取指针的根对象,仅识别全局变量与 alloca
287+ // / @param value 待剥离的指针值
288+ // / @return 根对象(全局变量或 alloca),无法识别时返回 nullptr
289+ Value * stripWritableRoot (Value * value)
290+ {
291+ std::unordered_set<Value *> visited;
292+ while (value && visited.insert (value).second ) {
293+ if (auto * gep = dynamic_cast <GetElementPtrInst *>(value)) {
294+ value = gep->getBasePointer ();
295+ continue ;
296+ }
297+ break ;
298+ }
299+ if (dynamic_cast <GlobalVariable *>(value) != nullptr || dynamic_cast <AllocaInst *>(value) != nullptr ) {
300+ return value;
301+ }
302+ return nullptr ;
303+ }
304+
305+ // / @brief 判断 callee 是否可能通过指针形参写入调用方内存
306+ // /
307+ // / store 地址的根既不是 callee 自身的 alloca 也不是全局变量时,
308+ // / 视为可能经形参指针写入调用方内存(mem2reg 前后均成立的保守判定)
309+ // / @param callee 被调用函数
310+ // / @return true 表示可能写入调用方传入的内存
311+ bool calleeMayWriteParamMemory (Function * callee)
312+ {
313+ for (auto * bb : callee->getBlocks ()) {
314+ for (auto * inst : bb->getInstructions ()) {
315+ auto * store = dynamic_cast <StoreInst *>(inst);
316+ if (store != nullptr && stripWritableRoot (store->getPointerOperand ()) == nullptr ) {
317+ return true ;
318+ }
319+ }
320+ }
321+ return false ;
322+ }
323+
324+ // / @brief 若调用匹配 LoopTiling 可折叠的重复不变调用循环模式,保留给折叠 pass
325+ // /
326+ // / LoopTiling 的 collapseRepeatedInvariantCallLoop 依赖循环体内
327+ // / "覆盖性 store + 唯一用户调用"的形态将常量重复循环折叠为单次执行,
328+ // / 提前内联该调用会破坏形态使折叠永久失效。这里用保守的充分信号判定:
329+ // / callee 可能经指针形参写内存,且调用点所在循环体内存在对某个
330+ // / 指针实参根对象的 store(即每轮先恢复数组再调用的模式)
331+ // / @param call 待判断的调用点
332+ // / @return true 表示应跳过内联,把机会留给折叠 pass
333+ bool shouldPreserveForRepeatedCallLoopFold (CallInst * call)
334+ {
335+ Function * caller = call ? call->getFunction () : nullptr ;
336+ Function * callee = call ? call->getCallee () : nullptr ;
337+ if (!caller || !callee || !call->getParentBlock ()) {
338+ return false ;
339+ }
340+
341+ if (!calleeMayWriteParamMemory (callee)) {
342+ return false ;
343+ }
344+
345+ // 收集调用的指针实参根对象(全局变量或调用方数组 alloca)
346+ std::unordered_set<Value *> argRoots;
347+ for (int32_t arg = 0 ; arg < call->getArgCount (); ++arg) {
348+ if (Value * root = stripWritableRoot (call->getArg (arg))) {
349+ argRoots.insert (root);
350+ }
351+ }
352+ if (argRoots.empty ()) {
353+ return false ;
354+ }
355+
356+ DominatorTree domTree (caller);
357+ LoopInfo loopInfo (caller, &domTree);
358+ BasicBlock * callBlock = call->getParentBlock ();
359+
360+ // 任一包含调用点的循环体内若存在覆盖实参根对象的 store 则保留
361+ for (auto * header : caller->getBlocks ()) {
362+ if (!loopInfo.isLoopHeader (header)) {
363+ continue ;
364+ }
365+ const auto * loopBody = loopInfo.getLoopBody (header);
366+ if (!loopBody || loopBody->find (callBlock) == loopBody->end ()) {
367+ continue ;
368+ }
369+ for (auto * bb : *loopBody) {
370+ for (auto * inst : bb->getInstructions ()) {
371+ auto * store = dynamic_cast <StoreInst *>(inst);
372+ if (!store) {
373+ continue ;
374+ }
375+ Value * root = stripWritableRoot (store->getPointerOperand ());
376+ if (root != nullptr && argRoots.count (root) > 0 ) {
377+ return true ;
378+ }
379+ }
380+ }
381+ }
382+
383+ return false ;
384+ }
385+
286386// / @brief 判断指令是否属于内联支持的指令类型
287387// / @param inst 待检查的指令
288388// / @return true 表示该指令可以被安全地克隆和内联
@@ -452,6 +552,11 @@ bool SmallFunctionInline::shouldInlineCallee(Function * caller, CallInst * call)
452552 return false ;
453553 }
454554
555+ // 与 LoopTiling 的协作:保留可折叠的重复不变调用循环中的调用
556+ if (shouldPreserveForRepeatedCallLoopFold (call)) {
557+ return false ;
558+ }
559+
455560 // 防止极端栈帧膨胀
456561 if (getAllocaBytes (callee) > kMaxAllocaBytes ) {
457562 return false ;
0 commit comments