Skip to content

Commit 5b79e60

Browse files
committed
[X86] Don't emit unreachable stack adjustments
Summary: This is a minor improvement on our past attempts to do this. Fixes PR43155. Reviewers: hans Subscribers: hiraditya, llvm-commits Tags: #llvm Differential Revision: https://reviews.llvm.org/D66905 llvm-svn: 370409
1 parent 81e458d commit 5b79e60

File tree

3 files changed

+129
-2
lines changed

3 files changed

+129
-2
lines changed

llvm/lib/Target/X86/X86FrameLowering.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2550,6 +2550,18 @@ static unsigned getHiPELiteral(
25502550
+ " required but not provided");
25512551
}
25522552

2553+
// Return true if there are no non-ehpad successors to MBB and there are no
2554+
// non-meta instructions between MBBI and MBB.end().
2555+
bool blockEndIsUnreachable(const MachineBasicBlock &MBB,
2556+
MachineBasicBlock::const_iterator MBBI) {
2557+
return std::all_of(
2558+
MBB.succ_begin(), MBB.succ_end(),
2559+
[](const MachineBasicBlock *Succ) { return Succ->isEHPad(); }) &&
2560+
std::all_of(MBBI, MBB.end(), [](const MachineInstr &MI) {
2561+
return MI.isMetaInstruction();
2562+
});
2563+
}
2564+
25532565
/// Erlang programs may need a special prologue to handle the stack size they
25542566
/// might need at runtime. That is because Erlang/OTP does not implement a C
25552567
/// stack but uses a custom implementation of hybrid stack/heap architecture.
@@ -2783,7 +2795,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
27832795
unsigned Opcode = I->getOpcode();
27842796
bool isDestroy = Opcode == TII.getCallFrameDestroyOpcode();
27852797
DebugLoc DL = I->getDebugLoc();
2786-
uint64_t Amount = !reserveCallFrame ? TII.getFrameSize(*I) : 0;
2798+
uint64_t Amount = TII.getFrameSize(*I);
27872799
uint64_t InternalAmt = (isDestroy || Amount) ? TII.getFrameAdjustment(*I) : 0;
27882800
I = MBB.erase(I);
27892801
auto InsertPos = skipDebugInstructionsForward(I, MBB.end());
@@ -2872,7 +2884,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
28722884
return I;
28732885
}
28742886

