Skip to content

Commit 65b2128

Browse files
committed
Avoid emitting unreachable SP adjustments after throw
In 172eee9, we tried to avoid these by modelling the callee as internally resetting the stack pointer. However, for the majority of functions with reserved stack frames, this would lead LLVM to emit extra SP adjustments to undo the callee's internal adjustment. This lead us to fix the problem further on down the pipeline in eliminateCallFramePseudoInstr. In 5b79e60, I added use a heuristic to try to detect when the adjustment would be unreachable. This heuristic is imperfect, and when exception handling is involved, it fails to fire. The new test is an example of this. Simply throwing an exception with an active cleanup emits dead SP adjustments after the throw. Not only are they dead, but if they were executed, they would be incorrect, so they are confusing. This change essentially reverts 172eee9 and makes the 5b79e60 heuristic responsible for preventing unreachable stack adjustments. This means we may emit unreachable stack adjustments for functions using EH with unreserved call frames, but that is not very many these days. Back in 2016 when this change was added, we were focused on 32-bit, which we observed to have fewer reserved frames. Fixes PR45064 Reviewed By: hans Differential Revision: https://reviews.llvm.org/D75712
1 parent 59029b9 commit 65b2128

File tree

3 files changed

+65
-13
lines changed

3 files changed

+65
-13
lines changed

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -3009,6 +3009,12 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
30093009
I = MBB.erase(I);
30103010
auto InsertPos = skipDebugInstructionsForward(I, MBB.end());
30113011

3012+
// Try to avoid emitting dead SP adjustments if the block end is unreachable,
3013+
// typically because the function is marked noreturn (abort, throw,
3014+
// assert_fail, etc).
3015+
if (isDestroy && blockEndIsUnreachable(MBB, I))
3016+
return I;
3017+
30123018
if (!reserveCallFrame) {
30133019
// If the stack pointer can be changed after prologue, turn the
30143020
// adjcallstackup instruction into a 'sub ESP, <amt>' and the
@@ -3091,13 +3097,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
30913097
return I;
30923098
}
30933099

3094-
if (isDestroy && InternalAmt && !blockEndIsUnreachable(MBB, I)) {
3095-
// If we are performing frame pointer elimination and if the callee pops
3096-
// something off the stack pointer, add it back. We do this until we have
3097-
// more advanced stack pointer tracking ability.
3098-
// We are not tracking the stack pointer adjustment by the callee, so make
3099-
// sure we restore the stack pointer immediately after the call, there may
3100-
// be spill code inserted between the CALL and ADJCALLSTACKUP instructions.
3100+
if (InternalAmt) {
31013101
MachineBasicBlock::iterator CI = I;
31023102
MachineBasicBlock::iterator B = MBB.begin();
31033103
while (CI != B && !std::prev(CI)->isCall())

llvm/lib/Target/X86/X86ISelLowering.cpp

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4362,12 +4362,6 @@ X86TargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
43624362
else
43634363
NumBytesForCalleeToPop = 0; // Callee pops nothing.
43644364

4365-
if (CLI.DoesNotReturn && !getTargetMachine().Options.TrapUnreachable) {
4366-
// No need to reset the stack after the call if the call doesn't return. To
4367-
// make the MI verify, we'll pretend the callee does it for us.
4368-
NumBytesForCalleeToPop = NumBytes;
4369-
}
4370-
43714365
// Returns a flag for retval copy to use.
43724366
if (!IsSibcall) {
43734367
Chain = DAG.getCALLSEQ_END(Chain,

llvm/test/CodeGen/X86/noreturn-call-win64.ll

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
; RUN: llc < %s -mtriple=x86_64-windows-msvc | FileCheck %s
22

3+
%struct.MakeCleanup = type { i8 }
4+
%eh.ThrowInfo = type { i32, i32, i32, i32 }
5+
36
; Function Attrs: noinline nounwind optnone uwtable
47
define dso_local i32 @foo() {
58
entry:
@@ -51,3 +54,58 @@ declare dso_local i32 @cond()
5154
declare dso_local void @abort1() noreturn
5255
declare dso_local void @abort2() noreturn
5356
declare dso_local void @abort3() noreturn
57+
58+
define dso_local void @throw_exception() uwtable personality i32 (...)* @__CxxFrameHandler3 {
59+
entry:
60+
%o = alloca %struct.MakeCleanup, align 1
61+
%call = invoke i32 @cond()
62+
to label %invoke.cont unwind label %ehcleanup
63+
64+
invoke.cont: ; preds = %entry
65+
%cmp1 = icmp eq i32 0, %call
66+
br i1 %cmp1, label %if.then, label %if.end
67+
68+
if.then: ; preds = %invoke.cont
69+
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null)
70+
to label %unreachable unwind label %ehcleanup
71+
72+
if.end: ; preds = %invoke.cont
73+
%call2 = invoke i32 @cond()
74+
to label %invoke.cont1 unwind label %ehcleanup
75+
76+
invoke.cont1: ; preds = %if.end
77+
%cmp2 = icmp eq i32 0, %call2
78+
br i1 %cmp2, label %if.then3, label %if.end4
79+
80+
if.then3: ; preds = %invoke.cont1
81+
invoke void @_CxxThrowException(i8* null, %eh.ThrowInfo* null)
82+
to label %unreachable unwind label %ehcleanup
83+
84+
if.end4: ; preds = %invoke.cont1
85+
call void @"??1MakeCleanup@@QEAA@XZ"(%struct.MakeCleanup* nonnull %o)
86+
ret void
87+
88+
ehcleanup: ; preds = %if.then3, %if.end, %if.then, %entry
89+
%cp = cleanuppad within none []
90+
call void @"??1MakeCleanup@@QEAA@XZ"(%struct.MakeCleanup* nonnull %o) [ "funclet"(token %cp) ]
91+
cleanupret from %cp unwind to caller
92+
93+
unreachable: ; preds = %if.then3, %if.then
94+
unreachable
95+
}
96+
97+
declare dso_local i32 @__CxxFrameHandler3(...)
98+
declare dso_local void @_CxxThrowException(i8*, %eh.ThrowInfo*)
99+
declare dso_local void @"??1MakeCleanup@@QEAA@XZ"(%struct.MakeCleanup*)
100+
101+
; CHECK-LABEL: throw_exception:
102+
; CHECK: callq cond
103+
; CHECK: je
104+
; CHECK: callq cond
105+
; CHECK: je
106+
; CHECK: retq
107+
; CHECK: callq _CxxThrowException
108+
; CHECK-NOT: {{(addq|subq) .*, %rsp}}
109+
; CHECK: callq _CxxThrowException
110+
; CHECK-NOT: {{(addq|subq) .*, %rsp}}
111+
; CHECK: .seh_handlerdata

0 commit comments

Comments
 (0)