Skip to content

Commit e33204e

Browse files
committed
[CodeGen][WinEH] Update saved esp for inlined inallocas
This fixes issue #116583 When inalloca calls are inlined the static stack pointer saving prolog of X86WinEHState breaks due to dynamic allocas. In this case we need to update the saved esp for every inalloca and for every stackrestore also related to inalloca.
1 parent b4c0ef1 commit e33204e

File tree

2 files changed

+123
-3
lines changed

2 files changed

+123
-3
lines changed

llvm/lib/Target/X86/X86WinEHState.cpp

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include "llvm/IR/Function.h"
2424
#include "llvm/IR/IRBuilder.h"
2525
#include "llvm/IR/Instructions.h"
26+
#include "llvm/IR/IntrinsicInst.h"
2627
#include "llvm/IR/Intrinsics.h"
2728
#include "llvm/IR/IntrinsicsX86.h"
2829
#include "llvm/IR/Module.h"
@@ -75,6 +76,8 @@ class WinEHStatePass : public FunctionPass {
7576
int getStateForCall(DenseMap<BasicBlock *, ColorVector> &BlockColors,
7677
WinEHFuncInfo &FuncInfo, CallBase &Call);
7778

79+
void updateEspForInAllocas(Function &F);
80+
7881
// Module-level type getters.
7982
Type *getEHLinkRegistrationType();
8083
Type *getSEHRegistrationType();
@@ -100,6 +103,9 @@ class WinEHStatePass : public FunctionPass {
100103
/// fs:00 chain and the current state.
101104
AllocaInst *RegNode = nullptr;
102105

106+
// Struct type of RegNode. Used for GEPing.
107+
Type *RegNodeTy = nullptr;
108+
103109
// The allocation containing the EH security guard.
104110
AllocaInst *EHGuardNode = nullptr;
105111

@@ -188,11 +194,13 @@ bool WinEHStatePass::runOnFunction(Function &F) {
188194
// numbers into an immutable analysis pass.
189195
WinEHFuncInfo FuncInfo;
190196
addStateStores(F, FuncInfo);
197+
updateEspForInAllocas(F);
191198

192199
// Reset per-function state.
193200
PersonalityFn = nullptr;
194201
Personality = EHPersonality::Unknown;
195202
UseStackGuard = false;
203+
RegNodeTy = nullptr;
196204
RegNode = nullptr;
197205
EHGuardNode = nullptr;
198206

@@ -269,9 +277,6 @@ void WinEHStatePass::emitExceptionRegistrationRecord(Function *F) {
269277
assert(Personality == EHPersonality::MSVC_CXX ||
270278
Personality == EHPersonality::MSVC_X86SEH);
271279

272-
// Struct type of RegNode. Used for GEPing.
273-
Type *RegNodeTy;
274-
275280
IRBuilder<> Builder(&F->getEntryBlock(), F->getEntryBlock().begin());
276281
Type *Int8PtrType = Builder.getPtrTy();
277282
Type *Int32Ty = Builder.getInt32Ty();
@@ -774,3 +779,28 @@ void WinEHStatePass::insertStateNumberStore(Instruction *IP, int State) {
774779
RegNode, StateFieldIndex);
775780
Builder.CreateStore(Builder.getInt32(State), StateField);
776781
}
782+
783+
void WinEHStatePass::updateEspForInAllocas(Function& F)
784+
{
785+
for (BasicBlock& BB : F) {
786+
for (Instruction &I : BB) {
787+
if (auto* Alloca = dyn_cast<AllocaInst>(&I)) {
788+
if (!Alloca->isUsedWithInAlloca())
789+
continue;
790+
IRBuilder<> Builder(Alloca->getNextNonDebugInstruction());
791+
// SavedESP = llvm.stacksave()
792+
Value *SP = Builder.CreateStackSave();
793+
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
794+
}
795+
796+
if (auto* II = dyn_cast<IntrinsicInst>(&I)) {
797+
if (II->getIntrinsicID() != Intrinsic::stackrestore)
798+
continue;
799+
IRBuilder<> Builder(II->getNextNonDebugInstruction());
800+
// SavedESP = llvm.stacksave()
801+
Value *SP = Builder.CreateStackSave();
802+
Builder.CreateStore(SP, Builder.CreateStructGEP(RegNodeTy, RegNode, 0));
803+
}
804+
}
805+
}
806+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
2+
; RUN: llc < %s | FileCheck %s
3+
target datalayout = "e-m:x-p:32:32-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32-a:0:32-S32"
4+
target triple = "i386-pc-windows-msvc"
5+
6+
%struct.Foo = type { i32, i32 }
7+
8+
define dso_local noundef i32 @foo() local_unnamed_addr #0 personality ptr @__CxxFrameHandler3 {
9+
; CHECK-LABEL: foo:
10+
; CHECK: # %bb.0: # %entry
11+
; CHECK-NEXT: pushl %ebp
12+
; CHECK-NEXT: movl %esp, %ebp
13+
; CHECK-NEXT: pushl %ebx
14+
; CHECK-NEXT: pushl %edi
15+
; CHECK-NEXT: pushl %esi
16+
; CHECK-NEXT: subl $16, %esp
17+
; CHECK-NEXT: movl %esp, -28(%ebp)
18+
; CHECK-NEXT: movl $-1, -16(%ebp)
19+
; CHECK-NEXT: leal -24(%ebp), %eax
20+
; CHECK-NEXT: movl $___ehhandler$foo, -20(%ebp)
21+
; CHECK-NEXT: movl %fs:0, %ecx
22+
; CHECK-NEXT: movl %ecx, -24(%ebp)
23+
; CHECK-NEXT: movl %eax, %fs:0
24+
; CHECK-NEXT: pushl %eax
25+
; CHECK-NEXT: pushl %eax
26+
; CHECK-NEXT: movl %esp, %ecx
27+
; CHECK-NEXT: movl %esp, -28(%ebp)
28+
; CHECK-NEXT: movl $123, (%ecx)
29+
; CHECK-NEXT: calll _bar
30+
; CHECK-NEXT: movl $0, -16(%ebp)
31+
; CHECK-NEXT: calll _alwaysthrows
32+
; CHECK-NEXT: # %bb.3: # %unreachable.i
33+
; CHECK-NEXT: LBB0_2: # Block address taken
34+
; CHECK-NEXT: # %catch.i
35+
; CHECK-NEXT: addl $12, %ebp
36+
; CHECK-NEXT: jmp LBB0_4
37+
; CHECK-NEXT: LBB0_4: # %exit
38+
; CHECK-NEXT: $ehgcr_0_4:
39+
; CHECK-NEXT: movl -24(%ebp), %eax
40+
; CHECK-NEXT: movl %eax, %fs:0
41+
; CHECK-NEXT: xorl %eax, %eax
42+
; CHECK-NEXT: leal -12(%ebp), %esp
43+
; CHECK-NEXT: popl %esi
44+
; CHECK-NEXT: popl %edi
45+
; CHECK-NEXT: popl %ebx
46+
; CHECK-NEXT: popl %ebp
47+
; CHECK-NEXT: retl
48+
; CHECK-NEXT: .def "?catch$1@?0?foo@4HA";
49+
; CHECK-NEXT: .scl 3;
50+
; CHECK-NEXT: .type 32;
51+
; CHECK-NEXT: .endef
52+
; CHECK-NEXT: .p2align 4
53+
; CHECK-NEXT: "?catch$1@?0?foo@4HA":
54+
; CHECK-NEXT: LBB0_1: # %catch.i
55+
; CHECK-NEXT: pushl %ebp
56+
; CHECK-NEXT: addl $12, %ebp
57+
; CHECK-NEXT: movl %esp, -28(%ebp)
58+
; CHECK-NEXT: movl $LBB0_2, %eax
59+
; CHECK-NEXT: popl %ebp
60+
; CHECK-NEXT: retl # CATCHRET
61+
; CHECK-NEXT: Lfunc_end0:
62+
entry:
63+
%argmem = alloca inalloca <{ %struct.Foo }>, align 4
64+
store i32 123, ptr %argmem, align 4
65+
call x86_thiscallcc void @bar(ptr noundef nonnull align 4 dereferenceable(8) %argmem)
66+
invoke void @alwaysthrows() #1
67+
to label %unreachable.i unwind label %catch.dispatch.i
68+
69+
catch.dispatch.i: ; preds = %entry
70+
%3 = catchswitch within none [label %catch.i] unwind to caller
71+
72+
catch.i: ; preds = %catch.dispatch.i
73+
%4 = catchpad within %3 [ptr null, i32 64, ptr null]
74+
catchret from %4 to label %exit
75+
76+
unreachable.i: ; preds = %entry
77+
unreachable
78+
79+
exit: ; preds = %catch.i
80+
ret i32 0
81+
}
82+
83+
declare dso_local x86_thiscallcc void @bar(ptr noundef nonnull align 4 dereferenceable(8) %this) local_unnamed_addr
84+
85+
declare dso_local i32 @__CxxFrameHandler3(...)
86+
87+
declare dso_local void @alwaysthrows() local_unnamed_addr
88+
89+
attributes #0 = { norecurse "min-legal-vector-width"="0" "target-cpu"="pentium4" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
90+
attributes #1 = { noreturn }

0 commit comments

Comments
 (0)