2875-
if (isDestroy && InternalAmt) {
2887+
if (isDestroy && InternalAmt && !blockEndIsUnreachable(MBB, I)) {
28762888
// If we are performing frame pointer elimination and if the callee pops
28772889
// something off the stack pointer, add it back. We do this until we have
28782890
// more advanced stack pointer tracking ability.
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
; RUN: llc < %s -mtriple=x86_64-linux-gnu | FileCheck %s
2+
3+
; PR43155, we used to emit dead stack adjustments for noreturn calls with stack
4+
; arguments.
5+
6+
; Original source code:
7+
; __attribute__((noreturn)) void exit_manyarg(int, int, int, int, int, int, int, int, int, int);
8+
; struct ByVal {
9+
; int vals[10];
10+
; };
11+
; struct ByVal getbyval();
12+
; void make_push_unprofitable(struct ByVal);
13+
; int foo(int c) {
14+
; if (c)
15+
; exit_manyarg(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
16+
; make_push_unprofitable(getbyval());
17+
; make_push_unprofitable(getbyval());
18+
; make_push_unprofitable(getbyval());
19+
; return 0;
20+
; }
21+
22+
%struct.ByVal = type { [10 x i32] }
23+
24+
define dso_local i32 @foo(i32 %c) {
25+
entry:
26+
%agg.tmp = alloca %struct.ByVal, align 8
27+
%agg.tmp1 = alloca %struct.ByVal, align 8
28+
%agg.tmp2 = alloca %struct.ByVal, align 8
29+
%tobool = icmp eq i32 %c, 0
30+
br i1 %tobool, label %if.end, label %if.then
31+
32+
if.then: ; preds = %entry
33+
tail call void @exit_manyarg(i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9, i32 10) #3
34+
unreachable
35+
36+
if.end: ; preds = %entry
37+
call void @getbyval(%struct.ByVal* nonnull sret %agg.tmp) #4
38+
call void @make_push_unprofitable(%struct.ByVal* nonnull byval(%struct.ByVal) align 8 %agg.tmp) #4
39+
call void @getbyval(%struct.ByVal* nonnull sret %agg.tmp1) #4
40+
call void @make_push_unprofitable(%struct.ByVal* nonnull byval(%struct.ByVal) align 8 %agg.tmp1) #4
41+
call void @getbyval(%struct.ByVal* nonnull sret %agg.tmp2) #4
42+
call void @make_push_unprofitable(%struct.ByVal* nonnull byval(%struct.ByVal) align 8 %agg.tmp2) #4
43+
ret i32 0
44+
}
45+
46+
; CHECK-LABEL: foo:
47+
; The main body is not important.
48+
; CHECK: callq exit_manyarg
49+
; CHECK-NOT: sub
50+
; CHECK-NOT: add
51+
; CHECK: # -- End function
52+
53+
; Function Attrs: noreturn
54+
declare dso_local void @exit_manyarg(i32, i32, i32, i32, i32, i32, i32, i32, i32, i32) noreturn
55+
56+
declare dso_local void @make_push_unprofitable(%struct.ByVal* byval(%struct.ByVal) align 8)
57+
58+
declare dso_local void @getbyval(%struct.ByVal* sret)
59+

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

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,3 +46,59 @@ if.then:
4646
declare void @crash(i8*) noreturn
4747
declare void @crash2(i8*)
4848
declare void @g(i8*)
49+
50+
%struct.ByVal = type { [10 x i32] }
51+
52+
define dso_local i32 @pr43155() {
53+
entry:
54+
%agg.tmp = alloca %struct.ByVal, align 4
55+
%agg.tmp5 = alloca %struct.ByVal, align 4
56+
%agg.tmp6 = alloca %struct.ByVal, align 4
57+
%call = tail call i32 @cond()
58+
%tobool = icmp eq i32 %call, 0
59+
br i1 %tobool, label %if.end, label %if.then
60+
61+
if.then: ; preds = %entry
62+
tail call x86_stdcallcc void @stdcall_abort(i32 12, i32 2)
63+
unreachable
64+
65+
if.end: ; preds = %entry
66+
%call1 = tail call i32 @cond()
67+
%tobool2 = icmp eq i32 %call1, 0
68+
br i1 %tobool2, label %if.end4, label %if.then3
69+
70+
if.then3: ; preds = %if.end
71+
tail call x86_stdcallcc void @stdcall_abort(i32 15, i32 2)
72+
unreachable
73+
74+
if.end4: ; preds = %if.end
75+
call void @getbyval(%struct.ByVal* nonnull sret %agg.tmp)
76+
call void @make_push_unprofitable(%struct.ByVal* nonnull byval(%struct.ByVal) align 4 %agg.tmp)
77+
call void @getbyval(%struct.ByVal* nonnull sret %agg.tmp5)
78+
call void @make_push_unprofitable(%struct.ByVal* nonnull byval(%struct.ByVal) align 4 %agg.tmp5)
79+
call void @getbyval(%struct.ByVal* nonnull sret %agg.tmp6)
80+
call void @make_push_unprofitable(%struct.ByVal* nonnull byval(%struct.ByVal) align 4 %agg.tmp6)
81+
ret i32 0
82+
}
83+
84+
; Check that there are no stack adjustments after stdcall_abort.
85+
; CHECK-LABEL: pr43155:
86+
; The main function body contents are not important.
87+
; CHECK: retl
88+
; CHECK: # %if.then
89+
; CHECK: calll _stdcall_abort@8
90+
; CHECK-NOT: sub
91+
; CHECK-NOT: add
92+
; CHECK: # %if.then3
93+
; CHECK: calll _stdcall_abort@8
94+
; CHECK-NOT: sub
95+
; CHECK-NOT: add
96+
; CHECK: # -- End function
97+
98+
declare dso_local i32 @cond()
99+
100+
declare dso_local x86_stdcallcc void @stdcall_abort(i32, i32) noreturn
101+
102+
declare dso_local void @make_push_unprofitable(%struct.ByVal* byval(%struct.ByVal) align 4)
103+
104+
declare dso_local void @getbyval(%struct.ByVal* sret)

0 commit comments

Comments
 (0)