Summary
GCC 15 fails to compile MVE kernels in a Zephyr build because its
pragma-generated vldrwq_s32 intrinsics retain the compiler-native
long int pointer type while Zephyr exposes int32_t as int.
This was reproduced with:
- Arm GNU Toolchain GCC 15.2.1
- Zephyr SDK GCC 14.3.0 as the working comparison
- Zephyr
apollo510_evb
- MVE integer and floating-point support enabled
The same sources compile normally with GCC 15 outside Zephyr.
Root cause
Zephyr force-includes zephyr_stdint.h, which changes:
#define __INT32_TYPE__ int
Consequently, int32_t * is int * in the Zephyr translation unit.
GCC 14's arm_mve.h declares the intrinsic textually:
#define vldrwq_s32(base) __arm_vldrwq_s32(base)
__arm_vldrwq_s32(int32_t const *base)
That declaration follows Zephyr's visible int32_t, so the call sites
compile.
GCC 15 changed arm_mve.h to pragma-generated intrinsics:
#pragma GCC arm "arm_mve.h" false
The generated declarations retain these compiler-native signatures:
vldrwq_s32(const long int *)
vldrwq_z_s32(const long int *, mve_pred16_t)
Calls using int32_t * therefore fail with
-Wincompatible-pointer-types. This is a compiler error without Zephyr
promoting the diagnostic through -Werror.
The full application build produced 66 diagnostics across 20 source
files, all limited to vldrwq_s32 and vldrwq_z_s32.
Suggested compatibility fix
Add a narrowly gated workaround immediately after including
arm_mve.h in Include/Internal/arm_nn_compiler.h:
#if defined(__ZEPHYR__) && defined(__GNUC__) && \
!defined(__clang__) && (__GNUC__ >= 15)
#define vldrwq_s32(base) \
vldrwq_s32((const long int *)(base))
#define vldrwq_z_s32(base, p) \
vldrwq_z_s32((const long int *)(base), (p))
#endif
Macro recursion suppression leaves the inner token referring to GCC's
intrinsic. The guard prevents any change in non-Zephyr builds, where
GCC's native int32_t already matches the intrinsic.
On AArch32 MVE, int and long int are both 32-bit and have identical
alignment. The cast does not alter the address or generated load:
representative output remains a single vldrw.32.
This should be treated as a GCC 15/Zephyr compatibility shim. The
underlying long-term fix is for GCC's generated signature to agree with
the translation unit's visible int32_t, or for Zephyr to revise its
compiler type override.
Validation
With the suggested workaround:
- The complete application builds with Arm GNU GCC 15.2.1.
- The complete application still builds with Zephyr SDK GCC 14.3.0.
- All previously failing MVE kernels compile.
- A representative GCC 15 kernel also compiles with strict aliasing
enabled.
Both application builds used effective -Ofast. This avoids conflating
the issue with the separate GCC 14 internal compiler error seen in some
F16 convolution files at module-local -O2 or -O3.
Summary
GCC 15 fails to compile MVE kernels in a Zephyr build because its
pragma-generated
vldrwq_s32intrinsics retain the compiler-nativelong intpointer type while Zephyr exposesint32_tasint.This was reproduced with:
apollo510_evbThe same sources compile normally with GCC 15 outside Zephyr.
Root cause
Zephyr force-includes
zephyr_stdint.h, which changes:Consequently,
int32_t *isint *in the Zephyr translation unit.GCC 14's
arm_mve.hdeclares the intrinsic textually:That declaration follows Zephyr's visible
int32_t, so the call sitescompile.
GCC 15 changed
arm_mve.hto pragma-generated intrinsics:#pragma GCC arm "arm_mve.h" falseThe generated declarations retain these compiler-native signatures:
Calls using
int32_t *therefore fail with-Wincompatible-pointer-types. This is a compiler error without Zephyrpromoting the diagnostic through
-Werror.The full application build produced 66 diagnostics across 20 source
files, all limited to
vldrwq_s32andvldrwq_z_s32.Suggested compatibility fix
Add a narrowly gated workaround immediately after including
arm_mve.hinInclude/Internal/arm_nn_compiler.h:Macro recursion suppression leaves the inner token referring to GCC's
intrinsic. The guard prevents any change in non-Zephyr builds, where
GCC's native
int32_talready matches the intrinsic.On AArch32 MVE,
intandlong intare both 32-bit and have identicalalignment. The cast does not alter the address or generated load:
representative output remains a single
vldrw.32.This should be treated as a GCC 15/Zephyr compatibility shim. The
underlying long-term fix is for GCC's generated signature to agree with
the translation unit's visible
int32_t, or for Zephyr to revise itscompiler type override.
Validation
With the suggested workaround:
enabled.
Both application builds used effective
-Ofast. This avoids conflatingthe issue with the separate GCC 14 internal compiler error seen in some
F16 convolution files at module-local
-O2or-O3.