[llvm] [FunctionSpecializer] Do not mark function dead if any unexecutable call site exists (PR #154668)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Sat Aug 23 08:15:10 PDT 2025


https://github.com/antoniofrighetto commented:

LLVM IR module before BBs pruning in SCCP:
```llvm
define i32 @caller() {
entry:
  %call1 = call i32 @callee.specialized.1(i32 1)
  %call2 = call i32 @callee.specialized.2(i32 0)
  %cond = icmp eq i32 undef, 0
  br i1 %cond, label %common.ret, label %if.then

common.ret:                                       ; preds = %entry
  ret i32 0

if.then:                                          ; preds = %entry
  %unreachable_call = call i32 @callee(i32 2)
  ret i32 0
}

define internal i32 @callee(i32 %ac) {
entry:
  br label %ai

ai:                                               ; preds = %entry
  unreachable

aj:                                               ; No predecessors!
  unreachable
}

define internal i32 @callee.specialized.1(i32 %ac) {
entry:
  br label %ai

ai:                                               ; preds = %ai, %entry
  %add = or i32 0, 0
  %cond = icmp eq i32 %ac, 1
  br i1 %cond, label %aj, label %ai

aj:                                               ; preds = %ai
  ret i32 0
}

define internal i32 @callee.specialized.2(i32 %ac) {
entry:
  br label %ai

ai:                                               ; preds = %ai, %entry
  %add = or i32 0, 0
  %cond = icmp eq i32 %ac, 1
  br i1 %cond, label %aj, label %ai

aj:                                               ; preds = %ai
  ret i32 0
}
```
As you correctly noted, FunctionSpecialization happens to look only at executable call-sites. Since the last call-site is not marked as executable, it is ignored by specialization. IIUC the fix correctly, you're suggesting to introduce specialization to those call-sites that live in basic blocks which were determined by the solver to be never executable.

The current code in updateCallSites seems correct to me, as `callee` is eventually marked as unreachable, as being fully specialized along all its executable-proven paths:

https://github.com/llvm/llvm-project/blob/cbf5af9668931bbc843a80817e0385629e03c5e4/llvm/lib/Transforms/IPO/FunctionSpecialization.cpp#L1207-L1212

Isn't the discrepancy here stemming from the fact that we are attempting to remove basic blocks of a fully specialized function, where it should be up to FunctionSpecializer's destructor to remove such functions (in which case, unreachable call-sites should be removed as well)?

https://github.com/llvm/llvm-project/pull/154668


More information about the llvm-commits mailing list