llvm / llvm/llvm-project

[libc][LLVM] vector va_arg miscompilation on MVE target (Cortex-M85)

Open
#220,447 4 comments 0 reactions 1 assignee Claimed by @linisha15 View on GitHub
libc llvm:codegen miscompilation
Dominant language
LLVM
Stars
40.5k
Forks
18.7k
PR merge metrics
PR metrics pending

Description

> Found when running semihosting libc tests with https://github.com/SchrodingerZhu/llvm-libc-ra8xx-test

> **Bug example produced and reduced by Claude Fable 5**

## Libc side report

The following `va_arg` test fails when running on cortex-m85 targets (with MVE)

```c++
#if !defined(LIBC_TARGET_OS_IS_WINDOWS) && __has_attribute(ext_vector_type)

using int1 = int __attribute__((ext_vector_type(1)));
using int2 = int __attribute__((ext_vector_type(2)));
using int3 = int __attribute__((ext_vector_type(3)));
using int4 = int __attribute__((ext_vector_type(4)));

int check_vector_type(int first, ...) {
va_list vlist;
va_start(vlist, first);
LIBC_NAMESPACE::internal::ArgList args(vlist);
va_end(vlist);

int1 v1 = args.next_var();
int2 v2 = args.next_var();
int3 v3 = args.next_var();
int4 v4 = args.next_var();

return v1.x + v2.x + v2.y + v3.x + v3.y + v3.z + v4.x + v4.y + v4.z + v4.w;
}

TEST(LlvmLibcArgListTest, TestVectorTypes) {
int1 v1 = {1};
int2 v2 = {1, 2};
int3 v3 = {1, 2, 3};
int4 v4 = {1, 2, 3, 4};
ASSERT_EQ(check_vector_type(0, v1, v2, v3, v4), 20);
}

#endif
```

## Reduced Example

```ll
; llc -mtriple=thumbv8.1m.main-none-eabi -mattr=+mve.fp vararg_vec.ll -o -
target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64"
target triple = "thumbv8.1m.main-none-unknown-eabi"

declare i32 @sum2(i32, ...)

define i32 @caller() {
entry:
%r = tail call i32 (i32, ...) @sum2(i32 0, <2 x i32> )
ret i32 %r
}
```
compiles to
```asm
caller: @ @caller
.fnstart
@ %bb.0: @ %entry
.save {r7, lr}
push {r7, lr}
.pad #8
sub sp, #8
adr r0, .LCPI0_0
vldrw.u32 q0, [r0]
movs r0, #0
vmov r2, r3, d0
vstr d1, [sp]
bl sum2
add sp, #8
pop {r7, pc
```
The problem happens at
```
vldrw.u32 q0, [r0]
```
where the vector gets widen to `{1, 0, 2, 0}` and then broken down into `d0, d1` in later call.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.