Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp @@ -253,7 +253,7 @@ assert(OnStack.count(MLI.getLoopFor(&MBB)) && "Blocks must be nested in their loops"); } - while (OnStack.size() > 1 && &MBB == LoopBottom(OnStack.back())) + while (OnStack.size() > 1 && &MBB == WebAssembly::getBottom(OnStack.back())) OnStack.pop_back(); } assert(OnStack.pop_back_val() == nullptr && Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -127,7 +127,8 @@ // Decide where in Header to put the BLOCK. MachineBasicBlock::iterator InsertPos; MachineLoop *HeaderLoop = MLI.getLoopFor(Header); - if (HeaderLoop && MBB.getNumber() > LoopBottom(HeaderLoop)->getNumber()) { + if (HeaderLoop && + MBB.getNumber() > WebAssembly::getBottom(HeaderLoop)->getNumber()) { // Header is the header of a loop that does not lexically contain MBB, so // the BLOCK needs to be above the LOOP, after any END constructs. InsertPos = Header->begin(); @@ -181,7 +182,7 @@ // The operand of a LOOP is the first block after the loop. If the loop is the // bottom of the function, insert a dummy block at the end. - MachineBasicBlock *Bottom = LoopBottom(Loop); + MachineBasicBlock *Bottom = WebAssembly::getBottom(Loop); auto Iter = std::next(MachineFunction::iterator(Bottom)); if (Iter == MF.end()) { MachineBasicBlock *Label = MF.CreateMachineBasicBlock(); Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -16,11 +16,10 @@ #ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYUTILITIES_H #define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYUTILITIES_H +#include "llvm/CodeGen/MachineBasicBlock.h" + namespace llvm { -class MachineBasicBlock; -class MachineInstr; -class MachineLoop; class WebAssemblyFunctionInfo; namespace WebAssembly { @@ -29,15 +28,45 @@ bool isCopy(const MachineInstr &MI); bool isTee(const MachineInstr &MI); bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI); +bool isCallDirect(const MachineInstr &MI); bool isCallIndirect(const MachineInstr &MI); +bool isMarker(const MachineInstr &MI); +bool isThrow(const MachineInstr &MI); +bool isRethrow(const MachineInstr &MI); +bool isCatch(const MachineInstr &MI); +bool mayThrow(const MachineInstr &MI); + +/// Returns the operand number of a callee, assuming the argument is a call +/// instruction. +unsigned getCalleeOpNo(const MachineInstr &MI); + +/// Returns if the given BB is a single BB terminate pad which starts with a +/// 'catch' instruction. +bool isCatchTerminatePad(const MachineBasicBlock &MBB); +/// Returns if the given BB is a single BB terminate pad which starts with a +/// 'catch_all' insrtruction. +bool isCatchAllTerminatePad(const MachineBasicBlock &MBB); + +// Exception-related function names +extern const char *const ClangCallTerminateFn; +extern const char *const CxaBeginCatchFn; +extern const char *const CxaRethrowFn; +extern const char *const StdTerminateFn; +extern const char *const PersonalityWrapperFn; + +/// Return the "bottom" block of an entity, which can be either a MachineLoop or +/// WebAssemblyException. This differs from MachineLoop::getBottomBlock in that +/// it works even if the entity is discontiguous. +template MachineBasicBlock *getBottom(const T *Unit) { + MachineBasicBlock *Bottom = Unit->getHeader(); + for (MachineBasicBlock *MBB : Unit->blocks()) + if (MBB->getNumber() > Bottom->getNumber()) + Bottom = MBB; + return Bottom; +} } // end namespace WebAssembly -/// Return the "bottom" block of a loop. This differs from -/// MachineLoop::getBottomBlock in that it works even if the loop is -/// discontiguous. -MachineBasicBlock *LoopBottom(const MachineLoop *Loop); - } // end namespace llvm #endif Index: llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp =================================================================== --- llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -18,6 +18,13 @@ #include "llvm/CodeGen/MachineLoopInfo.h" using namespace llvm; +const char *const WebAssembly::ClangCallTerminateFn = "__clang_call_terminate"; +const char *const WebAssembly::CxaBeginCatchFn = "__cxa_begin_catch"; +const char *const WebAssembly::CxaRethrowFn = "__cxa_rethrow"; +const char *const WebAssembly::StdTerminateFn = "_ZSt9terminatev"; +const char *const WebAssembly::PersonalityWrapperFn = + "_Unwind_Wasm_CallPersonality"; + bool WebAssembly::isArgument(const MachineInstr &MI) { switch (MI.getOpcode()) { case WebAssembly::ARGUMENT_I32: @@ -71,6 +78,24 @@ MFI.isVRegStackified(Reg); } +bool WebAssembly::isCallDirect(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case WebAssembly::CALL_VOID: + case WebAssembly::CALL_I32: + case WebAssembly::CALL_I64: + case WebAssembly::CALL_F32: + case WebAssembly::CALL_F64: + case WebAssembly::CALL_v16i8: + case WebAssembly::CALL_v8i16: + case WebAssembly::CALL_v4i32: + case WebAssembly::CALL_v4f32: + case WebAssembly::CALL_EXCEPT_REF: + return true; + default: + return false; + } +} + bool WebAssembly::isCallIndirect(const MachineInstr &MI) { switch (MI.getOpcode()) { case WebAssembly::CALL_INDIRECT_VOID: @@ -82,16 +107,136 @@ case WebAssembly::CALL_INDIRECT_v8i16: case WebAssembly::CALL_INDIRECT_v4i32: case WebAssembly::CALL_INDIRECT_v4f32: + case WebAssembly::CALL_INDIRECT_EXCEPT_REF: + return true; + default: + return false; + } +} + +unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case WebAssembly::CALL_VOID: + case WebAssembly::CALL_INDIRECT_VOID: + return 0; + case WebAssembly::CALL_I32: + case WebAssembly::CALL_I64: + case WebAssembly::CALL_F32: + case WebAssembly::CALL_F64: + case WebAssembly::CALL_EXCEPT_REF: + case WebAssembly::CALL_INDIRECT_I32: + case WebAssembly::CALL_INDIRECT_I64: + case WebAssembly::CALL_INDIRECT_F32: + case WebAssembly::CALL_INDIRECT_F64: + case WebAssembly::CALL_INDIRECT_EXCEPT_REF: + return 1; + default: + llvm_unreachable("Not a call instruction"); + } +} + +bool WebAssembly::isMarker(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case WebAssembly::BLOCK: + case WebAssembly::END_BLOCK: + case WebAssembly::LOOP: + case WebAssembly::END_LOOP: + case WebAssembly::TRY: + case WebAssembly::END_TRY: return true; default: return false; } } -MachineBasicBlock *llvm::LoopBottom(const MachineLoop *Loop) { - MachineBasicBlock *Bottom = Loop->getHeader(); - for (MachineBasicBlock *MBB : Loop->blocks()) - if (MBB->getNumber() > Bottom->getNumber()) - Bottom = MBB; - return Bottom; +bool WebAssembly::isThrow(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case WebAssembly::THROW_I32: + case WebAssembly::THROW_I64: + return true; + default: + return false; + } +} + +bool WebAssembly::isRethrow(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case WebAssembly::RETHROW: + case WebAssembly::RETHROW_TO_CALLER: + return true; + default: + return false; + } +} + +bool WebAssembly::isCatch(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case WebAssembly::CATCH_I32: + case WebAssembly::CATCH_I64: + case WebAssembly::CATCH_ALL: + return true; + default: + return false; + } +} + +bool WebAssembly::mayThrow(const MachineInstr &MI) { + switch (MI.getOpcode()) { + case WebAssembly::THROW_I32: + case WebAssembly::THROW_I64: + case WebAssembly::RETHROW: + return true; + } + if (isCallIndirect(MI)) + return true; + if (!MI.isCall()) + return false; + + const MachineOperand &MO = MI.getOperand(getCalleeOpNo(MI)); + assert(MO.isGlobal()); + const auto *F = dyn_cast(MO.getGlobal()); + if (!F) + return true; + if (F->doesNotThrow()) + return false; + // These functions never throw + if (F->getName() == CxaBeginCatchFn || F->getName() == PersonalityWrapperFn || + F->getName() == ClangCallTerminateFn || F->getName() == StdTerminateFn) + return false; + return true; +} + +bool WebAssembly::isCatchTerminatePad(const MachineBasicBlock &MBB) { + if (!MBB.isEHPad()) + return false; + bool SeenCatch = false; + for (auto &MI : MBB) { + if (MI.getOpcode() == WebAssembly::CATCH_I32 || + MI.getOpcode() == WebAssembly::CATCH_I64) + SeenCatch = true; + if (SeenCatch && MI.isCall()) { + const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI)); + if (CalleeOp.isGlobal() && + CalleeOp.getGlobal()->getName() == ClangCallTerminateFn) + return true; + } + } + return false; +} + +bool WebAssembly::isCatchAllTerminatePad(const MachineBasicBlock &MBB) { + if (!MBB.isEHPad()) + return false; + bool SeenCatchAll = false; + for (auto &MI : MBB) { + if (MI.getOpcode() == WebAssembly::CATCH_ALL) + SeenCatchAll = true; + if (SeenCatchAll && MI.isCall()) { + const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI)); + if (CalleeOp.isGlobal() && + CalleeOp.getGlobal()->getName() == StdTerminateFn) + return true; + } + } + return false; }