From dd854ba81b01b3f377a63e1aef2585c79ca7ee47 Mon Sep 17 00:00:00 2001 From: Heejin Ahn Date: Wed, 30 Jan 2019 22:44:45 +0000 Subject: [PATCH] [WebAssembly] Restore stack pointer right after catch instruction Summary: After the staack is unwound due to a thrown exxception, `__stack_pointer` global can point to an invalid address. So a `global.set` to restore `__stack_pointer` should be inserted right after `catch` instruction. But after r352598 the `global.set` instruction is inserted not right after `catch` but after `block` - `br-on-exn` - `end_block` - `extract_exception` sequence. This CL fixes it. While doing that, we can actually move ReplacePhysRegs pass after LateEHPrepare and merge EHRestoreStackPointer pass into LateEHPrepare, and now placing `global.set` to `__stack_pointer` right after `catch` is much easier. Otherwise it is hard to guarantee that `global.set` is still right after `catch` and not touched with other transformations, in which case we have to do something to hoist it. Reviewers: dschuff Subscribers: mgorny, sbc100, jgravelle-google, sunfish, llvm-commits Differential Revision: https://reviews.llvm.org/D57421 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@352681 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/Target/WebAssembly/CMakeLists.txt | 1 - lib/Target/WebAssembly/WebAssembly.h | 2 - .../WebAssemblyEHRestoreStackPointer.cpp | 86 ------------------- .../WebAssembly/WebAssemblyLateEHPrepare.cpp | 32 +++++++ .../WebAssembly/WebAssemblyTargetMachine.cpp | 14 ++- test/CodeGen/WebAssembly/exception.ll | 2 +- 6 files changed, 38 insertions(+), 99 deletions(-) delete mode 100644 lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp diff --git a/lib/Target/WebAssembly/CMakeLists.txt b/lib/Target/WebAssembly/CMakeLists.txt index 1f3b7d942d4..4fc2e26ccf3 100644 --- a/lib/Target/WebAssembly/CMakeLists.txt +++ b/lib/Target/WebAssembly/CMakeLists.txt @@ -21,7 +21,6 @@ add_llvm_target(WebAssemblyCodeGen WebAssemblyCFGSort.cpp WebAssemblyDebugValueManager.cpp WebAssemblyLateEHPrepare.cpp - WebAssemblyEHRestoreStackPointer.cpp WebAssemblyExceptionInfo.cpp WebAssemblyExplicitLocals.cpp WebAssemblyFastISel.cpp diff --git a/lib/Target/WebAssembly/WebAssembly.h b/lib/Target/WebAssembly/WebAssembly.h index 27bc156eae8..2a7efe1176f 100644 --- a/lib/Target/WebAssembly/WebAssembly.h +++ b/lib/Target/WebAssembly/WebAssembly.h @@ -38,7 +38,6 @@ FunctionPass *createWebAssemblyArgumentMove(); FunctionPass *createWebAssemblySetP2AlignOperands(); // Late passes. -FunctionPass *createWebAssemblyEHRestoreStackPointer(); FunctionPass *createWebAssemblyReplacePhysRegs(); FunctionPass *createWebAssemblyPrepareForLiveIntervals(); FunctionPass *createWebAssemblyOptimizeLiveIntervals(); @@ -63,7 +62,6 @@ void initializeFixFunctionBitcastsPass(PassRegistry &); void initializeOptimizeReturnedPass(PassRegistry &); void initializeWebAssemblyArgumentMovePass(PassRegistry &); void initializeWebAssemblySetP2AlignOperandsPass(PassRegistry &); -void initializeWebAssemblyEHRestoreStackPointerPass(PassRegistry &); void initializeWebAssemblyReplacePhysRegsPass(PassRegistry &); void initializeWebAssemblyPrepareForLiveIntervalsPass(PassRegistry &); void initializeWebAssemblyOptimizeLiveIntervalsPass(PassRegistry &); diff --git a/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp b/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp deleted file mode 100644 index bed4d1ede99..00000000000 --- a/lib/Target/WebAssembly/WebAssemblyEHRestoreStackPointer.cpp +++ /dev/null @@ -1,86 +0,0 @@ -//===-- WebAssemblyEHRestoreStackPointer.cpp - __stack_pointer restoration ===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -/// -/// \file -/// After the stack is unwound due to a thrown exception, the __stack_pointer -/// global can point to an invalid address. This inserts instructions that -/// restore __stack_pointer global. -/// -//===----------------------------------------------------------------------===// - -#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" -#include "WebAssembly.h" -#include "WebAssemblySubtarget.h" -#include "WebAssemblyUtilities.h" -#include "llvm/CodeGen/MachineFrameInfo.h" -#include "llvm/MC/MCAsmInfo.h" -using namespace llvm; - -#define DEBUG_TYPE "wasm-eh-restore-stack-pointer" - -namespace { -class WebAssemblyEHRestoreStackPointer final : public MachineFunctionPass { -public: - static char ID; // Pass identification, replacement for typeid - WebAssemblyEHRestoreStackPointer() : MachineFunctionPass(ID) {} - - StringRef getPassName() const override { - return "WebAssembly Restore Stack Pointer for Exception Handling"; - } - - void getAnalysisUsage(AnalysisUsage &AU) const override { - AU.setPreservesCFG(); - MachineFunctionPass::getAnalysisUsage(AU); - } - - bool runOnMachineFunction(MachineFunction &MF) override; -}; -} // end anonymous namespace - -char WebAssemblyEHRestoreStackPointer::ID = 0; -INITIALIZE_PASS(WebAssemblyEHRestoreStackPointer, DEBUG_TYPE, - "Restore Stack Pointer for Exception Handling", true, false) - -FunctionPass *llvm::createWebAssemblyEHRestoreStackPointer() { - return new WebAssemblyEHRestoreStackPointer(); -} - -bool WebAssemblyEHRestoreStackPointer::runOnMachineFunction( - MachineFunction &MF) { - LLVM_DEBUG(dbgs() << "********** EH Restore Stack Pointer **********\n" - "********** Function: " - << MF.getName() << '\n'); - - const auto *FrameLowering = static_cast( - MF.getSubtarget().getFrameLowering()); - if (!FrameLowering->needsPrologForEH(MF)) - return false; - bool Changed = false; - - for (auto &MBB : MF) { - if (!MBB.isEHPad()) - continue; - Changed = true; - - // Insert __stack_pointer restoring instructions at the beginning of each EH - // 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 (MBB.begin()->getOpcode() == WebAssembly::CATCH) - InsertPos++; - FrameLowering->writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPos, - MBB.begin()->getDebugLoc()); - } - return Changed; -} diff --git a/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp b/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp index 030f09b8bf4..2962de47653 100644 --- a/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp +++ b/lib/Target/WebAssembly/WebAssemblyLateEHPrepare.cpp @@ -34,6 +34,7 @@ class WebAssemblyLateEHPrepare final : public MachineFunctionPass { bool replaceFuncletReturns(MachineFunction &MF); bool addCatches(MachineFunction &MF); bool addExceptionExtraction(MachineFunction &MF); + bool restoreStackPointer(MachineFunction &MF); public: static char ID; // Pass identification, replacement for typeid @@ -113,6 +114,7 @@ bool WebAssemblyLateEHPrepare::runOnMachineFunction(MachineFunction &MF) { Changed |= replaceFuncletReturns(MF); Changed |= addCatches(MF); Changed |= addExceptionExtraction(MF); + Changed |= restoreStackPointer(MF); return Changed; } @@ -330,3 +332,33 @@ bool WebAssemblyLateEHPrepare::addExceptionExtraction(MachineFunction &MF) { return true; } + +// After the stack is unwound due to a thrown exception, the __stack_pointer +// global can point to an invalid address. This inserts instructions that +// restore __stack_pointer global. +bool WebAssemblyLateEHPrepare::restoreStackPointer(MachineFunction &MF) { + const auto *FrameLowering = static_cast( + MF.getSubtarget().getFrameLowering()); + if (!FrameLowering->needsPrologForEH(MF)) + return false; + bool Changed = false; + + for (auto &MBB : MF) { + if (!MBB.isEHPad()) + continue; + Changed = true; + + // Insert __stack_pointer restoring instructions at the beginning of each EH + // pad, after the catch instruction. 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 (MBB.begin()->getOpcode() == WebAssembly::CATCH) + InsertPos++; + FrameLowering->writeSPToGlobal(WebAssembly::SP32, MF, MBB, InsertPos, + MBB.begin()->getDebugLoc()); + } + return Changed; +} diff --git a/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index c235fd21d06..80e34b307e1 100644 --- a/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -57,7 +57,6 @@ extern "C" void LLVMInitializeWebAssemblyTarget() { initializeOptimizeReturnedPass(PR); initializeWebAssemblyArgumentMovePass(PR); initializeWebAssemblySetP2AlignOperandsPass(PR); - initializeWebAssemblyEHRestoreStackPointerPass(PR); initializeWebAssemblyReplacePhysRegsPass(PR); initializeWebAssemblyPrepareForLiveIntervalsPass(PR); initializeWebAssemblyOptimizeLiveIntervalsPass(PR); @@ -284,14 +283,6 @@ void WebAssemblyPassConfig::addPostRegAlloc() { void WebAssemblyPassConfig::addPreEmitPass() { TargetPassConfig::addPreEmitPass(); - // Restore __stack_pointer global after an exception is thrown. - addPass(createWebAssemblyEHRestoreStackPointer()); - - // Now that we have a prologue and epilogue and all frame indices are - // rewritten, eliminate SP and FP. This allows them to be stackified, - // colored, and numbered with the rest of the registers. - addPass(createWebAssemblyReplacePhysRegs()); - // Rewrite pseudo call_indirect instructions as real instructions. // This needs to run before register stackification, because we change the // order of the arguments. @@ -304,6 +295,11 @@ void WebAssemblyPassConfig::addPreEmitPass() { // Every CFG-changing optimizations should come before this. addPass(createWebAssemblyLateEHPrepare()); + // Now that we have a prologue and epilogue and all frame indices are + // rewritten, eliminate SP and FP. This allows them to be stackified, + // colored, and numbered with the rest of the registers. + addPass(createWebAssemblyReplacePhysRegs()); + // Preparations and optimizations related to register stackification. if (getOptLevel() != CodeGenOpt::None) { // LiveIntervals isn't commonly run this late. Re-establish preconditions. diff --git a/test/CodeGen/WebAssembly/exception.ll b/test/CodeGen/WebAssembly/exception.ll index 46ec46837af..e2a48ed47d6 100644 --- a/test/CodeGen/WebAssembly/exception.ll +++ b/test/CodeGen/WebAssembly/exception.ll @@ -30,12 +30,12 @@ define void @test_rethrow(i8* %p) { ; CHECK: try ; CHECK: call foo@FUNCTION ; CHECK: catch $[[EXCEPT_REF:[0-9]+]]= +; CHECK: global.set __stack_pointer@GLOBAL ; CHECK: block i32 ; CHECK: br_on_exn 0, __cpp_exception@EVENT, $[[EXCEPT_REF]] ; CHECK: rethrow ; CHECK: end_block ; CHECK: extract_exception $[[EXN:[0-9]+]]= -; CHECK: global.set __stack_pointer@GLOBAL ; CHECK-DAG: i32.store __wasm_lpad_context ; CHECK-DAG: i32.store __wasm_lpad_context+4 ; CHECK: i32.call $drop=, _Unwind_CallPersonality@FUNCTION, $[[EXN]] -- 2.40.0