From 964d1fe44b6f578e0e4bcb36c120c1a4749ff12d Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Wed, 7 Oct 2015 23:55:01 +0000 Subject: [PATCH] [WinEH] Fix 32-bit funclet epilogues in the presence of dynamic allocas In particular, passing non-trivially copyable objects by value on win32 uses a dynamic alloca (inalloca). We would clobber ESP in the epilogue and end up returning to outer space. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@249637 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/X86/X86FrameLowering.cpp | 7 ++- test/CodeGen/X86/cleanuppad-inalloca.ll | 68 +++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 test/CodeGen/X86/cleanuppad-inalloca.ll diff --git a/lib/Target/X86/X86FrameLowering.cpp b/lib/Target/X86/X86FrameLowering.cpp index fc314d76c64..7f05e5b3b13 100644 --- a/lib/Target/X86/X86FrameLowering.cpp +++ b/lib/Target/X86/X86FrameLowering.cpp @@ -1057,6 +1057,7 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF, bool IsWin64Prologue = MF.getTarget().getMCAsmInfo()->usesWindowsCFI(); bool NeedsWinCFI = IsWin64Prologue && MF.getFunction()->needsUnwindTableEntry(); + bool IsFunclet = isFuncletReturnInstr(MBBI); // Get the number of bytes to allocate from the FrameInfo. uint64_t StackSize = MFI->getStackSize(); @@ -1170,8 +1171,10 @@ void X86FrameLowering::emitEpilogue(MachineFunction &MF, // If dynamic alloca is used, then reset esp to point to the last callee-saved // slot before popping them off! Same applies for the case, when stack was - // realigned. - if (TRI->needsStackRealignment(MF) || MFI->hasVarSizedObjects()) { + // realigned. Don't do this if this was a funclet epilogue, since the funclets + // will not do realignment or dynamic stack allocation. + if ((TRI->needsStackRealignment(MF) || MFI->hasVarSizedObjects()) && + !IsFunclet) { if (TRI->needsStackRealignment(MF)) MBBI = FirstCSPop; unsigned SEHFrameOffset = calculateSetFPREG(SEHStackAllocAmt); diff --git a/test/CodeGen/X86/cleanuppad-inalloca.ll b/test/CodeGen/X86/cleanuppad-inalloca.ll new file mode 100644 index 00000000000..8858f3704a1 --- /dev/null +++ b/test/CodeGen/X86/cleanuppad-inalloca.ll @@ -0,0 +1,68 @@ +; RUN: llc < %s | FileCheck %s + +; Based on this C++: +; struct A { +; int x; +; A(); +; A(const A &a); +; ~A(); +; }; +; extern "C" void takes_two(A a1, A a2); +; extern "C" void passes_two() { takes_two(A(), A()); } + +target datalayout = "e-m:x-p:32:32-i64:64-f80:32-n8:16:32-a:0:32-S32" +target triple = "i686--windows-msvc" + +%struct.A = type { i32 } + +define void @passes_two() #0 personality i8* bitcast (i32 (...)* @__CxxFrameHandler3 to i8*) { +entry: + %argmem = alloca inalloca <{ %struct.A, %struct.A }>, align 4 + %0 = getelementptr inbounds <{ %struct.A, %struct.A }>, <{ %struct.A, %struct.A }>* %argmem, i32 0, i32 1 + %call = call x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %0) + %1 = getelementptr inbounds <{ %struct.A, %struct.A }>, <{ %struct.A, %struct.A }>* %argmem, i32 0, i32 0 + %call1 = invoke x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* %1) + to label %invoke.cont unwind label %ehcleanup + +invoke.cont: ; preds = %entry + call void @takes_two(<{ %struct.A, %struct.A }>* inalloca nonnull %argmem) + ret void + +ehcleanup: ; preds = %entry + %2 = cleanuppad [] + call x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A* %0) + cleanupret %2 unwind to caller +} + +; CHECK: _passes_two: +; CHECK: pushl %ebp +; CHECK: movl %esp, %ebp +; CHECK: subl ${{[0-9]+}}, %esp +; CHECK: movl $8, %eax +; CHECK: calll __chkstk +; CHECK: calll "??0A@@QAE@XZ" +; CHECK: calll "??0A@@QAE@XZ" +; CHECK: calll _takes_two +; ESP must be restored via EBP due to "dynamic" alloca. +; CHECK: leal -{{[0-9]+}}(%ebp), %esp +; CHECK: popl %ebp +; CHECK: retl + +; CHECK: "?dtor$2@?0?passes_two@4HA": +; CHECK: pushl %ebp +; CHECK: subl $8, %esp +; CHECK: addl $12, %ebp +; CHECK: {{movl|leal}} -{{[0-9]+}}(%ebp), %ecx +; CHECK: calll "??1A@@QAE@XZ" +; CHECK: addl $8, %esp +; CHECK: retl + +declare void @takes_two(<{ %struct.A, %struct.A }>* inalloca) #0 + +declare x86_thiscallcc %struct.A* @"\01??0A@@QAE@XZ"(%struct.A* returned) #0 + +declare i32 @__CxxFrameHandler3(...) + +declare x86_thiscallcc void @"\01??1A@@QAE@XZ"(%struct.A*) #0 + +attributes #0 = { "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="false" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" } -- 2.34.1