Skip to content

Commit 13b720d

Browse files
authored
[win][x64] Re-use fixed object if multiple catchpads use the same alloca for their catch objects (#147849)
Addresses <#147421 (comment)> for x86 If more than one `catchpad ` uses the same `alloca` for their catch objects, then we will allocate more than one object in the fixed area resulting in wasted stack space. As a follow up, Clang could be updated to re-use the same `alloca` for all by-reference and by-pointer catch objects.
1 parent 4b52d22 commit 13b720d

File tree

2 files changed

+101
-1
lines changed

2 files changed

+101
-1
lines changed

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4241,7 +4241,7 @@ void X86FrameLowering::adjustFrameForMsvcCxxEh(MachineFunction &MF) const {
42414241
for (WinEHTryBlockMapEntry &TBME : EHInfo.TryBlockMap) {
42424242
for (WinEHHandlerType &H : TBME.HandlerArray) {
42434243
int FrameIndex = H.CatchObj.FrameIndex;
4244-
if (FrameIndex != INT_MAX) {
4244+
if ((FrameIndex != INT_MAX) && MFI.getObjectOffset(FrameIndex) == 0) {
42454245
// Ensure alignment.
42464246
unsigned Align = MFI.getObjectAlign(FrameIndex).value();
42474247
MinFixedObjOffset -= std::abs(MinFixedObjOffset) % Align;
Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
; RUN: llc %s --mtriple=x86_64-pc-windows-msvc -o - | FileCheck %s
2+
3+
; Tests the fixed object layouts when two catchpads re-use the same stack
4+
; allocation for this catch objects.
5+
6+
; Generated from this C++ code, with modifications to the IR (see comments in
7+
; IR):
8+
; https://godbolt.org/z/9qv5Yn68j
9+
; > clang --target=x86_64-pc-windows-msvc test.cpp
10+
; ```
11+
; extern "C" void boom();
12+
; extern "C" int calls_boom();
13+
; {
14+
; try { boom(); }
15+
; catch (int& i) { return i; }
16+
; catch (long& l) { return l; }
17+
; return 0;
18+
; }
19+
; ```
20+
21+
; Minimum stack alloc is 64 bytes, so no change there.
22+
; CHECK-LABEL: calls_boom:
23+
; CHECK: subq $64, %rsp
24+
; CHECK: .seh_stackalloc 64
25+
26+
; Both the catch blocks load from the same address.
27+
; CHECK-LABEL: "?catch$3@?0?calls_boom@4HA":
28+
; CHECK: movq -8(%rbp), %rax
29+
; CHECK-LABEL: "?catch$4@?0?calls_boom@4HA":
30+
; CHECK: movq -8(%rbp), %rax
31+
32+
; There's enough space for the UnwindHelp to be at 48 instead of 40
33+
; CHECK-LABEL: $cppxdata$calls_boom:
34+
; CHECK: .long 48 # UnwindHelp
35+
36+
; Both catches have the same object offset.
37+
; CHECK-LABEL: $handlerMap$0$calls_boom:
38+
; CHECK: .long 56 # CatchObjOffset
39+
; CHECK-NEXT: .long "?catch$3@?0?calls_boom@4HA"@IMGREL # Handler
40+
; CHECK: .long 56 # CatchObjOffset
41+
; CHECK-NEXT: .long "?catch$4@?0?calls_boom@4HA"@IMGREL # Handler
42+
43+
%rtti.TypeDescriptor2 = type { ptr, ptr, [3 x i8] }
44+
45+
$"??_R0H@8" = comdat any
46+
47+
$"??_R0J@8" = comdat any
48+
49+
@"??_7type_info@@6B@" = external constant ptr
50+
@"??_R0H@8" = linkonce_odr global %rtti.TypeDescriptor2 { ptr @"??_7type_info@@6B@", ptr null, [3 x i8] c".H\00" }, comdat
51+
@"??_R0J@8" = linkonce_odr global %rtti.TypeDescriptor2 { ptr @"??_7type_info@@6B@", ptr null, [3 x i8] c".J\00" }, comdat
52+
53+
define dso_local i32 @calls_boom() personality ptr @__CxxFrameHandler3 {
54+
entry:
55+
%retval = alloca i32, align 4
56+
; MODIFICATION: Remove unusued alloca
57+
; %l = alloca ptr, align 8
58+
%i = alloca ptr, align 8
59+
invoke void @boom()
60+
to label %invoke.cont unwind label %catch.dispatch
61+
62+
catch.dispatch:
63+
%0 = catchswitch within none [label %catch1, label %catch] unwind to caller
64+
65+
catch1:
66+
%1 = catchpad within %0 [ptr @"??_R0H@8", i32 8, ptr %i]
67+
%2 = load ptr, ptr %i, align 8
68+
%3 = load i32, ptr %2, align 4
69+
store i32 %3, ptr %retval, align 4
70+
catchret from %1 to label %catchret.dest2
71+
72+
catch:
73+
; MODIFICATION: Use %i instead of %l
74+
%4 = catchpad within %0 [ptr @"??_R0J@8", i32 8, ptr %i]
75+
%5 = load ptr, ptr %i, align 8
76+
%6 = load i32, ptr %5, align 4
77+
store i32 %6, ptr %retval, align 4
78+
catchret from %4 to label %catchret.dest
79+
80+
invoke.cont:
81+
br label %try.cont
82+
83+
catchret.dest:
84+
br label %return
85+
86+
catchret.dest2:
87+
br label %return
88+
89+
try.cont:
90+
store i32 0, ptr %retval, align 4
91+
br label %return
92+
93+
return:
94+
%7 = load i32, ptr %retval, align 4
95+
ret i32 %7
96+
}
97+
98+
declare dso_local void @boom() #1
99+
100+
declare dso_local i32 @__CxxFrameHandler3(...)

0 commit comments

Comments
 (0)