1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-23 11:13:28 +01:00

[WebAssembly] Don't write SP back when prolog is generated only for EH

Summary:
When we don't actually have stack-allocated variables but need SP only
to support EH, we don't need to write SP back in the epilog, because we
don't bump down the stack pointer.

Reviewers: dschuff

Subscribers: jgravelle-google, sbc100, sunfish, llvm-commits

Differential Revision: https://reviews.llvm.org/D51114

llvm-svn: 340454
This commit is contained in:
Heejin Ahn 2018-08-22 21:13:49 +00:00
parent 05de5c7fdc
commit 986b1b55cb
4 changed files with 54 additions and 5 deletions

View File

@ -68,6 +68,11 @@ bool WebAssemblyEHRestoreStackPointer::runOnMachineFunction(
// pad, after the catch instruction. (Catch instructions may have been
// reordered, and catch_all instructions have not been inserted yet, but
// those cases are handled in LateEHPrepare).
//
// Here it is safe to assume that SP32 holds the latest value of
// __stack_pointer, because the only exception for this case is when a
// function uses the red zone, but that only happens with leaf functions,
// and we don't restore __stack_pointer in leaf functions anyway.
auto InsertPos = MBB.begin();
if (WebAssembly::isCatch(*MBB.begin()))
InsertPos++;

View File

@ -79,6 +79,14 @@ bool WebAssemblyFrameLowering::hasReservedCallFrame(
return !MF.getFrameInfo().hasVarSizedObjects();
}
// Returns true if this function needs a local user-space stack pointer for its
// local frame (not for exception handling).
bool WebAssemblyFrameLowering::needsSPForLocalFrame(
const MachineFunction &MF) const {
auto &MFI = MF.getFrameInfo();
return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF);
}
// In function with EH pads, we need to make a copy of the value of
// __stack_pointer global in SP32 register, in order to use it when restoring
// __stack_pointer after an exception is caught.
@ -93,9 +101,7 @@ bool WebAssemblyFrameLowering::needsPrologForEH(
/// Unlike a machine stack pointer, the wasm user stack pointer is a global
/// variable, so it is loaded into a register in the prolog.
bool WebAssemblyFrameLowering::needsSP(const MachineFunction &MF) const {
auto &MFI = MF.getFrameInfo();
return MFI.getStackSize() || MFI.adjustsStack() || hasFP(MF) ||
needsPrologForEH(MF);
return needsSPForLocalFrame(MF) || needsPrologForEH(MF);
}
/// Returns true if the local user-space stack pointer needs to be written back
@ -106,8 +112,16 @@ bool WebAssemblyFrameLowering::needsSPWriteback(
const MachineFunction &MF) const {
auto &MFI = MF.getFrameInfo();
assert(needsSP(MF));
return MFI.getStackSize() > RedZoneSize || MFI.hasCalls() ||
MF.getFunction().hasFnAttribute(Attribute::NoRedZone);
// When we don't need a local stack pointer for its local frame but only to
// support EH, we don't need to write SP back in the epilog, because we don't
// bump down the stack pointer in the prolog. We need to write SP back in the
// epilog only if
// 1. We need SP not only for EH support but also because we actually use
// stack or we have a frame address taken.
// 2. We cannot use the red zone.
bool CanUseRedZone = MFI.getStackSize() <= RedZoneSize && !MFI.hasCalls() &&
!MF.getFunction().hasFnAttribute(Attribute::NoRedZone);
return needsSPForLocalFrame(MF) && !CanUseRedZone;
}
void WebAssemblyFrameLowering::writeSPToGlobal(

View File

@ -56,6 +56,7 @@ class WebAssemblyFrameLowering final : public TargetFrameLowering {
private:
bool hasBP(const MachineFunction &MF) const;
bool needsSPForLocalFrame(const MachineFunction &MF) const;
bool needsSP(const MachineFunction &MF) const;
bool needsSPWriteback(const MachineFunction &MF) const;
};

View File

@ -217,6 +217,35 @@ ehcleanup: ; preds = %catch
cleanupret from %8 unwind to caller
}
; When a function does not have stack-allocated objects, it does not need to
; store SP back to __stack_pointer global at the epilog.
; CHECK-LABEL: no_sp_writeback
; CHECK: try
; CHECK: call foo@FUNCTION
; CHECK: end_try
; CHECK-NOT: set_global __stack_pointer@GLOBAL
; CHECK: return
define void @no_sp_writeback() personality i8* bitcast (i32 (...)* @__gxx_wasm_personality_v0 to i8*) {
entry:
invoke void @foo()
to label %try.cont unwind label %catch.dispatch
catch.dispatch: ; preds = %entry
%0 = catchswitch within none [label %catch.start] unwind to caller
catch.start: ; preds = %catch.dispatch
%1 = catchpad within %0 [i8* null]
%2 = call i8* @llvm.wasm.get.exception(token %1)
%3 = call i32 @llvm.wasm.get.ehselector(token %1)
%4 = call i8* @__cxa_begin_catch(i8* %2) #2 [ "funclet"(token %1) ]
call void @__cxa_end_catch() [ "funclet"(token %1) ]
catchret from %1 to label %try.cont
try.cont: ; preds = %entry, %catch.start
ret void
}
declare void @foo()
declare void @bar(i32*)
declare i32 @__gxx_wasm_personality_v0(...)