summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/WebAssembly
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp33
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h31
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp42
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h4
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp80
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h16
-rw-r--r--llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp48
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp99
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h77
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp14
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp25
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp54
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp3
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td12
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td5
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td3
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp126
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.h6
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h2
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp14
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp16
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp17
-rw-r--r--llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h1
23 files changed, 588 insertions, 140 deletions
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp
index 337c18ca57d..5b210742063 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "MCTargetDesc/WebAssemblyFixupKinds.h"
#include "llvm/MC/MCAsmBackend.h"
#include "llvm/MC/MCAssembler.h"
#include "llvm/MC/MCDirectives.h"
@@ -70,6 +71,12 @@ public:
: MCAsmBackend(), Is64Bit(Is64Bit) {}
~WebAssemblyAsmBackend() override {}
+ unsigned getNumFixupKinds() const override {
+ return WebAssembly::NumTargetFixupKinds;
+ }
+
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
+
void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
uint64_t Value, bool IsPCRel) const override;
@@ -82,12 +89,6 @@ public:
return false;
}
- unsigned getNumFixupKinds() const override {
- // We currently just use the generic fixups in MCFixup.h and don't have any
- // target-specific fixups.
- return 0;
- }
-
bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
@@ -131,6 +132,26 @@ WebAssemblyAsmBackendELF::createObjectWriter(raw_pwrite_stream &OS) const {
return createWebAssemblyELFObjectWriter(OS, Is64Bit, 0);
}
+const MCFixupKindInfo &
+WebAssemblyAsmBackend::getFixupKindInfo(MCFixupKind Kind) const {
+ const static MCFixupKindInfo Infos[WebAssembly::NumTargetFixupKinds] = {
+ // This table *must* be in the order that the fixup_* kinds are defined in
+ // WebAssemblyFixupKinds.h.
+ //
+ // Name Offset (bits) Size (bits) Flags
+ { "fixup_code_sleb128_i32", 0, 5*8, 0 },
+ { "fixup_code_sleb128_i64", 0, 10*8, 0 },
+ { "fixup_code_uleb128_i32", 0, 5*8, 0 },
+ };
+
+ if (Kind < FirstTargetFixupKind)
+ return MCAsmBackend::getFixupKindInfo(Kind);
+
+ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+ "Invalid kind!");
+ return Infos[Kind - FirstTargetFixupKind];
+}
+
bool WebAssemblyAsmBackend::writeNopData(uint64_t Count,
MCObjectWriter *OW) const {
if (Count == 0)
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h
new file mode 100644
index 00000000000..b0af63c924b
--- /dev/null
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h
@@ -0,0 +1,31 @@
+//=- WebAssemblyFixupKinds.h - WebAssembly Specific Fixup Entries -*- C++ -*-=//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYFIXUPKINDS_H
+#define LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYFIXUPKINDS_H
+
+#include "llvm/MC/MCFixup.h"
+
+namespace llvm {
+namespace WebAssembly {
+enum Fixups {
+ fixup_code_sleb128_i32 = FirstTargetFixupKind, // 32-bit signed
+ fixup_code_sleb128_i64, // 64-bit signed
+ fixup_code_uleb128_i32, // 32-bit unsigned
+
+ fixup_code_global_index, // 32-bit unsigned
+
+ // Marker
+ LastTargetFixupKind,
+ NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
+};
+} // end namespace WebAssembly
+} // end namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
index 91583ef119e..a0b00894749 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
@@ -13,6 +13,7 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "MCTargetDesc/WebAssemblyFixupKinds.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/MC/MCCodeEmitter.h"
@@ -48,9 +49,7 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter {
public:
WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
- : MCII(mcii), Ctx(ctx) {
- (void)Ctx;
- }
+ : MCII(mcii), Ctx(ctx) {}
};
} // end anonymous namespace
@@ -68,6 +67,13 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
assert(Binary < UINT8_MAX && "Multi-byte opcodes not supported yet");
OS << uint8_t(Binary);
+ // For br_table instructions, encode the size of the table. In the MCInst,
+ // there's an index operand, one operand for each table entry, and the
+ // default operand.
+ if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
+ MI.getOpcode() == WebAssembly::BR_TABLE_I64)
+ encodeULEB128(MI.getNumOperands() - 2, OS);
+
const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
const MCOperand &MO = MI.getOperand(i);
@@ -82,6 +88,12 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
encodeSLEB128(int32_t(MO.getImm()), OS);
} else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
encodeSLEB128(int64_t(MO.getImm()), OS);
+ } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
+ Fixups.push_back(MCFixup::create(
+ OS.tell() - Start, MCConstantExpr::create(MO.getImm(), Ctx),
+ MCFixupKind(WebAssembly::fixup_code_global_index), MI.getLoc()));
+ ++MCNumFixups;
+ encodeULEB128(uint64_t(MO.getImm()), OS);
} else {
encodeULEB128(uint64_t(MO.getImm()), OS);
}
@@ -107,14 +119,28 @@ void WebAssemblyMCCodeEmitter::encodeInstruction(
support::endian::Writer<support::little>(OS).write<double>(d);
}
} else if (MO.isExpr()) {
+ const MCOperandInfo &Info = Desc.OpInfo[i];
+ llvm::MCFixupKind FixupKind;
+ size_t PaddedSize;
+ if (Info.OperandType == WebAssembly::OPERAND_I32IMM) {
+ FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32);
+ PaddedSize = 5;
+ } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
+ FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64);
+ PaddedSize = 10;
+ } else if (Info.OperandType == WebAssembly::OPERAND_FUNCTION32 ||
+ Info.OperandType == WebAssembly::OPERAND_OFFSET32 ||
+ Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
+ FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32);
+ PaddedSize = 5;
+ } else {
+ llvm_unreachable("unexpected symbolic operand kind");
+ }
Fixups.push_back(MCFixup::create(
OS.tell() - Start, MO.getExpr(),
- STI.getTargetTriple().isArch64Bit() ? FK_Data_8 : FK_Data_4,
- MI.getLoc()));
+ FixupKind, MI.getLoc()));
++MCNumFixups;
- encodeULEB128(STI.getTargetTriple().isArch64Bit() ? UINT64_MAX
- : uint64_t(UINT32_MAX),
- OS);
+ encodeULEB128(0, OS, PaddedSize - 1);
} else {
llvm_unreachable("unexpected operand kind");
}
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
index 93ad57407e2..1108f5f5a32 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
@@ -68,7 +68,9 @@ enum OperandType {
/// p2align immediate for load and store address alignment.
OPERAND_P2ALIGN,
/// signature immediate for block/loop.
- OPERAND_SIGNATURE
+ OPERAND_SIGNATURE,
+ /// type signature immediate for call_indirect.
+ OPERAND_TYPEINDEX,
};
} // end namespace WebAssembly
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
index b8a0f589d7f..c198a262241 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
@@ -22,8 +22,10 @@
#include "llvm/MC/MCSubtargetInfo.h"
#include "llvm/MC/MCSymbolELF.h"
#include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/Wasm.h"
using namespace llvm;
WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S)
@@ -51,14 +53,28 @@ static void PrintTypes(formatted_raw_ostream &OS, ArrayRef<MVT> Types) {
OS << '\n';
}
-void WebAssemblyTargetAsmStreamer::emitParam(ArrayRef<MVT> Types) {
- OS << "\t.param \t";
- PrintTypes(OS, Types);
+void WebAssemblyTargetAsmStreamer::emitParam(MCSymbol *Symbol,
+ ArrayRef<MVT> Types) {
+ if (!Types.empty()) {
+ OS << "\t.param \t";
+
+ // FIXME: Currently this applies to the "current" function; it may
+ // be cleaner to specify an explicit symbol as part of the directive.
+
+ PrintTypes(OS, Types);
+ }
}
-void WebAssemblyTargetAsmStreamer::emitResult(ArrayRef<MVT> Types) {
- OS << "\t.result \t";
- PrintTypes(OS, Types);
+void WebAssemblyTargetAsmStreamer::emitResult(MCSymbol *Symbol,
+ ArrayRef<MVT> Types) {
+ if (!Types.empty()) {
+ OS << "\t.result \t";
+
+ // FIXME: Currently this applies to the "current" function; it may
+ // be cleaner to specify an explicit symbol as part of the directive.
+
+ PrintTypes(OS, Types);
+ }
}
void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<MVT> Types) {
@@ -92,11 +108,13 @@ void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) {
OS << "\t.indidx \t" << *Value << '\n';
}
-void WebAssemblyTargetELFStreamer::emitParam(ArrayRef<MVT> Types) {
+void WebAssemblyTargetELFStreamer::emitParam(MCSymbol *Symbol,
+ ArrayRef<MVT> Types) {
// Nothing to emit; params are declared as part of the function signature.
}
-void WebAssemblyTargetELFStreamer::emitResult(ArrayRef<MVT> Types) {
+void WebAssemblyTargetELFStreamer::emitResult(MCSymbol *Symbol,
+ ArrayRef<MVT> Types) {
// Nothing to emit; results are declared as part of the function signature.
}
@@ -123,22 +141,52 @@ void WebAssemblyTargetELFStreamer::emitIndirectFunctionType(
void WebAssemblyTargetELFStreamer::emitGlobalImport(StringRef name) {
}
-void WebAssemblyTargetWasmStreamer::emitParam(ArrayRef<MVT> Types) {
- // Nothing to emit; params are declared as part of the function signature.
+static unsigned MVT2WasmType(MVT Ty) {
+ switch (Ty.SimpleTy) {
+ case MVT::i32: return wasm::WASM_TYPE_I32;
+ case MVT::i64: return wasm::WASM_TYPE_I64;
+ case MVT::f32: return wasm::WASM_TYPE_F32;
+ case MVT::f64: return wasm::WASM_TYPE_F64;
+ default: llvm_unreachable("unsupported type");
+ }
}
-void WebAssemblyTargetWasmStreamer::emitResult(ArrayRef<MVT> Types) {
- // Nothing to emit; results are declared as part of the function signature.
+void WebAssemblyTargetWasmStreamer::emitParam(MCSymbol *Symbol,
+ ArrayRef<MVT> Types) {
+ SmallVector<unsigned, 4> Params;
+ for (MVT Ty : Types)
+ Params.push_back(MVT2WasmType(Ty));
+
+ cast<MCSymbolWasm>(Symbol)->setParams(std::move(Params));
+}
+
+void WebAssemblyTargetWasmStreamer::emitResult(MCSymbol *Symbol,
+ ArrayRef<MVT> Types) {
+ SmallVector<unsigned, 4> Returns;
+ for (MVT Ty : Types)
+ Returns.push_back(MVT2WasmType(Ty));
+
+ cast<MCSymbolWasm>(Symbol)->setReturns(std::move(Returns));
}
void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef<MVT> Types) {
- Streamer.EmitULEB128IntValue(Types.size());
- for (MVT Type : Types)
- Streamer.EmitIntValue(int64_t(WebAssembly::toValType(Type)), 1);
+ SmallVector<std::pair<MVT, uint32_t>, 4> Grouped;
+ for (MVT Type : Types) {
+ if (Grouped.empty() || Grouped.back().first != Type)
+ Grouped.push_back(std::make_pair(Type, 1));
+ else
+ ++Grouped.back().second;
+ }
+
+ Streamer.EmitULEB128IntValue(Grouped.size());
+ for (auto Pair : Grouped) {
+ Streamer.EmitULEB128IntValue(Pair.second);
+ Streamer.EmitULEB128IntValue(uint64_t(WebAssembly::toValType(Pair.first)));
+ }
}
void WebAssemblyTargetWasmStreamer::emitEndFunc() {
- Streamer.EmitIntValue(WebAssembly::End, 1);
+ llvm_unreachable(".end_func is not needed for direct wasm output");
}
void WebAssemblyTargetWasmStreamer::emitIndIdx(const MCExpr *Value) {
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
index 35b14bc0ba5..1ad3ffcf408 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
@@ -31,9 +31,9 @@ public:
explicit WebAssemblyTargetStreamer(MCStreamer &S);
/// .param
- virtual void emitParam(ArrayRef<MVT> Types) = 0;
+ virtual void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) = 0;
/// .result
- virtual void emitResult(ArrayRef<MVT> Types) = 0;
+ virtual void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) = 0;
/// .local
virtual void emitLocal(ArrayRef<MVT> Types) = 0;
/// .endfunc
@@ -57,8 +57,8 @@ class WebAssemblyTargetAsmStreamer final : public WebAssemblyTargetStreamer {
public:
WebAssemblyTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
- void emitParam(ArrayRef<MVT> Types) override;
- void emitResult(ArrayRef<MVT> Types) override;
+ void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
+ void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
void emitLocal(ArrayRef<MVT> Types) override;
void emitEndFunc() override;
void emitIndirectFunctionType(StringRef name,
@@ -73,8 +73,8 @@ class WebAssemblyTargetELFStreamer final : public WebAssemblyTargetStreamer {
public:
explicit WebAssemblyTargetELFStreamer(MCStreamer &S);
- void emitParam(ArrayRef<MVT> Types) override;
- void emitResult(ArrayRef<MVT> Types) override;
+ void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
+ void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
void emitLocal(ArrayRef<MVT> Types) override;
void emitEndFunc() override;
void emitIndirectFunctionType(StringRef name,
@@ -89,8 +89,8 @@ class WebAssemblyTargetWasmStreamer final : public WebAssemblyTargetStreamer {
public:
explicit WebAssemblyTargetWasmStreamer(MCStreamer &S);
- void emitParam(ArrayRef<MVT> Types) override;
- void emitResult(ArrayRef<MVT> Types) override;
+ void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
+ void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
void emitLocal(ArrayRef<MVT> Types) override;
void emitEndFunc() override;
void emitIndirectFunctionType(StringRef name,
diff --git a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
index 3fb3e65fb91..2846ec5e933 100644
--- a/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
+++ b/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
@@ -14,9 +14,13 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "MCTargetDesc/WebAssemblyFixupKinds.h"
#include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCSymbolWasm.h"
#include "llvm/MC/MCWasmObjectWriter.h"
+#include "llvm/Support/Casting.h"
#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Wasm.h"
using namespace llvm;
namespace {
@@ -33,12 +37,52 @@ private:
WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit)
: MCWasmObjectTargetWriter(Is64Bit) {}
+// Test whether the given expression computes a function address.
+static bool IsFunctionExpr(const MCExpr *Expr) {
+ if (const MCSymbolRefExpr *SyExp =
+ dyn_cast<MCSymbolRefExpr>(Expr))
+ return cast<MCSymbolWasm>(SyExp->getSymbol()).isFunction();
+
+ if (const MCBinaryExpr *BinOp =
+ dyn_cast<MCBinaryExpr>(Expr))
+ return IsFunctionExpr(BinOp->getLHS()) != IsFunctionExpr(BinOp->getRHS());
+
+ if (const MCUnaryExpr *UnOp =
+ dyn_cast<MCUnaryExpr>(Expr))
+ return IsFunctionExpr(UnOp->getSubExpr());
+
+ return false;
+}
+
unsigned WebAssemblyWasmObjectWriter::getRelocType(MCContext &Ctx,
const MCValue &Target,
const MCFixup &Fixup,
bool IsPCRel) const {
- llvm_unreachable("Relocations not yet implemented");
- return 0;
+ // WebAssembly functions are not allocated in the data address space. To
+ // resolve a pointer to a function, we must use a special relocation type.
+ bool IsFunction = IsFunctionExpr(Fixup.getValue());
+
+ assert(!IsPCRel);
+ switch (unsigned(Fixup.getKind())) {
+ case WebAssembly::fixup_code_sleb128_i32:
+ if (IsFunction)
+ return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB;
+ return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB;
+ case WebAssembly::fixup_code_sleb128_i64:
+ llvm_unreachable("fixup_sleb128_i64 not implemented yet");
+ case WebAssembly::fixup_code_uleb128_i32:
+ if (IsFunction)
+ return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB;
+ return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB;
+ case FK_Data_4:
+ if (IsFunction)
+ return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32;
+ return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32;
+ case FK_Data_8:
+ llvm_unreachable("FK_Data_8 not implemented yet");
+ default:
+ llvm_unreachable("unimplemented fixup kind");
+ }
}
MCObjectWriter *llvm::createWebAssemblyWasmObjectWriter(raw_pwrite_stream &OS,
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
index 5b4b82eb560..56bb550c72f 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
@@ -14,6 +14,7 @@
///
//===----------------------------------------------------------------------===//
+#include "WebAssemblyAsmPrinter.h"
#include "InstPrinter/WebAssemblyInstPrinter.h"
#include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
#include "MCTargetDesc/WebAssemblyTargetStreamer.h"
@@ -21,13 +22,13 @@
#include "WebAssemblyMCInstLower.h"
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblyRegisterInfo.h"
-#include "WebAssemblySubtarget.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/CodeGen/Analysis.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineConstantPool.h"
#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalVariable.h"
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCStreamer.h"
#include "llvm/MC/MCSymbol.h"
@@ -38,56 +39,6 @@ using namespace llvm;
#define DEBUG_TYPE "asm-printer"
-namespace {
-
-class WebAssemblyAsmPrinter final : public AsmPrinter {
- const MachineRegisterInfo *MRI;
- WebAssemblyFunctionInfo *MFI;
-
-public:
- WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
- : AsmPrinter(TM, std::move(Streamer)), MRI(nullptr), MFI(nullptr) {}
-
-private:
- StringRef getPassName() const override {
- return "WebAssembly Assembly Printer";
- }
-
- //===------------------------------------------------------------------===//
- // MachineFunctionPass Implementation.
- //===------------------------------------------------------------------===//
-
- bool runOnMachineFunction(MachineFunction &MF) override {
- MRI = &MF.getRegInfo();
- MFI = MF.getInfo<WebAssemblyFunctionInfo>();
- return AsmPrinter::runOnMachineFunction(MF);
- }
-
- //===------------------------------------------------------------------===//
- // AsmPrinter Implementation.
- //===------------------------------------------------------------------===//
-
- void EmitEndOfAsmFile(Module &M) override;
- void EmitJumpTableInfo() override;
- void EmitConstantPool() override;
- void EmitFunctionBodyStart() override;
- void EmitFunctionBodyEnd() override;
- void EmitInstruction(const MachineInstr *MI) override;
- const MCExpr *lowerConstant(const Constant *CV) override;
- bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
- unsigned AsmVariant, const char *ExtraCode,
- raw_ostream &OS) override;
- bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
- unsigned AsmVariant, const char *ExtraCode,
- raw_ostream &OS) override;
-
- MVT getRegType(unsigned RegNo) const;
- std::string regToString(const MachineOperand &MO);
- WebAssemblyTargetStreamer *getTargetStreamer();
-};
-
-} // end anonymous namespace
-
//===----------------------------------------------------------------------===//
// Helpers.
//===----------------------------------------------------------------------===//
@@ -135,7 +86,10 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) {
}
for (const auto &G : M.globals()) {
if (!G.hasInitializer() && G.hasExternalLinkage()) {
+ uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
getTargetStreamer()->emitGlobalImport(G.getGlobalIdentifier());
+ OutStreamer->emitELFSize(getSymbol(&G),
+ MCConstantExpr::create(Size, OutContext));
}
}
}
@@ -150,8 +104,7 @@ void WebAssemblyAsmPrinter::EmitJumpTableInfo() {
}
void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
- if (!MFI->getParams().empty())
- getTargetStreamer()->emitParam(MFI->getParams());
+ getTargetStreamer()->emitParam(CurrentFnSym, MFI->getParams());
SmallVector<MVT, 4> ResultVTs;
const Function &F(*MF->getFunction());
@@ -169,23 +122,26 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
// If the return type needs to be legalized it will get converted into
// passing a pointer.
if (ResultVTs.size() == 1)
- getTargetStreamer()->emitResult(ResultVTs);
-
- // FIXME: When ExplicitLocals is enabled by default, we won't need
- // to define the locals here (and MFI can go back to being pointer-to-const).
- for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
- unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
- unsigned WAReg = MFI->getWAReg(VReg);
- // Don't declare unused registers.
- if (WAReg == WebAssemblyFunctionInfo::UnusedReg)
- continue;
- // Don't redeclare parameters.
- if (WAReg < MFI->getParams().size())
- continue;
- // Don't declare stackified registers.
- if (int(WAReg) < 0)
- continue;
- MFI->addLocal(getRegType(VReg));
+ getTargetStreamer()->emitResult(CurrentFnSym, ResultVTs);
+ else
+ getTargetStreamer()->emitResult(CurrentFnSym, ArrayRef<MVT>());
+
+ if (TM.getTargetTriple().isOSBinFormatELF()) {
+ assert(MFI->getLocals().empty());
+ for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
+ unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
+ unsigned WAReg = MFI->getWAReg(VReg);
+ // Don't declare unused registers.
+ if (WAReg == WebAssemblyFunctionInfo::UnusedReg)
+ continue;
+ // Don't redeclare parameters.
+ if (WAReg < MFI->getParams().size())
+ continue;
+ // Don't declare stackified registers.
+ if (int(WAReg) < 0)
+ continue;
+ MFI->addLocal(getRegType(VReg));
+ }
}
getTargetStreamer()->emitLocal(MFI->getLocals());
@@ -194,7 +150,8 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
}
void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() {
- getTargetStreamer()->emitEndFunc();
+ if (TM.getTargetTriple().isOSBinFormatELF())
+ getTargetStreamer()->emitEndFunc();
}
void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
new file mode 100644
index 00000000000..c8917b8d7e4
--- /dev/null
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
@@ -0,0 +1,77 @@
+// WebAssemblyAsmPrinter.h - WebAssembly implementation of AsmPrinter-*- C++ -*-
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYASMPRINTER_H
+#define LLVM_LIB_TARGET_WEBASSEMBLY_WEBASSEMBLYASMPRINTER_H
+
+#include "WebAssemblySubtarget.h"
+#include "llvm/CodeGen/AsmPrinter.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace llvm {
+class MCSymbol;
+class WebAssemblyFunctionInfo;
+class WebAssemblyTargetStreamer;
+class WebAssemblyMCInstLower;
+
+class LLVM_LIBRARY_VISIBILITY WebAssemblyAsmPrinter final : public AsmPrinter {
+ const WebAssemblySubtarget *Subtarget;
+ const MachineRegisterInfo *MRI;
+ WebAssemblyFunctionInfo *MFI;
+
+public:
+ explicit WebAssemblyAsmPrinter(TargetMachine &TM,
+ std::unique_ptr<MCStreamer> Streamer)
+ : AsmPrinter(TM, std::move(Streamer)),
+ Subtarget(nullptr), MRI(nullptr), MFI(nullptr) {}
+
+ StringRef getPassName() const override {
+ return "WebAssembly Assembly Printer";
+ }
+
+ const WebAssemblySubtarget &getSubtarget() const { return *Subtarget; }
+
+ //===------------------------------------------------------------------===//
+ // MachineFunctionPass Implementation.
+ //===------------------------------------------------------------------===//
+
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ Subtarget = &MF.getSubtarget<WebAssemblySubtarget>();
+ MRI = &MF.getRegInfo();
+ MFI = MF.getInfo<WebAssemblyFunctionInfo>();
+ return AsmPrinter::runOnMachineFunction(MF);
+ }
+
+ //===------------------------------------------------------------------===//
+ // AsmPrinter Implementation.
+ //===------------------------------------------------------------------===//
+
+ void EmitEndOfAsmFile(Module &M) override;
+ void EmitJumpTableInfo() override;
+ void EmitConstantPool() override;
+ void EmitFunctionBodyStart() override;
+ void EmitFunctionBodyEnd() override;
+ void EmitInstruction(const MachineInstr *MI) override;
+ const MCExpr *lowerConstant(const Constant *CV) override;
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &OS) override;
+ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &OS) override;
+
+ MVT getRegType(unsigned RegNo) const;
+ std::string regToString(const MachineOperand &MO);
+ WebAssemblyTargetStreamer *getTargetStreamer();
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
index 49b9754e6b6..cf094b9b4d7 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
@@ -488,6 +488,15 @@ static void FixEndsAtEndOfFunction(
}
}
+// WebAssembly functions end with an end instruction, as if the function body
+// were a block.
+static void AppendEndToFunction(
+ MachineFunction &MF,
+ const WebAssemblyInstrInfo &TII) {
+ BuildMI(MF.back(), MF.back().end(), DebugLoc(),
+ TII.get(WebAssembly::END_FUNCTION));
+}
+
/// Insert LOOP and BLOCK markers at appropriate places.
static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
const WebAssemblyInstrInfo &TII,
@@ -555,6 +564,11 @@ static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
// Fix up block/loop signatures at the end of the function to conform to
// WebAssembly's rules.
FixEndsAtEndOfFunction(MF, MFI, BlockTops, LoopTops);
+
+ // Add an end instruction at the end of the function body.
+ if (!MF.getSubtarget<WebAssemblySubtarget>()
+ .getTargetTriple().isOSBinFormatELF())
+ AppendEndToFunction(MF, TII);
}
bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp
index fc0a01ca30e..bc6360aafd6 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp
@@ -97,15 +97,28 @@ bool WebAssemblyCallIndirectFixup::runOnMachineFunction(MachineFunction &MF) {
MI.setDesc(Desc);
// Rewrite argument order
- auto Uses = MI.explicit_uses();
- MachineInstr::mop_iterator it = Uses.begin();
- const MachineOperand MO = *it;
+ SmallVector<MachineOperand, 8> Ops;
+
+ // Set up a placeholder for the type signature immediate.
+ Ops.push_back(MachineOperand::CreateImm(0));
// Set up the flags immediate, which currently has no defined flags
// so it's always zero.
- it->ChangeToImmediate(0);
-
- MI.addOperand(MF, MO);
+ Ops.push_back(MachineOperand::CreateImm(0));
+
+ for (const MachineOperand &MO :
+ make_range(MI.operands_begin() +
+ MI.getDesc().getNumDefs() + 1,
+ MI.operands_begin() +
+ MI.getNumExplicitOperands()))
+ Ops.push_back(MO);
+ Ops.push_back(MI.getOperand(MI.getDesc().getNumDefs()));
+
+ // Replace the instructions operands.
+ while (MI.getNumOperands() > MI.getDesc().getNumDefs())
+ MI.RemoveOperand(MI.getNumOperands() - 1);
+ for (const MachineOperand &MO : Ops)
+ MI.addOperand(MO);
DEBUG(dbgs() << " After transform: " << MI);
Changed = true;
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
index 04ede7ff110..50ee79b7079 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
@@ -60,7 +60,25 @@ FunctionPass *llvm::createWebAssemblyExplicitLocals() {
/// if it doesn't yet have one.
static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
unsigned &CurLocal, unsigned Reg) {
- return Reg2Local.insert(std::make_pair(Reg, CurLocal++)).first->second;
+ auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
+ if (P.second)
+ ++CurLocal;
+ return P.first->second;
+}
+
+/// Get the appropriate drop opcode for the given register class.
+static unsigned getDropOpcode(const TargetRegisterClass *RC) {
+ if (RC == &WebAssembly::I32RegClass)
+ return WebAssembly::DROP_I32;
+ if (RC == &WebAssembly::I64RegClass)
+ return WebAssembly::DROP_I64;
+ if (RC == &WebAssembly::F32RegClass)
+ return WebAssembly::DROP_F32;
+ if (RC == &WebAssembly::F64RegClass)
+ return WebAssembly::DROP_F64;
+ if (RC == &WebAssembly::V128RegClass)
+ return WebAssembly::DROP_V128;
+ llvm_unreachable("Unexpected register class");
}
/// Get the appropriate get_local opcode for the given register class.
@@ -176,6 +194,12 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
// Start assigning local numbers after the last parameter.
unsigned CurLocal = MFI.getParams().size();
+ // Precompute the set of registers that are unused, so that we can insert
+ // drops to their defs.
+ BitVector UseEmpty(MRI.getNumVirtRegs());
+ for (unsigned i = 0, e = MRI.getNumVirtRegs(); i < e; ++i)
+ UseEmpty[i] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(i));
+
// Visit each instruction in the function.
for (MachineBasicBlock &MBB : MF) {
for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
@@ -224,15 +248,26 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
assert(MI.getDesc().getNumDefs() <= 1);
if (MI.getDesc().getNumDefs() == 1) {
unsigned OldReg = MI.getOperand(0).getReg();
- if (!MFI.isVRegStackified(OldReg) && !MRI.use_empty(OldReg)) {
- unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
+ if (!MFI.isVRegStackified(OldReg)) {
const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
unsigned NewReg = MRI.createVirtualRegister(RC);
auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
- unsigned Opc = getSetLocalOpcode(RC);
- BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
- .addImm(LocalId)
- .addReg(NewReg);
+ if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
+ MI.eraseFromParent();
+ Changed = true;
+ continue;
+ }
+ if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) {
+ unsigned Opc = getDropOpcode(RC);
+ BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
+ .addReg(NewReg);
+ } else {
+ unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
+ unsigned Opc = getSetLocalOpcode(RC);
+ BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
+ .addImm(LocalId)
+ .addReg(NewReg);
+ }
MI.getOperand(0).setReg(NewReg);
MFI.stackifyVReg(NewReg);
Changed = true;
@@ -278,13 +313,16 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) {
}
// Define the locals.
+ // TODO: Sort the locals for better compression.
+ MFI.setNumLocals(CurLocal - MFI.getParams().size());
for (size_t i = 0, e = MRI.getNumVirtRegs(); i < e; ++i) {
unsigned Reg = TargetRegisterInfo::index2VirtReg(i);
auto I = Reg2Local.find(Reg);
if (I == Reg2Local.end() || I->second < MFI.getParams().size())
continue;
- MFI.addLocal(typeForRegClass(MRI.getRegClass(Reg)));
+ MFI.setLocal(I->second - MFI.getParams().size(),
+ typeForRegClass(MRI.getRegClass(Reg)));
Changed = true;
}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
index a6a2c0bf06a..b325b0953d0 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
@@ -24,6 +24,7 @@
#include "WebAssemblyMachineFunctionInfo.h"
#include "WebAssemblySubtarget.h"
#include "WebAssemblyTargetMachine.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -151,6 +152,8 @@ void WebAssemblyFrameLowering::emitPrologue(MachineFunction &MF,
auto &MRI = MF.getRegInfo();
auto InsertPt = MBB.begin();
+ while (InsertPt != MBB.end() && WebAssembly::isArgument(*InsertPt))
+ ++InsertPt;
DebugLoc DL;
const TargetRegisterClass *PtrRC =
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
index 047f4be066c..73d1d4be293 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td
@@ -30,13 +30,15 @@ multiclass CALL<WebAssemblyRegClass vt, string prefix> {
[(set vt:$dst, (WebAssemblycall1 (i32 imm:$callee)))],
!strconcat(prefix, "call\t$dst, $callee"),
0x10>;
+
let isCodeGenOnly = 1 in {
def PCALL_INDIRECT_#vt : I<(outs vt:$dst), (ins I32:$callee, variable_ops),
[(set vt:$dst, (WebAssemblycall1 I32:$callee))],
"PSEUDO CALL INDIRECT\t$callee">;
} // isCodeGenOnly = 1
- def CALL_INDIRECT_#vt : I<(outs vt:$dst), (ins i32imm:$flags, variable_ops),
+ def CALL_INDIRECT_#vt : I<(outs vt:$dst),
+ (ins TypeIndex:$type, i32imm:$flags, variable_ops),
[],
!strconcat(prefix, "call_indirect\t$dst"),
0x11>;
@@ -48,6 +50,7 @@ multiclass SIMD_CALL<ValueType vt, string prefix> {
(WebAssemblycall1 (i32 imm:$callee)))],
!strconcat(prefix, "call\t$dst, $callee"),
0x10>;
+
let isCodeGenOnly = 1 in {
def PCALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst),
(ins I32:$callee, variable_ops),
@@ -57,7 +60,8 @@ multiclass SIMD_CALL<ValueType vt, string prefix> {
} // isCodeGenOnly = 1
def CALL_INDIRECT_#vt : SIMD_I<(outs V128:$dst),
- (ins i32imm:$flags, variable_ops),
+ (ins TypeIndex:$type, i32imm:$flags,
+ variable_ops),
[],
!strconcat(prefix, "call_indirect\t$dst"),
0x11>;
@@ -76,13 +80,15 @@ let Uses = [SP32, SP64], isCall = 1 in {
def CALL_VOID : I<(outs), (ins function32_op:$callee, variable_ops),
[(WebAssemblycall0 (i32 imm:$callee))],
"call \t$callee", 0x10>;
+
let isCodeGenOnly = 1 in {
def PCALL_INDIRECT_VOID : I<(outs), (ins I32:$callee, variable_ops),
[(WebAssemblycall0 I32:$callee)],
"PSEUDO CALL INDIRECT\t$callee">;
} // isCodeGenOnly = 1
- def CALL_INDIRECT_VOID : I<(outs), (ins i32imm:$flags, variable_ops),
+ def CALL_INDIRECT_VOID : I<(outs),
+ (ins TypeIndex:$type, i32imm:$flags, variable_ops),
[],
"call_indirect\t", 0x11>;
} // Uses = [SP32,SP64], isCall = 1
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
index 1146431e6b7..39cb1ca336f 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td
@@ -64,9 +64,12 @@ let Uses = [VALUE_STACK], Defs = [VALUE_STACK] in {
def BLOCK : I<(outs), (ins Signature:$sig), [], "block \t$sig", 0x02>;
def LOOP : I<(outs), (ins Signature:$sig), [], "loop \t$sig", 0x03>;
-// END_BLOCK and END_LOOP are represented with the same opcode in wasm.
+// END_BLOCK, END_LOOP, and END_FUNCTION are represented with the same opcode
+// in wasm.
def END_BLOCK : I<(outs), (ins), [], "end_block", 0x0b>;
def END_LOOP : I<(outs), (ins), [], "end_loop", 0x0b>;
+let isTerminator = 1, isBarrier = 1 in
+def END_FUNCTION : I<(outs), (ins), [], "end_function", 0x0b>;
} // Uses = [VALUE_STACK], Defs = [VALUE_STACK]
multiclass RETURN<WebAssemblyRegClass vt> {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
index 79472cd8e48..a601b575f57 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
@@ -107,6 +107,9 @@ def Signature : Operand<i32> {
}
} // OperandType = "OPERAND_SIGNATURE"
+let OperandType = "OPERAND_TYPEINDEX" in
+def TypeIndex : Operand<i32>;
+
} // OperandNamespace = "WebAssembly"
//===----------------------------------------------------------------------===//
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
index f3384210b0e..354662d9d3d 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
@@ -14,7 +14,10 @@
//===----------------------------------------------------------------------===//
#include "WebAssemblyMCInstLower.h"
+#include "WebAssemblyAsmPrinter.h"
#include "WebAssemblyMachineFunctionInfo.h"
+#include "WebAssemblyRuntimeLibcallSignatures.h"
+#include "WebAssemblyUtilities.h"
#include "llvm/CodeGen/AsmPrinter.h"
#include "llvm/CodeGen/MachineFunction.h"
#include "llvm/IR/Constants.h"
@@ -22,18 +25,85 @@
#include "llvm/MC/MCContext.h"
#include "llvm/MC/MCExpr.h"
#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCSymbolWasm.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
MCSymbol *
WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
- return Printer.getSymbol(MO.getGlobal());
+ const GlobalValue *Global = MO.getGlobal();
+ MCSymbol *Sym = Printer.getSymbol(Global);
+ if (isa<MCSymbolELF>(Sym))
+ return Sym;
+
+ MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
+
+ if (const auto *FuncTy = dyn_cast<FunctionType>(Global->getValueType())) {
+ const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
+ const TargetMachine &TM = MF.getTarget();
+ const Function &CurrentFunc = *MF.getFunction();
+
+ SmallVector<unsigned, 4> Returns;
+ SmallVector<unsigned, 4> Params;
+
+ WebAssembly::ValType iPTR =
+ MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() ?
+ WebAssembly::ValType::I64 :
+ WebAssembly::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(unsigned(WebAssembly::toValType(ResultMVT)));
+ else
+ Params.push_back(unsigned(iPTR));
+
+ for (Type *Ty : FuncTy->params()) {
+ SmallVector<MVT, 4> ParamMVTs;
+ ComputeLegalValueVTs(CurrentFunc, TM, Ty, ParamMVTs);
+ for (MVT ParamMVT : ParamMVTs)
+ Params.push_back(unsigned(WebAssembly::toValType(ParamMVT)));
+ }
+
+ if (FuncTy->isVarArg())
+ Params.push_back(unsigned(iPTR));
+
+ WasmSym->setReturns(std::move(Returns));
+ WasmSym->setParams(std::move(Params));
+ WasmSym->setIsFunction(true);
+ }
+
+ return WasmSym;
}
MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
const MachineOperand &MO) const {
- return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
+ const char *Name = MO.getSymbolName();
+ MCSymbol *Sym = Printer.GetExternalSymbolSymbol(Name);
+ if (isa<MCSymbolELF>(Sym))
+ return Sym;
+
+ MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
+ const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
+
+ // __stack_pointer is a global variable; all other external symbols used by
+ // CodeGen are functions.
+ if (strcmp(Name, "__stack_pointer") == 0)
+ return WasmSym;
+
+ SmallVector<unsigned, 4> Returns;
+ SmallVector<unsigned, 4> Params;
+ GetSignature(Subtarget, Name, Returns, Params);
+
+ WasmSym->setReturns(std::move(Returns));
+ WasmSym->setParams(std::move(Params));
+ WasmSym->setIsFunction(true);
+
+ return WasmSym;
}
MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
@@ -42,6 +112,9 @@ MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
MCSymbolRefExpr::VariantKind VK =
IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
: MCSymbolRefExpr::VK_None;
+ if (!isa<MCSymbolELF>(Sym))
+ cast<MCSymbolWasm>(Sym)->setIsFunction(IsFunc);
+
const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
if (Offset != 0) {
@@ -54,10 +127,24 @@ MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
return MCOperand::createExpr(Expr);
}
+// Return the WebAssembly type associated with the given register class.
+static unsigned getType(const TargetRegisterClass *RC) {
+ if (RC == &WebAssembly::I32RegClass)
+ return unsigned(WebAssembly::ExprType::I32);
+ if (RC == &WebAssembly::I64RegClass)
+ return unsigned(WebAssembly::ExprType::I64);
+ if (RC == &WebAssembly::F32RegClass)
+ return unsigned(WebAssembly::ExprType::F32);
+ if (RC == &WebAssembly::F64RegClass)
+ return unsigned(WebAssembly::ExprType::F64);
+ llvm_unreachable("Unexpected register class");
+}
+
void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
MCInst &OutMI) const {
OutMI.setOpcode(MI->getOpcode());
+ const MCInstrDesc &Desc = MI->getDesc();
for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
const MachineOperand &MO = MI->getOperand(i);
@@ -80,6 +167,41 @@ void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
break;
}
case MachineOperand::MO_Immediate:
+ if (i < Desc.NumOperands) {
+ const MCOperandInfo &Info = Desc.OpInfo[i];
+ if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
+ MCSymbol *Sym = Printer.createTempSymbol("typeindex");
+ if (!isa<MCSymbolELF>(Sym)) {
+ SmallVector<unsigned, 4> Returns;
+ SmallVector<unsigned, 4> Params;
+
+ const MachineRegisterInfo &MRI =
+ MI->getParent()->getParent()->getRegInfo();
+ for (const MachineOperand &MO : MI->defs())
+ Returns.push_back(getType(MRI.getRegClass(MO.getReg())));
+ for (const MachineOperand &MO : MI->explicit_uses())
+ if (MO.isReg())
+ Params.push_back(getType(MRI.getRegClass(MO.getReg())));
+
+ // call_indirect instructions have a callee operand at the end which
+ // doesn't count as a param.
+ if (WebAssembly::isCallIndirect(*MI))
+ Params.pop_back();
+
+ MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
+ WasmSym->setReturns(std::move(Returns));
+ WasmSym->setParams(std::move(Params));
+ WasmSym->setIsFunction(true);
+
+ const MCExpr *Expr =
+ MCSymbolRefExpr::create(WasmSym,
+ MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX,
+ Ctx);
+ MCOp = MCOperand::createExpr(Expr);
+ break;
+ }
+ }
+ }
MCOp = MCOperand::createImm(MO.getImm());
break;
case MachineOperand::MO_FPImmediate: {
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.h b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.h
index ab4ba1c28d5..d1d2794c3b8 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.h
@@ -20,7 +20,7 @@
#include "llvm/Support/Compiler.h"
namespace llvm {
-class AsmPrinter;
+class WebAssemblyAsmPrinter;
class MCContext;
class MCSymbol;
class MachineInstr;
@@ -29,7 +29,7 @@ class MachineOperand;
/// This class is used to lower an MachineInstr into an MCInst.
class LLVM_LIBRARY_VISIBILITY WebAssemblyMCInstLower {
MCContext &Ctx;
- AsmPrinter &Printer;
+ WebAssemblyAsmPrinter &Printer;
MCSymbol *GetGlobalAddressSymbol(const MachineOperand &MO) const;
MCSymbol *GetExternalSymbolSymbol(const MachineOperand &MO) const;
@@ -37,7 +37,7 @@ class LLVM_LIBRARY_VISIBILITY WebAssemblyMCInstLower {
bool IsFunc) const;
public:
- WebAssemblyMCInstLower(MCContext &ctx, AsmPrinter &printer)
+ WebAssemblyMCInstLower(MCContext &ctx, WebAssemblyAsmPrinter &printer)
: Ctx(ctx), Printer(printer) {}
void Lower(const MachineInstr *MI, MCInst &OutMI) const;
};
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
index 756619bebbe..1fcbb7791d4 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
@@ -60,6 +60,8 @@ class WebAssemblyFunctionInfo final : public MachineFunctionInfo {
void addResult(MVT VT) { Results.push_back(VT); }
const std::vector<MVT> &getResults() const { return Results; }
+ void setNumLocals(size_t NumLocals) { Locals.resize(NumLocals, MVT::i32); }
+ void setLocal(size_t i, MVT VT) { Locals[i] = VT; }
void addLocal(MVT VT) { Locals.push_back(VT); }
const std::vector<MVT> &getLocals() const { return Locals; }
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
index 6303a1638bc..d2fbc5a2230 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
@@ -80,8 +80,18 @@ static bool MaybeRewriteToFallthrough(MachineInstr &MI, MachineBasicBlock &MBB,
return false;
if (&MBB != &MF.back())
return false;
- if (&MI != &MBB.back())
- return false;
+ if (MF.getSubtarget<WebAssemblySubtarget>()
+ .getTargetTriple().isOSBinFormatELF()) {
+ if (&MI != &MBB.back())
+ return false;
+ } else {
+ MachineBasicBlock::iterator End = MBB.end();
+ --End;
+ assert(End->getOpcode() == WebAssembly::END_FUNCTION);
+ --End;
+ if (&MI != &*End)
+ return false;
+ }
if (FallthroughOpc != WebAssembly::FALLTHROUGH_RETURN_VOID) {
// If the operand isn't stackified, insert a COPY to read the operand and
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
index 0651a1c11b4..04bf7b118b7 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
@@ -85,6 +85,14 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine(
// 'unreachable' instructions which is meant for that case.
this->Options.TrapUnreachable = true;
+ // WebAssembly treats each function as an independent unit. Force
+ // -ffunction-sections, effectively, so that we can emit them independently.
+ if (!TT.isOSBinFormatELF()) {
+ this->Options.FunctionSections = true;
+ this->Options.DataSections = true;
+ this->Options.UniqueSectionNames = true;
+ }
+
initAsmInfo();
// Note that we don't use setRequiresStructuredCFG(true). It disables
@@ -264,12 +272,14 @@ void WebAssemblyPassConfig::addPreEmitPass() {
addPass(createWebAssemblyRegColoring());
}
+ // Eliminate multiple-entry loops. Do this before inserting explicit get_local
+ // and set_local operators because we create a new variable that we want
+ // converted into a local.
+ addPass(createWebAssemblyFixIrreducibleControlFlow());
+
// Insert explicit get_local and set_local operators.
addPass(createWebAssemblyExplicitLocals());
- // Eliminate multiple-entry loops.
- addPass(createWebAssemblyFixIrreducibleControlFlow());
-
// Put the CFG in structured form; insert BLOCK and LOOP markers.
addPass(createWebAssemblyCFGStackify());
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
index a0049c147d2..2fb2327cf67 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
@@ -69,3 +69,20 @@ bool WebAssembly::isChild(const MachineInstr &MI,
return TargetRegisterInfo::isVirtualRegister(Reg) &&
MFI.isVRegStackified(Reg);
}
+
+bool WebAssembly::isCallIndirect(const MachineInstr &MI) {
+ switch (MI.getOpcode()) {
+ case WebAssembly::CALL_INDIRECT_VOID:
+ case WebAssembly::CALL_INDIRECT_I32:
+ case WebAssembly::CALL_INDIRECT_I64:
+ case WebAssembly::CALL_INDIRECT_F32:
+ case WebAssembly::CALL_INDIRECT_F64:
+ case WebAssembly::CALL_INDIRECT_v16i8:
+ case WebAssembly::CALL_INDIRECT_v8i16:
+ case WebAssembly::CALL_INDIRECT_v4i32:
+ case WebAssembly::CALL_INDIRECT_v4f32:
+ return true;
+ default:
+ return false;
+ }
+}
diff --git a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
index eb114403d14..cccc96152f2 100644
--- a/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
+++ b/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h
@@ -27,6 +27,7 @@ bool isArgument(const MachineInstr &MI);
bool isCopy(const MachineInstr &MI);
bool isTee(const MachineInstr &MI);
bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI);
+bool isCallIndirect(const MachineInstr &MI);
} // end namespace WebAssembly
} // end namespace llvm
OpenPOWER on IntegriCloud