// 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++;
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.
/// 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
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(
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(...)