================
@@ -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