[AArch64][SME] AlwaysInliner's new attribute-compatibility check (#209345) leaves un-legalizable orphan functions instead of preventing them
- Dominant language
- LLVM
- Stars
- 40.5k
- Forks
- 18.7k
- PR merge metrics
- PR metrics pending
Description
`[AlwaysInliner] Do not inline on attribute mismatches` (#209345, commit 37b8e765ce48) made `AlwaysInlinerPass` consult `TTI::areInlineCompatible` before inlining an `alwaysinline` callee. On AArch64, this now blocks inlining a plain (non-streaming-attributed) helper that only contains SVE intrinsics into a caller with `"aarch64_pstate_sm_body"`, because `AArch64TTIImpl::areInlineCompatible` → `hasPossibleIncompatibleOps` conservatively flags *any* `@llvm.aarch64.*` intrinsic call as SM-incompatible.
The callee doesn't get an alternative, legal lowering — it's `alwaysinline` precisely because it has none. Leaving it un-inlined just relocates the bug: the orphaned function has no streaming/SVE attribute of its own, so `AArch64Subtarget::isSVEorStreamingSVEAvailable()` is false for it, and instruction selection later crashes:
```
fatal error: error in backend: Don't know how to legalize this scalable vector type
...
3. Running pass 'AArch64 Instruction Selection' on function '@fast_inverse_f16nx8'
```
**Minimal reproducer** (no frontend needed):
```llvm
target triple = "aarch64-unknown-linux-gnu"
define linkonce_odr @fast_inverse_f16nx8( %x) #0 {
%approx = tail call @llvm.aarch64.sve.frecpe.x.nxv8f16( %x)
%correction = tail call @llvm.aarch64.sve.frecps.x.nxv8f16( %approx, %x)
%result = fmul %approx, %correction
ret %result
}
declare @llvm.aarch64.sve.frecpe.x.nxv8f16() #1
declare @llvm.aarch64.sve.frecps.x.nxv8f16(, ) #1
define @caller( %v) #2 {
%r = call @fast_inverse_f16nx8( %v)
ret %r
}
attributes #0 = { alwaysinline mustprogress nounwind "target-cpu"="generic" "target-features"="+fullfp16,+sme2" }
attributes #1 = { nocallback nofree nosync nounwind willreturn memory(none) }
attributes #2 = { mustprogress noinline nounwind vscale_range(4,4) "aarch64_pstate_sm_body" "target-cpu"="generic" "target-features"="+fullfp16,+sme2" }
```
```
$ clang -c repro.ll -O2 -o repro.o
```
- Before 37b8e765ce48: `@fast_inverse_f16nx8` is inlined into `@caller` by `always-inline`; compiles cleanly.
- At/after 37b8e765ce48 (reproduced on `23.1.0rc3`): inlining is skipped; compilation crashes as above.
Found via Halide, which emits exactly this pattern (an `alwaysinline` runtime helper built from SVE-only intrinsics, called from an SME2-streaming-mode function) for its ARM SVE2/SME2 backend.
Possible fixes: have `hasPossibleIncompatibleOps` not treat streaming-compatible-only SVE intrinsics as incompatible, or have `AlwaysInlinerPass` force the inline (emitting the diagnostic but still inlining) when the callee is `alwaysinline` and has no other legal target.
Contributor guide
Research direction
Start by running the provided repro.ll with clang -c repro.ll -O2 and inspect AlwaysInlinerPass, AArch64TTIImpl::areInlineCompatible, and hasPossibleIncompatibleOps. Trace how AArch64Subtarget::isSVEorStreamingSVEAvailable() affects the orphan function; done means the reproducer no longer reaches the scalable-vector legalization crash while preserving the intended compatibility checks.
Written by the indexing model from the issue text.
Assessment
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100