From 733508d4e8d70530f9e4753f92c77f042af75e95 Mon Sep 17 00:00:00 2001 From: Reid Kleckner Date: Thu, 9 Jul 2015 22:09:41 +0000 Subject: [PATCH] [WinEH] Give up on using CSRs across 32-bit invokes for now The runtime does not restore CSRs when transferring control back to the function handling the exception. According to the experts on IRC, LLVM's register allocator has no way to model register clobbers that only happen on one edge of the CFG. For now, don't worry about trying to use the meager three CSRs available on 32-bit X86 and just say that such invokes preserve nothing. llvm-svn: 241865 --- lib/Target/X86/X86ISelLowering.cpp | 19 +++++++++-- test/CodeGen/X86/seh-catch-all-win32.ll | 17 ++++++++-- test/CodeGen/X86/win32-eh.ll | 43 +++++++++++++------------ 3 files changed, 54 insertions(+), 25 deletions(-) diff --git a/lib/Target/X86/X86ISelLowering.cpp b/lib/Target/X86/X86ISelLowering.cpp index 74e5dd62ccb..2e689fbe3d9 100644 --- a/lib/Target/X86/X86ISelLowering.cpp +++ b/lib/Target/X86/X86ISelLowering.cpp @@ -3258,9 +3258,24 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI, RegsToPass[i].second.getValueType())); // Add a register mask operand representing the call-preserved registers. - const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); - const uint32_t *Mask = TRI->getCallPreservedMask(MF, CallConv); + const uint32_t *Mask = RegInfo->getCallPreservedMask(MF, CallConv); assert(Mask && "Missing call preserved mask for calling convention"); + + // If this is an invoke in a 32-bit function using an MSVC personality, assume + // the function clobbers all registers. If an exception is thrown, the runtime + // will not restore CSRs. + // FIXME: Model this more precisely so that we can register allocate across + // the normal edge and spill and fill across the exceptional edge. + if (!Is64Bit && CLI.CS && CLI.CS->isInvoke()) { + const Function *CallerFn = MF.getFunction(); + EHPersonality Pers = + CallerFn->hasPersonalityFn() + ? classifyEHPersonality(CallerFn->getPersonalityFn()) + : EHPersonality::Unknown; + if (isMSVCEHPersonality(Pers)) + Mask = RegInfo->getNoPreservedMask(); + } + Ops.push_back(DAG.getRegisterMask(Mask)); if (InFlag.getNode()) diff --git a/test/CodeGen/X86/seh-catch-all-win32.ll b/test/CodeGen/X86/seh-catch-all-win32.ll index d840cb41acc..39906f8fecc 100644 --- a/test/CodeGen/X86/seh-catch-all-win32.ll +++ b/test/CodeGen/X86/seh-catch-all-win32.ll @@ -59,20 +59,31 @@ entry: ; Check that we can get the exception code from eax to the printf. ; CHECK-LABEL: _main: +; CHECK: pushl %ebp +; CHECK: movl %esp, %ebp +; Ensure that we push *all* the CSRs, since they are clobbered by the +; __except block. +; CHECK: pushl %ebx +; CHECK: pushl %edi +; CHECK: pushl %esi + ; CHECK: Lmain$frame_escape_0 = [[code_offs:[-0-9]+]] ; CHECK: Lmain$frame_escape_1 = [[reg_offs:[-0-9]+]] ; CHECK: movl %esp, [[reg_offs]](%ebp) ; CHECK: movl $L__ehtable$main, ; EH state 0 -; CHECK: movl $0, -4(%ebp) +; CHECK: movl $0, -16(%ebp) ; CHECK: calll _crash +; CHECK: popl %esi +; CHECK: popl %edi +; CHECK: popl %ebx ; CHECK: retl ; CHECK: # Block address taken ; stackrestore -; CHECK: movl [[reg_offs]](%ebp), %esp +; CHECK: movl -24(%ebp), %esp ; EH state -1 ; CHECK: movl [[code_offs]](%ebp), %[[code:[a-z]+]] -; CHECK: movl $-1, -4(%ebp) +; CHECK: movl $-1, -16(%ebp) ; CHECK-DAG: movl %[[code]], 4(%esp) ; CHECK-DAG: movl $_str, (%esp) ; CHECK: calll _printf diff --git a/test/CodeGen/X86/win32-eh.ll b/test/CodeGen/X86/win32-eh.ll index f235d2884d0..199afd07f79 100644 --- a/test/CodeGen/X86/win32-eh.ll +++ b/test/CodeGen/X86/win32-eh.ll @@ -32,16 +32,19 @@ eh.resume: ; CHECK-LABEL: _use_except_handler3: ; CHECK: pushl %ebp ; CHECK: movl %esp, %ebp +; CHECK: pushl %ebx +; CHECK: pushl %edi +; CHECK: pushl %esi ; CHECK: subl ${{[0-9]+}}, %esp -; CHECK: movl $-1, -4(%ebp) -; CHECK: movl $L__ehtable$use_except_handler3, -8(%ebp) -; CHECK: leal -16(%ebp), %[[node:[^ ,]*]] -; CHECK: movl $__except_handler3, -12(%ebp) +; CHECK: movl $-1, -16(%ebp) +; CHECK: movl $L__ehtable$use_except_handler3, -20(%ebp) +; CHECK: leal -28(%ebp), %[[node:[^ ,]*]] +; CHECK: movl $__except_handler3, -24(%ebp) ; CHECK: movl %fs:0, %[[next:[^ ,]*]] -; CHECK: movl %[[next]], -16(%ebp) +; CHECK: movl %[[next]], -28(%ebp) ; CHECK: movl %[[node]], %fs:0 ; CHECK: calll _may_throw_or_crash -; CHECK: movl -16(%ebp), %[[next:[^ ,]*]] +; CHECK: movl -28(%ebp), %[[next:[^ ,]*]] ; CHECK: movl %[[next]], %fs:0 ; CHECK: retl @@ -72,18 +75,18 @@ eh.resume: ; CHECK: pushl %ebp ; CHECK: movl %esp, %ebp ; CHECK: subl ${{[0-9]+}}, %esp -; CHECK: movl %esp, -24(%ebp) -; CHECK: movl $-2, -4(%ebp) +; CHECK: movl %esp, -36(%ebp) +; CHECK: movl $-2, -16(%ebp) ; CHECK: movl $L__ehtable$use_except_handler4, %[[lsda:[^ ,]*]] ; CHECK: xorl ___security_cookie, %[[lsda]] -; CHECK: movl %[[lsda]], -8(%ebp) -; CHECK: leal -16(%ebp), %[[node:[^ ,]*]] -; CHECK: movl $__except_handler4, -12(%ebp) +; CHECK: movl %[[lsda]], -20(%ebp) +; CHECK: leal -28(%ebp), %[[node:[^ ,]*]] +; CHECK: movl $__except_handler4, -24(%ebp) ; CHECK: movl %fs:0, %[[next:[^ ,]*]] -; CHECK: movl %[[next]], -16(%ebp) +; CHECK: movl %[[next]], -28(%ebp) ; CHECK: movl %[[node]], %fs:0 ; CHECK: calll _may_throw_or_crash -; CHECK: movl -16(%ebp), %[[next:[^ ,]*]] +; CHECK: movl -28(%ebp), %[[next:[^ ,]*]] ; CHECK: movl %[[next]], %fs:0 ; CHECK: retl @@ -115,16 +118,16 @@ catchall: ; CHECK: pushl %ebp ; CHECK: movl %esp, %ebp ; CHECK: subl ${{[0-9]+}}, %esp -; CHECK: movl %esp, -16(%ebp) -; CHECK: movl $-1, -4(%ebp) -; CHECK: leal -12(%ebp), %[[node:[^ ,]*]] -; CHECK: movl $___ehhandler$use_CxxFrameHandler3, -8(%ebp) +; CHECK: movl %esp, -28(%ebp) +; CHECK: movl $-1, -16(%ebp) +; CHECK: leal -24(%ebp), %[[node:[^ ,]*]] +; CHECK: movl $___ehhandler$use_CxxFrameHandler3, -20(%ebp) ; CHECK: movl %fs:0, %[[next:[^ ,]*]] -; CHECK: movl %[[next]], -12(%ebp) +; CHECK: movl %[[next]], -24(%ebp) ; CHECK: movl %[[node]], %fs:0 -; CHECK: movl $0, -4(%ebp) +; CHECK: movl $0, -16(%ebp) ; CHECK: calll _may_throw_or_crash -; CHECK: movl -12(%ebp), %[[next:[^ ,]*]] +; CHECK: movl -24(%ebp), %[[next:[^ ,]*]] ; CHECK: movl %[[next]], %fs:0 ; CHECK: retl