summaryrefslogtreecommitdiff
path: root/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp')
-rw-r--r--lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp164
1 files changed, 118 insertions, 46 deletions
diff --git a/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index d85db14fc679f..fa862fbaa634c 100644
--- a/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -30,6 +30,21 @@
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
+// Defines llvm::WebAssembly::getStackOpcode to convert register instructions to
+// stack instructions
+#define GET_INSTRMAP_INFO 1
+#include "WebAssemblyGenInstrInfo.inc"
+
+// This disables the removal of registers when lowering into MC, as required
+// by some current tests.
+static cl::opt<bool>
+ WasmKeepRegisters("wasm-keep-registers", cl::Hidden,
+ cl::desc("WebAssembly: output stack registers in"
+ " instruction output for test purposes only."),
+ cl::init(false));
+
+static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI);
+
MCSymbol *
WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
const GlobalValue *Global = MO.getGlobal();
@@ -40,35 +55,13 @@ WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
const TargetMachine &TM = MF.getTarget();
const Function &CurrentFunc = MF.getFunction();
- SmallVector<wasm::ValType, 4> Returns;
- SmallVector<wasm::ValType, 4> Params;
-
- wasm::ValType iPTR =
- MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() ?
- wasm::ValType::I64 :
- wasm::ValType::I32;
-
- SmallVector<MVT, 4> ResultMVTs;
- ComputeLegalValueVTs(CurrentFunc, TM, FuncTy->getReturnType(), ResultMVTs);
- // WebAssembly can't currently handle returning tuples.
- if (ResultMVTs.size() <= 1)
- for (MVT ResultMVT : ResultMVTs)
- Returns.push_back(WebAssembly::toValType(ResultMVT));
- else
- Params.push_back(iPTR);
-
- for (Type *Ty : FuncTy->params()) {
- SmallVector<MVT, 4> ParamMVTs;
- ComputeLegalValueVTs(CurrentFunc, TM, Ty, ParamMVTs);
- for (MVT ParamMVT : ParamMVTs)
- Params.push_back(WebAssembly::toValType(ParamMVT));
- }
-
- if (FuncTy->isVarArg())
- Params.push_back(iPTR);
+ SmallVector<MVT, 1> ResultMVTs;
+ SmallVector<MVT, 4> ParamMVTs;
+ ComputeSignatureVTs(FuncTy, CurrentFunc, TM, ParamMVTs, ResultMVTs);
- WasmSym->setReturns(std::move(Returns));
- WasmSym->setParams(std::move(Params));
+ auto Signature = SignatureFromMVTs(ResultMVTs, ParamMVTs);
+ WasmSym->setSignature(Signature.get());
+ Printer.addSignature(std::move(Signature));
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
}
@@ -82,10 +75,10 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
cast<MCSymbolWasm>(Printer.GetExternalSymbolSymbol(Name));
const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
- // __stack_pointer is a global variable; all other external symbols used by
- // CodeGen are functions. It's OK to hardcode knowledge of specific symbols
- // here; this method is precisely there for fetching the signatures of known
- // Clang-provided symbols.
+ // Except for the two exceptions (__stack_pointer and __cpp_exception), all
+ // other external symbols used by CodeGen are functions. It's OK to hardcode
+ // knowledge of specific symbols here; this method is precisely there for
+ // fetching the signatures of known Clang-provided symbols.
if (strcmp(Name, "__stack_pointer") == 0) {
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_GLOBAL);
WasmSym->setGlobalType(wasm::WasmGlobalType{
@@ -97,27 +90,55 @@ MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
SmallVector<wasm::ValType, 4> Returns;
SmallVector<wasm::ValType, 4> Params;
- GetSignature(Subtarget, Name, Returns, Params);
+ if (strcmp(Name, "__cpp_exception") == 0) {
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_EVENT);
+ // We can't confirm its signature index for now because there can be
+ // imported exceptions. Set it to be 0 for now.
+ WasmSym->setEventType(
+ {wasm::WASM_EVENT_ATTRIBUTE_EXCEPTION, /* SigIndex */ 0});
+ // We may have multiple C++ compilation units to be linked together, each of
+ // which defines the exception symbol. To resolve them, we declare them as
+ // weak.
+ WasmSym->setWeak(true);
+ WasmSym->setExternal(true);
- WasmSym->setReturns(std::move(Returns));
- WasmSym->setParams(std::move(Params));
- WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
+ // All C++ exceptions are assumed to have a single i32 (for wasm32) or i64
+ // (for wasm64) param type and void return type. The reaon is, all C++
+ // exception values are pointers, and to share the type section with
+ // functions, exceptions are assumed to have void return type.
+ Params.push_back(Subtarget.hasAddr64() ? wasm::ValType::I64
+ : wasm::ValType::I32);
+ } else { // Function symbols
+ WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
+ GetLibcallSignature(Subtarget, Name, Returns, Params);
+ }
+ auto Signature =
+ make_unique<wasm::WasmSignature>(std::move(Returns), std::move(Params));
+ WasmSym->setSignature(Signature.get());
+ Printer.addSignature(std::move(Signature));
return WasmSym;
}
MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
int64_t Offset,
- bool IsFunc) const {
+ bool IsFunc, bool IsGlob,
+ bool IsEvent) const {
MCSymbolRefExpr::VariantKind VK =
IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
- : MCSymbolRefExpr::VK_None;
+ : IsGlob ? MCSymbolRefExpr::VK_WebAssembly_GLOBAL
+ : IsEvent ? MCSymbolRefExpr::VK_WebAssembly_EVENT
+ : MCSymbolRefExpr::VK_None;
const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
if (Offset != 0) {
if (IsFunc)
report_fatal_error("Function addresses with offsets not supported");
+ if (IsGlob)
+ report_fatal_error("Global indexes with offsets not supported");
+ if (IsEvent)
+ report_fatal_error("Event indexes with offsets not supported");
Expr =
MCBinaryExpr::createAdd(Expr, MCConstantExpr::create(Offset, Ctx), Ctx);
}
@@ -135,6 +156,8 @@ static wasm::ValType getType(const TargetRegisterClass *RC) {
return wasm::ValType::F32;
if (RC == &WebAssembly::F64RegClass)
return wasm::ValType::F64;
+ if (RC == &WebAssembly::V128RegClass)
+ return wasm::ValType::V128;
llvm_unreachable("Unexpected register class");
}
@@ -187,8 +210,10 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
Params.pop_back();
MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
- WasmSym->setReturns(std::move(Returns));
- WasmSym->setParams(std::move(Params));
+ auto Signature = make_unique<wasm::WasmSignature>(std::move(Returns),
+ std::move(Params));
+ WasmSym->setSignature(Signature.get());
+ Printer.addSignature(std::move(Signature));
WasmSym->setType(wasm::WASM_SYMBOL_TYPE_FUNCTION);
const MCExpr *Expr = MCSymbolRefExpr::create(
@@ -212,21 +237,68 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
break;
}
case MachineOperand::MO_GlobalAddress:
- assert(MO.getTargetFlags() == 0 &&
+ assert(MO.getTargetFlags() == WebAssemblyII::MO_NO_FLAG &&
"WebAssembly does not use target flags on GlobalAddresses");
MCOp = LowerSymbolOperand(GetGlobalAddressSymbol(MO), MO.getOffset(),
- MO.getGlobal()->getValueType()->isFunctionTy());
+ MO.getGlobal()->getValueType()->isFunctionTy(),
+ false, false);
break;
case MachineOperand::MO_ExternalSymbol:
// The target flag indicates whether this is a symbol for a
// variable or a function.
- assert((MO.getTargetFlags() & -2) == 0 &&
- "WebAssembly uses only one target flag bit on ExternalSymbols");
- MCOp = LowerSymbolOperand(GetExternalSymbolSymbol(MO), /*Offset=*/0,
- MO.getTargetFlags() & 1);
+ assert((MO.getTargetFlags() & ~WebAssemblyII::MO_SYMBOL_MASK) == 0 &&
+ "WebAssembly uses only symbol flags on ExternalSymbols");
+ MCOp = LowerSymbolOperand(
+ GetExternalSymbolSymbol(MO), /*Offset=*/0,
+ (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_FUNCTION) != 0,
+ (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_GLOBAL) != 0,
+ (MO.getTargetFlags() & WebAssemblyII::MO_SYMBOL_EVENT) != 0);
+ break;
+ case MachineOperand::MO_MCSymbol:
+ // This is currently used only for LSDA symbols (GCC_except_table),
+ // because global addresses or other external symbols are handled above.
+ assert(MO.getTargetFlags() == 0 &&
+ "WebAssembly does not use target flags on MCSymbol");
+ MCOp = LowerSymbolOperand(MO.getMCSymbol(), /*Offset=*/0, false, false,
+ false);
break;
}
OutMI.addOperand(MCOp);
}
+
+ if (!WasmKeepRegisters)
+ removeRegisterOperands(MI, OutMI);
+}
+
+static void removeRegisterOperands(const MachineInstr *MI, MCInst &OutMI) {
+ // Remove all uses of stackified registers to bring the instruction format
+ // into its final stack form used thruout MC, and transition opcodes to
+ // their _S variant.
+ // We do this seperate from the above code that still may need these
+ // registers for e.g. call_indirect signatures.
+ // See comments in lib/Target/WebAssembly/WebAssemblyInstrFormats.td for
+ // details.
+ // TODO: the code above creates new registers which are then removed here.
+ // That code could be slightly simplified by not doing that, though maybe
+ // it is simpler conceptually to keep the code above in "register mode"
+ // until this transition point.
+ // FIXME: we are not processing inline assembly, which contains register
+ // operands, because it is used by later target generic code.
+ if (MI->isDebugInstr() || MI->isLabel() || MI->isInlineAsm())
+ return;
+
+ // Transform to _S instruction.
+ auto RegOpcode = OutMI.getOpcode();
+ auto StackOpcode = WebAssembly::getStackOpcode(RegOpcode);
+ assert(StackOpcode != -1 && "Failed to stackify instruction");
+ OutMI.setOpcode(StackOpcode);
+
+ // Remove register operands.
+ for (auto I = OutMI.getNumOperands(); I; --I) {
+ auto &MO = OutMI.getOperand(I - 1);
+ if (MO.isReg()) {
+ OutMI.erase(&MO);
+ }
+ }
}