================
@@ -0,0 +1,57 @@
+; RUN: llc -mtriple thumbv7-windows-msvc -o - %s
+; XFAIL: *
+
+; FIXME: C++ EH is not supported on thumbv7-windows-msvc yet.
+
+; FIXME: Windows SEH for armv7 does not preserve the frame register R11 in
+; handlers. This may affect C++ EH when accessing arguments on the stack in
+; functions with stack realignment.
+
+; C++ source:
+; struct X { int x[100]; };
+; void f(X x, void (*a)(), void (*g)(int*)) {
+;     alignas(64) int aligned;
+;     try {
+;         a();
+;     } catch (...) {
+;         g(&x.x[11]);
+;     }
+; }
+
+%struct.X = type { [100 x i32] }
+
+define void @"?f@@YAXUX@@P6AXXZP6AXPAH@Z@Z"(ptr byval(%struct.X) align 4 %x, 
ptr %a, ptr %g) personality ptr @__CxxFrameHandler3 {
----------------
trungnt2910 wrote:

TL;DR: If it doesn't go through `llvm.localrecover`, `r11` is used as usual.

Seems like upstream `clang` crashes with your example in MSVC mode: 
https://godbolt.org/z/dMK41o7v3
In MinGW mode, the destructor is inline.

Meanwhile, the build produced by this PR emits an outlined `dtor`:

```asm
"?dtor$2@?0??f@@YAXUX@@P6AXXZ@Z@4HA":
.seh_proc "?dtor$2@?0??f@@YAXUX@@P6AXXZ@Z@4HA"
$MBB0_2:
        sub     sp, #16
        .seh_stackalloc 16
        push    {r4, r5, r6, r7}
        .seh_save_regs  {r4-r7}
        push.w  {r11, lr}
        .seh_save_regs_w        {r11, lr}
        mov     r11, sp
        .seh_save_sp    r11
        .seh_endprologue
        sub     sp, #24
        mov     r4, sp
        bfc     r4, #0, #6
        mov     sp, r4
        add.w   r0, r11, #24
        mov     r1, sp
        adds    r0, #44
        bl      "?g@@YAXPAH0@Z"
        .seh_startepilogue
        mov     sp, r11
        .seh_save_sp    r11
        pop.w   {r11, lr}
        .seh_save_regs_w        {r11, lr}
        pop     {r4, r5, r6, r7}
        .seh_save_regs  {r4-r7}
        add     sp, #16
        .seh_stackalloc 16
        bx      lr
        .seh_nop
        .seh_endepilogue
```

<details>
<summary>Full Assembly</summary>

```cmd
armv7-w64-mingw32-clang++.exe example.cpp -S -o - 
--target=armv7-pc-windows-msvc -O2
```

```asm
        .syntax unified
        .file   "seh.cpp"
        .def    "?f@@YAXUX@@P6AXXZ@Z";
        .scl    2;
        .type   32;
        .endef
        .text
        .globl  "?f@@YAXUX@@P6AXXZ@Z"           @ -- Begin function 
?f@@YAXUX@@P6AXXZ@Z
        .p2align        1
        .code   16
        .thumb_func
"?f@@YAXUX@@P6AXXZ@Z":                  @ @"?f@@YAXUX@@P6AXXZ@Z"
$Mfunc_begin0:
.seh_proc "?f@@YAXUX@@P6AXXZ@Z"
        .seh_handler __CxxFrameHandler3, %unwind, %except
@ %bb.0:
        sub     sp, #16
        .seh_stackalloc 16
        push    {r4, r5, r6, r7}
        .seh_save_regs  {r4-r7}
        push.w  {r11, lr}
        .seh_save_regs_w        {r11, lr}
        mov     r11, sp
        .seh_save_sp    r11
        .seh_endprologue
        sub     sp, #24
        mov     r4, sp
        bfc     r4, #0, #6
        mov     sp, r4
        ldr.w   r5, [r11, #424]
        add.w   r12, r11, #24
        mov     r6, sp
        stm.w   r12, {r0, r1, r2, r3}
$Mtmp0:                                 @ EH_LABEL
        blx     r5
$Mtmp1:                                 @ EH_LABEL
@ %bb.1:
        add.w   r0, r11, #24
        mov     r5, sp
        add.w   r4, r0, #44
        mov     r1, r5
        mov     r0, r4
        bl      "?g@@YAXPAH0@Z"
        mov     r0, r4
        mov     r1, r5
        bl      "?g@@YAXPAH0@Z"
        .seh_startepilogue
        mov     sp, r11
        .seh_save_sp    r11
        pop.w   {r11, lr}
        .seh_save_regs_w        {r11, lr}
        pop     {r4, r5, r6, r7}
        .seh_save_regs  {r4-r7}
        add     sp, #16
        .seh_stackalloc 16
        bx      lr
        .seh_nop
        .seh_endepilogue
        .seh_handlerdata
        .long   "$cppxdata$?f@@YAXUX@@P6AXXZ@Z"@imgrel
        .text
        .seh_endproc
        .def    "?dtor$2@?0??f@@YAXUX@@P6AXXZ@Z@4HA";
        .scl    3;
        .type   32;
        .endef
        .p2align        1
"?dtor$2@?0??f@@YAXUX@@P6AXXZ@Z@4HA":
.seh_proc "?dtor$2@?0??f@@YAXUX@@P6AXXZ@Z@4HA"
$MBB0_2:
        sub     sp, #16
        .seh_stackalloc 16
        push    {r4, r5, r6, r7}
        .seh_save_regs  {r4-r7}
        push.w  {r11, lr}
        .seh_save_regs_w        {r11, lr}
        mov     r11, sp
        .seh_save_sp    r11
        .seh_endprologue
        sub     sp, #24
        mov     r4, sp
        bfc     r4, #0, #6
        mov     sp, r4
        add.w   r0, r11, #24
        mov     r1, sp
        adds    r0, #44
        bl      "?g@@YAXPAH0@Z"
        .seh_startepilogue
        mov     sp, r11
        .seh_save_sp    r11
        pop.w   {r11, lr}
        .seh_save_regs_w        {r11, lr}
        pop     {r4, r5, r6, r7}
        .seh_save_regs  {r4-r7}
        add     sp, #16
        .seh_stackalloc 16
        bx      lr
        .seh_nop
        .seh_endepilogue
$Mfunc_end0:
        .seh_handlerdata
        .text
        .seh_endproc
        .section        .xdata,"dr"
        .p2align        2, 0x0
"$cppxdata$?f@@YAXUX@@P6AXXZ@Z":
        .long   429065506                       @ MagicNumber
        .long   1                               @ MaxState
        .long   "$stateUnwindMap$?f@@YAXUX@@P6AXXZ@Z"@imgrel @ UnwindMap
        .long   0                               @ NumTryBlocks
        .long   0                               @ TryBlockMap
        .long   3                               @ IPMapEntries
        .long   "$ip2state$?f@@YAXUX@@P6AXXZ@Z"@imgrel @ IPToStateXData
        .long   0                               @ ESTypeList
        .long   1                               @ EHFlags
"$stateUnwindMap$?f@@YAXUX@@P6AXXZ@Z":
        .long   -1                              @ ToState
        .long   "?dtor$2@?0??f@@YAXUX@@P6AXXZ@Z@4HA"@imgrel @ Action
"$ip2state$?f@@YAXUX@@P6AXXZ@Z":
        .long   $Mfunc_begin0@imgrel            @ IP
        .long   -1                              @ ToState
        .long   $Mtmp0@imgrel                   @ IP
        .long   0                               @ ToState
        .long   $Mtmp1@imgrel                   @ IP
        .long   -1                              @ ToState
        .text
                                        @ -- End function
        .section        .debug$S,"dr"
        .p2align        2, 0x0
        .long   4                               @ Debug section magic
        .long   241
        .long   $Mtmp3-$Mtmp2                   @ Subsection size
$Mtmp2:
        .short  $Mtmp5-$Mtmp4                   @ Record length
$Mtmp4:
        .short  4353                            @ Record kind: S_OBJNAME
        .long   0                               @ Signature
        .byte   0                               @ Object name
        .p2align        2, 0x0
$Mtmp5:
        .short  $Mtmp7-$Mtmp6                   @ Record length
$Mtmp6:
        .short  4412                            @ Record kind: S_COMPILE3
        .long   16385                           @ Flags and language
        .short  244                             @ CPUType
        .short  23                              @ Frontend version
        .short  0
        .short  0
        .short  0
        .short  23000                           @ Backend version
        .short  0
        .short  0
        .short  0
        .asciz  "clang version 23.0.0git 
(https://github.com/llvm/llvm-project.git 
e1e01df17d51c6d42313afe87c4eb73949b35f49)" @ Null-terminated compiler version 
string
        .p2align        2, 0x0
$Mtmp7:
$Mtmp3:
        .p2align        2, 0x0
        .addrsig
        .addrsig_sym __CxxFrameHandler3
```
</details>

Since this function does not involve any SEH (and involving SEH would upset 
both `clang` and MSVC: https://godbolt.org/z/bhjn5xoeK), `r11` is used as 
usual. When paired with a second `g` call in the main function body and a 
MSVC-compiled `main` function, your example prints:

```
g() reports:
  x[11]   addr: 0021FCBC, val: 1234
  aligned addr: 0021FC40, val: 0
g() reports:
  x[11]   addr: 0021FCBC, val: 1234
  aligned addr: 0021FC40, val: 0
```

<details>
<summary>Full Source Code</summary>

```cpp
struct X { int x[100]; };
void g(int*, int*) noexcept;
#ifdef __clang__
void f(X x, void (*a)()) {
    alignas(64) int aligned;
    struct A {
        X &x;
        int &aligned;
        ~A() {g(&x.x[11], &aligned);}
    } obj = {x, aligned};
    a();
    g(&x.x[11], &aligned);
}
#else
void f(X x, void(*a)());
#endif

#ifndef __clang__
// External C declaration for printf to avoid including <cstdio> or <stdio.h>
extern "C" int printf(const char* format, ...);

// g implementation: marked noinline for MSVC.
// Note: 'aligned' in f() is uninitialized, so printing its value is UB, 
// but for a driver/debug test, we print the raw memory content.
[[msvc::noinline]] 
void g(int* px, int* paligned) noexcept {
    printf("g() reports:\n");
    printf("  x[11]   addr: %p, val: %d\n", (void*)px, *px);
    printf("  aligned addr: %p, val: %d\n", (void*)paligned, *paligned);
}

// a implementation: no-op, marked noinline.
[[msvc::noinline]] 
void my_noop() {
    // No-op
}

int main() {
    X instance = {}; // Zero-initialize for predictable output
    instance.x[11] = 1234;

    // Call f with our driver functions
    f(instance, my_noop);

    return 0;
}
#endif
```
</details>

https://github.com/llvm/llvm-project/pull/184953
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to