[WebAssembly] Add more utility functions

Summary:
Added more utility functions that will be used in EH-related passes Also
changed `LoopBottom` function to `getBottom` and uses templates to be
able to handle other classes as well, which will be used in CFGSort
later.

Reviewers: dschuff

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

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

llvm-svn: 335006
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
index 0a81154..5944cea 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
+++ b/llvm/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;
   }
 }
 
-MachineBasicBlock *llvm::LoopBottom(const MachineLoop *Loop) {
-  MachineBasicBlock *Bottom = Loop->getHeader();
-  for (MachineBasicBlock *MBB : Loop->blocks())
-    if (MBB->getNumber() > Bottom->getNumber())
-      Bottom = MBB;
-  return Bottom;
+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;
+  }
+}
+
+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<Function>(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;
 }