Files
archived-llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
Wouter van Oortmerssen a26aa42625 [WebAssembly] Added default stack-only instruction mode for MC.
Summary:
Made it convert from register to stack based instructions, and removed the registers.
Fixes to related code that was expecting register based instructions.
Added the correct testing flag to all tests, depending on what the
format they were expecting so far.
Translated one test to stack format as example: reg-stackify-stack.ll

tested:
llvm-lit -v `find test -name WebAssembly`
unittests/MC/*

Reviewers: dschuff, sunfish

Subscribers: sbc100, jgravelle-google, eraman, aheejin, llvm-commits, jfb

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

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@340750 91177308-0d34-0410-b5e6-96231b3b80d8
2018-08-27 15:45:51 +00:00

322 lines
9.4 KiB
C++

//===-- WebAssemblyUtilities.cpp - WebAssembly Utility Functions ----------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
///
/// \file
/// This file implements several utility functions for WebAssembly.
///
//===----------------------------------------------------------------------===//
#include "WebAssemblyUtilities.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "llvm/CodeGen/MachineInstr.h"
#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:
case WebAssembly::ARGUMENT_I32_S:
case WebAssembly::ARGUMENT_I64:
case WebAssembly::ARGUMENT_I64_S:
case WebAssembly::ARGUMENT_F32:
case WebAssembly::ARGUMENT_F32_S:
case WebAssembly::ARGUMENT_F64:
case WebAssembly::ARGUMENT_F64_S:
case WebAssembly::ARGUMENT_v16i8:
case WebAssembly::ARGUMENT_v16i8_S:
case WebAssembly::ARGUMENT_v8i16:
case WebAssembly::ARGUMENT_v8i16_S:
case WebAssembly::ARGUMENT_v4i32:
case WebAssembly::ARGUMENT_v4i32_S:
case WebAssembly::ARGUMENT_v2i64:
case WebAssembly::ARGUMENT_v2i64_S:
case WebAssembly::ARGUMENT_v4f32:
case WebAssembly::ARGUMENT_v4f32_S:
case WebAssembly::ARGUMENT_v2f64:
case WebAssembly::ARGUMENT_v2f64_S:
return true;
default:
return false;
}
}
bool WebAssembly::isCopy(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::COPY_I32:
case WebAssembly::COPY_I32_S:
case WebAssembly::COPY_I64:
case WebAssembly::COPY_I64_S:
case WebAssembly::COPY_F32:
case WebAssembly::COPY_F32_S:
case WebAssembly::COPY_F64:
case WebAssembly::COPY_F64_S:
return true;
default:
return false;
}
}
bool WebAssembly::isTee(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::TEE_I32:
case WebAssembly::TEE_I32_S:
case WebAssembly::TEE_I64:
case WebAssembly::TEE_I64_S:
case WebAssembly::TEE_F32:
case WebAssembly::TEE_F32_S:
case WebAssembly::TEE_F64:
case WebAssembly::TEE_F64_S:
return true;
default:
return false;
}
}
/// Test whether MI is a child of some other node in an expression tree.
bool WebAssembly::isChild(const MachineInstr &MI,
const WebAssemblyFunctionInfo &MFI) {
if (MI.getNumOperands() == 0)
return false;
const MachineOperand &MO = MI.getOperand(0);
if (!MO.isReg() || MO.isImplicit() || !MO.isDef())
return false;
unsigned Reg = MO.getReg();
return TargetRegisterInfo::isVirtualRegister(Reg) &&
MFI.isVRegStackified(Reg);
}
bool WebAssembly::isCallDirect(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::CALL_VOID:
case WebAssembly::CALL_VOID_S:
case WebAssembly::CALL_I32:
case WebAssembly::CALL_I32_S:
case WebAssembly::CALL_I64:
case WebAssembly::CALL_I64_S:
case WebAssembly::CALL_F32:
case WebAssembly::CALL_F32_S:
case WebAssembly::CALL_F64:
case WebAssembly::CALL_F64_S:
case WebAssembly::CALL_v16i8:
case WebAssembly::CALL_v16i8_S:
case WebAssembly::CALL_v8i16:
case WebAssembly::CALL_v8i16_S:
case WebAssembly::CALL_v4i32:
case WebAssembly::CALL_v4i32_S:
case WebAssembly::CALL_v2i64:
case WebAssembly::CALL_v2i64_S:
case WebAssembly::CALL_v4f32:
case WebAssembly::CALL_v4f32_S:
case WebAssembly::CALL_v2f64:
case WebAssembly::CALL_v2f64_S:
case WebAssembly::CALL_EXCEPT_REF:
case WebAssembly::CALL_EXCEPT_REF_S:
return true;
default:
return false;
}
}
bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::CALL_INDIRECT_VOID:
case WebAssembly::CALL_INDIRECT_VOID_S:
case WebAssembly::CALL_INDIRECT_I32:
case WebAssembly::CALL_INDIRECT_I32_S:
case WebAssembly::CALL_INDIRECT_I64:
case WebAssembly::CALL_INDIRECT_I64_S:
case WebAssembly::CALL_INDIRECT_F32:
case WebAssembly::CALL_INDIRECT_F32_S:
case WebAssembly::CALL_INDIRECT_F64:
case WebAssembly::CALL_INDIRECT_F64_S:
case WebAssembly::CALL_INDIRECT_v16i8:
case WebAssembly::CALL_INDIRECT_v16i8_S:
case WebAssembly::CALL_INDIRECT_v8i16:
case WebAssembly::CALL_INDIRECT_v8i16_S:
case WebAssembly::CALL_INDIRECT_v4i32:
case WebAssembly::CALL_INDIRECT_v4i32_S:
case WebAssembly::CALL_INDIRECT_v2i64:
case WebAssembly::CALL_INDIRECT_v2i64_S:
case WebAssembly::CALL_INDIRECT_v4f32:
case WebAssembly::CALL_INDIRECT_v4f32_S:
case WebAssembly::CALL_INDIRECT_v2f64:
case WebAssembly::CALL_INDIRECT_v2f64_S:
case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S:
return true;
default:
return false;
}
}
unsigned WebAssembly::getCalleeOpNo(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::CALL_VOID:
case WebAssembly::CALL_VOID_S:
case WebAssembly::CALL_INDIRECT_VOID:
case WebAssembly::CALL_INDIRECT_VOID_S:
return 0;
case WebAssembly::CALL_I32:
case WebAssembly::CALL_I32_S:
case WebAssembly::CALL_I64:
case WebAssembly::CALL_I64_S:
case WebAssembly::CALL_F32:
case WebAssembly::CALL_F32_S:
case WebAssembly::CALL_F64:
case WebAssembly::CALL_F64_S:
case WebAssembly::CALL_EXCEPT_REF:
case WebAssembly::CALL_EXCEPT_REF_S:
case WebAssembly::CALL_INDIRECT_I32:
case WebAssembly::CALL_INDIRECT_I32_S:
case WebAssembly::CALL_INDIRECT_I64:
case WebAssembly::CALL_INDIRECT_I64_S:
case WebAssembly::CALL_INDIRECT_F32:
case WebAssembly::CALL_INDIRECT_F32_S:
case WebAssembly::CALL_INDIRECT_F64:
case WebAssembly::CALL_INDIRECT_F64_S:
case WebAssembly::CALL_INDIRECT_EXCEPT_REF:
case WebAssembly::CALL_INDIRECT_EXCEPT_REF_S:
return 1;
default:
llvm_unreachable("Not a call instruction");
}
}
bool WebAssembly::isMarker(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::BLOCK:
case WebAssembly::BLOCK_S:
case WebAssembly::END_BLOCK:
case WebAssembly::END_BLOCK_S:
case WebAssembly::LOOP:
case WebAssembly::LOOP_S:
case WebAssembly::END_LOOP:
case WebAssembly::END_LOOP_S:
case WebAssembly::TRY:
case WebAssembly::TRY_S:
case WebAssembly::END_TRY:
case WebAssembly::END_TRY_S:
return true;
default:
return false;
}
}
bool WebAssembly::isThrow(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::THROW_I32:
case WebAssembly::THROW_I32_S:
case WebAssembly::THROW_I64:
case WebAssembly::THROW_I64_S:
return true;
default:
return false;
}
}
bool WebAssembly::isRethrow(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::RETHROW:
case WebAssembly::RETHROW_S:
case WebAssembly::RETHROW_TO_CALLER:
case WebAssembly::RETHROW_TO_CALLER_S:
return true;
default:
return false;
}
}
bool WebAssembly::isCatch(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::CATCH_I32:
case WebAssembly::CATCH_I32_S:
case WebAssembly::CATCH_I64:
case WebAssembly::CATCH_I64_S:
case WebAssembly::CATCH_ALL:
case WebAssembly::CATCH_ALL_S:
return true;
default:
return false;
}
}
bool WebAssembly::mayThrow(const MachineInstr &MI) {
switch (MI.getOpcode()) {
case WebAssembly::THROW_I32:
case WebAssembly::THROW_I32_S:
case WebAssembly::THROW_I64:
case WebAssembly::THROW_I64_S:
case WebAssembly::RETHROW:
case WebAssembly::RETHROW_S:
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 ||
MI.getOpcode() == WebAssembly::CATCH_I32_S ||
MI.getOpcode() == WebAssembly::CATCH_I64_S)
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 ||
MI.getOpcode() == WebAssembly::CATCH_ALL_S)
SeenCatchAll = true;
if (SeenCatchAll && MI.isCall()) {
const MachineOperand &CalleeOp = MI.getOperand(getCalleeOpNo(MI));
if (CalleeOp.isGlobal() &&
CalleeOp.getGlobal()->getName() == StdTerminateFn)
return true;
}
}
return false;
}