diff options
Diffstat (limited to 'llvm/lib/Target/WebAssembly')
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 |