dotnet / dotnet/runtime

[mono][llvm] Malformed uaddlp/saddlp intrinsic declaration breaks LLVM AOT with LLVM 23

Closed Beginner friendly
#132,743 1 comment 0 reactions 0 assignees View on GitHub
area-Codegen-meta-mono
Dominant language
C#
Stars
18.3k
Forks
5.6k
PR merge metrics
PR metrics pending

Description

### Description

Mono's LLVM AOT compiler emits a malformed declaration for the `llvm.aarch64.neon.uaddlp` / `llvm.aarch64.neon.saddlp` intrinsics:

```llvm
declare <8 x i8> @llvm.aarch64.neon.uaddlp.v8i8.f64(double)
declare <8 x i8> @llvm.aarch64.neon.saddlp.v8i8.f64(double)
```

The argument type should be a vector, not `double`. With the recent bump to **LLVM 23**, the IR verifier now rejects this, so any LLVM-AOT compilation of an assembly that references `AdvSimd.AddPairwiseWidening` (or `AddPairwiseWideningScalar` / `AddPairwiseWideningAndAdd`) fails:

```
intrinsic argument 0 type (overload type 1) expected any vector type, but got double
declare <8 x i8> @llvm.aarch64.neon.uaddlp.v8i8.f64(double)
intrinsic argument 0 type (overload type 1) expected any vector type, but got double
declare <8 x i8> @llvm.aarch64.neon.saddlp.v8i8.f64(double)
LLVM ERROR: Broken module found, compilation aborted!
```

In practice this shows up as an AOT compilation failure of `System.Private.CoreLib.dll` in untrimmed Mono iOS apps.

### Root cause

`add_intrinsic ()` in `src/mono/mono/mini/mini-llvm.c` reads out of bounds for the `INTRIN_kind_widen` case:

https://github.com/dotnet/runtime/blob/main/src/mono/mono/mini/mini-llvm.c#L14021-L14027

```c
} else if (kind == INTRIN_kind_widen) {
/*
* @llvm.aarch64.neon.saddlp.v2i64.v4i32
* @llvm.aarch64.neon.saddlp.v4i16.v8i8
*/
intrins = add_intrins2 (module, id, distinguishing_type, intrin_types [vw][ew - 1], &intrins_type);
```

`intrin_types [vw][ew - 1]` is the *narrower* source type. But the two `Widen`-kind intrinsics are declared with `I1` (8-bit elements) in their overload spec:

https://github.com/dotnet/runtime/blob/main/src/mono/mono/mini/llvm-intrinsics.h#L436-L437

```c
INTRINS_OVR_TAG_KIND(AARCH64_ADV_SIMD_SADDLP, aarch64_neon_saddlp, Arm64, Widen, V64 | V128 | I1 | I2 | I4 | I8)
INTRINS_OVR_TAG_KIND(AARCH64_ADV_SIMD_UADDLP, aarch64_neon_uaddlp, Arm64, Widen, V64 | V128 | I1 | I2 | I4 | I8)
```

so the loop reaches `ew == 0` and evaluates `intrin_types [vw][-1]`, which reads the last element of the previous row: `intrin_types [1][-1]` is `intrin_types [0][5]` = `LLVMDoubleType ()`. Hence the `f64` operand.

There is no `uaddlp`/`saddlp` form with an 8-bit **result** element — the valid result element widths are 16/32/64 bits — so `I1` simply doesn't belong in these two specs. `SADDLP`/`UADDLP` are the only two `Widen`-kind entries in `llvm-intrinsics.h`, so no other intrinsic is affected.

The out-of-bounds read has been there since dotnet/runtime#51993 (2021); it only started failing now because of the LLVM 23 bump.

### Why it only breaks with LLVM 23

The intrinsic definition itself is unchanged (`AdvSIMD_1VectorArg_Expand_Intrinsic` is `[llvm_anyvector_ty], [llvm_anyvector_ty]` in both `release/22.x` and `main`). What changed is `llvm/lib/IR/Intrinsics.cpp`, which in LLVM 23 gained the more thorough overload-type checking that produces the `... (overload type N) expected ..., but got ...` diagnostics (that message machinery does not exist in `release/22.x`).

Verified with a file containing nothing but the malformed declaration:

| `opt` version | `opt -passes=verify` |
|-------------------------|----------------------|
| 22.1.2 | accepts |
| 23.1.0-rc2 (mono cross) | rejects |

### Reproduction Steps

Any Mono LLVM-AOT compilation of an assembly that references `AdvSimd.AddPairwiseWidening` reproduces this. Minimal .NET for iOS app:

```csharp
using System;
using System.Runtime.Intrinsics;
using System.Runtime.Intrinsics.Arm;

public class Program {
static void Main ()
{
if (AdvSimd.IsSupported)
Console.WriteLine (AdvSimd.AddPairwiseWidening (Vector64.Create ((byte) 1)));
}
}
```

```xml


net11.0-ios
Exe
iossimulator-arm64
true
com.example.uaddlprepro

```

`dotnet build -c Release`

### Expected behavior

The app builds.

### Actual behavior

```
error : Failed to AOT compile System.Private.CoreLib.dll, the AOT compiler exited with code 1.
```

with the `LLVM ERROR: Broken module found, compilation aborted!` output shown above.

Replacing the single `AdvSimd.AddPairwiseWidening` call with `AdvSimd.AddPairwise` makes the build succeed, which confirms the trigger. Note the intrinsic is registered lazily (`get_intrins` → `add_intrinsic`), and in a stock app the only thing referencing UADDLP/SADDLP is the body of `AdvSimd.AddPairwiseWidening` itself — so trimmed apps are unaffected, and only untrimmed ones fail.

### Configuration

* .NET 11 (`11.0.100-rc.1.26411.119` / runtime `11.0.0-rc.1.26411.119`)
* `Microsoft.NETCore.App.Runtime.AOT.osx-arm64.Cross.iossimulator-arm64`, `tools/opt --version` reports LLVM 23.1.0-rc2
* Mono runtime, LLVM AOT, arm64
* Found via dotnet/macios: the `tests/linker/dont link` (untrimmed) iOS test started failing on the dotnet/dotnet bump from `11.0.0-preview.7.26365.101` to `11.0.0-rc.1.26411.119`.

### Suggested fix

Drop `I1` from both specs:

```c
INTRINS_OVR_TAG_KIND(AARCH64_ADV_SIMD_SADDLP, aarch64_neon_saddlp, Arm64, Widen, V64 | V128 | I2 | I4 | I8)
INTRINS_OVR_TAG_KIND(AARCH64_ADV_SIMD_UADDLP, aarch64_neon_uaddlp, Arm64, Widen, V64 | V128 | I2 | I4 | I8)
```

Contributor guide

Open the contributing guide

Research direction

Start with the SADDLP and UADDLP specifications in src/mono/mono/mini/llvm-intrinsics.h, then inspect add_intrinsic() in src/mono/mono/mini/mini-llvm.c to understand the invalid type lookup. Verify the change with the provided AdvSimd.AddPairwiseWidening reproduction and confirm LLVM 23 accepts the generated IR and the iOS AOT build succeeds.

Written by the indexing model from the issue text.

Assessment

Tech stack
c, csharp
Domain
compilers
Issue type
Bug
Difficulty
1/5
Estimated time
1-3 hours
Activity status
Active
Clarity
Clearly specified
Newbie friendliness
84/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.