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:
parent
05de5c7fdc
commit
986b1b55cb
@ -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++;
|
||||
|
@ -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(
|
||||
|
@ -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;
|
||||
};
|
||||
|
@ -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(...)
|
||||
|
Loading…
Reference in New Issue
Block a user