diff options
| author | Dan Gohman <dan433584@gmail.com> | 2017-02-24 23:18:00 +0000 |
|---|---|---|
| committer | Dan Gohman <dan433584@gmail.com> | 2017-02-24 23:18:00 +0000 |
| commit | d934cb8806dbddcbdf70fadf9b125af626fbcac3 (patch) | |
| tree | 9791d4ffccafec115dbadb7e1f9cce94963dbc1c /llvm/lib/Target/WebAssembly/MCTargetDesc | |
| parent | fb34a35c4eb11d30d9ba225c9daf84cf63f100fb (diff) | |
| download | bcm5719-llvm-d934cb8806dbddcbdf70fadf9b125af626fbcac3.tar.gz bcm5719-llvm-d934cb8806dbddcbdf70fadf9b125af626fbcac3.zip | |
[WebAssembly] Basic support for Wasm object file encoding.
With the "wasm32-unknown-unknown-wasm" triple, this allows writing out
simple wasm object files, and is another step in a larger series toward
migrating from ELF to general wasm object support. Note that this code
and the binary format itself is still experimental.
llvm-svn: 296190
Diffstat (limited to 'llvm/lib/Target/WebAssembly/MCTargetDesc')
7 files changed, 213 insertions, 41 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, |

