Skip to content

Commit

Permalink
[WebAssembly] Add more utility functions
Browse files Browse the repository at this point in the history
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
  • Loading branch information
aheejin committed Jun 19, 2018
1 parent 33c3fce commit 817811c
Show file tree
Hide file tree
Showing 4 changed files with 192 additions and 17 deletions.
2 changes: 1 addition & 1 deletion llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp
Expand Up @@ -253,7 +253,7 @@ static void SortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI,
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 &&
Expand Down
5 changes: 3 additions & 2 deletions llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
Expand Up @@ -127,7 +127,8 @@ static void PlaceBlockMarker(
// 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();
Expand Down Expand Up @@ -181,7 +182,7 @@ static void PlaceLoopMarker(

// 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();
Expand Down
157 changes: 151 additions & 6 deletions llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
Expand Up @@ -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:
Expand Down Expand Up @@ -71,6 +78,24 @@ bool WebAssembly::isChild(const MachineInstr &MI,
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:
Expand All @@ -82,16 +107,136 @@ bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
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;
}
}

bool WebAssembly::isThrow(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::THROW_I32:
case WebAssembly::THROW_I64:
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::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;
}
45 changes: 37 additions & 8 deletions llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
Expand Up @@ -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 {
Expand All @@ -29,14 +28,44 @@ bool isArgument(const MachineInstr &MI);
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);

} // end namespace WebAssembly
/// 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);

/// 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);
// 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 <typename T> 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

} // end namespace llvm

Expand Down

0 comments on commit 817811c

Please sign in to comment.