diff options
Diffstat (limited to 'contrib/llvm/lib/Target/WebAssembly/MCTargetDesc')
11 files changed, 1382 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp new file mode 100644 index 000000000000..226a3b35f2cf --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp @@ -0,0 +1,206 @@ +//===-- WebAssemblyAsmBackend.cpp - WebAssembly Assembler Backend ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the WebAssemblyAsmBackend class. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/WebAssemblyFixupKinds.h" +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCAssembler.h" +#include "llvm/MC/MCDirectives.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MCWasmObjectWriter.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +namespace { +class WebAssemblyAsmBackendELF final : public MCAsmBackend { + bool Is64Bit; + +public: + explicit WebAssemblyAsmBackendELF(bool Is64Bit) + : MCAsmBackend(), Is64Bit(Is64Bit) {} + ~WebAssemblyAsmBackendELF() override {} + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef<char> Data, + uint64_t Value, bool IsPCRel) const override; + + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override; + + // No instruction requires relaxation + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + 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, + MCInst &Res) const override {} + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; +}; + +class WebAssemblyAsmBackend final : public MCAsmBackend { + bool Is64Bit; + +public: + explicit WebAssemblyAsmBackend(bool Is64Bit) + : MCAsmBackend(), Is64Bit(Is64Bit) {} + ~WebAssemblyAsmBackend() override {} + + unsigned getNumFixupKinds() const override { + return WebAssembly::NumTargetFixupKinds; + } + + const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override; + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef<char> Data, + uint64_t Value, bool IsPCRel) const override; + + std::unique_ptr<MCObjectWriter> + createObjectWriter(raw_pwrite_stream &OS) const override; + + // No instruction requires relaxation + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override { + return false; + } + + bool mayNeedRelaxation(const MCInst &Inst) const override { return false; } + + void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + MCInst &Res) const override {} + + bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override; +}; + +bool WebAssemblyAsmBackendELF::writeNopData(uint64_t Count, + MCObjectWriter *OW) const { + for (uint64_t i = 0; i < Count; ++i) + OW->write8(WebAssembly::Nop); + + return true; +} + +void WebAssemblyAsmBackendELF::applyFixup(const MCAssembler &Asm, + const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef<char> Data, + uint64_t Value, bool IsPCRel) const { + const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); + assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); + + unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; + if (Value == 0) + return; // Doesn't change encoding. + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned Offset = Fixup.getOffset(); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); + + // For each byte of the fragment that the fixup touches, mask in the + // bits from the fixup value. + for (unsigned i = 0; i != NumBytes; ++i) + Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); +} + +std::unique_ptr<MCObjectWriter> +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) + return true; + + for (uint64_t i = 0; i < Count; ++i) + OW->write8(WebAssembly::Nop); + + return true; +} + +void WebAssemblyAsmBackend::applyFixup(const MCAssembler &Asm, + const MCFixup &Fixup, + const MCValue &Target, + MutableArrayRef<char> Data, + uint64_t Value, bool IsPCRel) const { + const MCFixupKindInfo &Info = getFixupKindInfo(Fixup.getKind()); + assert(Info.Flags == 0 && "WebAssembly does not use MCFixupKindInfo flags"); + + unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; + if (Value == 0) + return; // Doesn't change encoding. + + // Shift the value into position. + Value <<= Info.TargetOffset; + + unsigned Offset = Fixup.getOffset(); + assert(Offset + NumBytes <= Data.size() && "Invalid fixup offset!"); + + // For each byte of the fragment that the fixup touches, mask in the + // bits from the fixup value. + for (unsigned i = 0; i != NumBytes; ++i) + Data[Offset + i] |= uint8_t((Value >> (i * 8)) & 0xff); +} + +std::unique_ptr<MCObjectWriter> +WebAssemblyAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { + return createWebAssemblyWasmObjectWriter(OS, Is64Bit); +} +} // end anonymous namespace + +MCAsmBackend *llvm::createWebAssemblyAsmBackend(const Triple &TT) { + if (TT.isOSBinFormatELF()) + return new WebAssemblyAsmBackendELF(TT.isArch64Bit()); + return new WebAssemblyAsmBackend(TT.isArch64Bit()); +} diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyELFObjectWriter.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyELFObjectWriter.cpp new file mode 100644 index 000000000000..b67ecfa455b3 --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyELFObjectWriter.cpp @@ -0,0 +1,68 @@ +//===-- WebAssemblyELFObjectWriter.cpp - WebAssembly ELF Writer -----------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file handles ELF-specific object emission, converting LLVM's +/// internal fixups into the appropriate relocations. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/ErrorHandling.h" +using namespace llvm; + +namespace { +class WebAssemblyELFObjectWriter final : public MCELFObjectTargetWriter { +public: + WebAssemblyELFObjectWriter(bool Is64Bit, uint8_t OSABI); + +protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; +}; +} // end anonymous namespace + +WebAssemblyELFObjectWriter::WebAssemblyELFObjectWriter(bool Is64Bit, + uint8_t OSABI) + : MCELFObjectTargetWriter(Is64Bit, OSABI, ELF::EM_WEBASSEMBLY, + /*HasRelocationAddend=*/false) {} + +unsigned WebAssemblyELFObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + // WebAssembly functions are not allocated in the address space. To resolve a + // pointer to a function, we must use a special relocation type. + if (const MCSymbolRefExpr *SyExp = + dyn_cast<MCSymbolRefExpr>(Fixup.getValue())) + if (SyExp->getKind() == MCSymbolRefExpr::VK_WebAssembly_FUNCTION) + return ELF::R_WEBASSEMBLY_FUNCTION; + + switch (Fixup.getKind()) { + case FK_Data_4: + assert(!is64Bit() && "4-byte relocations only supported on wasm32"); + return ELF::R_WEBASSEMBLY_DATA; + case FK_Data_8: + assert(is64Bit() && "8-byte relocations only supported on wasm64"); + return ELF::R_WEBASSEMBLY_DATA; + default: + llvm_unreachable("unimplemented fixup kind"); + } +} + +std::unique_ptr<MCObjectWriter> +llvm::createWebAssemblyELFObjectWriter(raw_pwrite_stream &OS, + bool Is64Bit, + uint8_t OSABI) { + auto MOTW = llvm::make_unique<WebAssemblyELFObjectWriter>(Is64Bit, OSABI); + return createELFObjectWriter(std::move(MOTW), OS, /*IsLittleEndian=*/true); +} diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h new file mode 100644 index 000000000000..b0af63c924bd --- /dev/null +++ b/contrib/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/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp new file mode 100644 index 000000000000..5f8c78ed1683 --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp @@ -0,0 +1,83 @@ +//===-- WebAssemblyMCAsmInfo.cpp - WebAssembly asm properties -------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file contains the declarations of the WebAssemblyMCAsmInfo +/// properties. +/// +//===----------------------------------------------------------------------===// + +#include "WebAssemblyMCAsmInfo.h" +#include "llvm/ADT/Triple.h" +using namespace llvm; + +#define DEBUG_TYPE "wasm-mc-asm-info" + +WebAssemblyMCAsmInfoELF::~WebAssemblyMCAsmInfoELF() {} + +WebAssemblyMCAsmInfoELF::WebAssemblyMCAsmInfoELF(const Triple &T) { + CodePointerSize = CalleeSaveStackSlotSize = T.isArch64Bit() ? 8 : 4; + + // TODO: What should MaxInstLength be? + + UseDataRegionDirectives = true; + + // Use .skip instead of .zero because .zero is confusing when used with two + // arguments (it doesn't actually zero things out). + ZeroDirective = "\t.skip\t"; + + Data8bitsDirective = "\t.int8\t"; + Data16bitsDirective = "\t.int16\t"; + Data32bitsDirective = "\t.int32\t"; + Data64bitsDirective = "\t.int64\t"; + + AlignmentIsInBytes = false; + COMMDirectiveAlignmentIsInBytes = false; + LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; + + SupportsDebugInformation = true; + + // For now, WebAssembly does not support exceptions. + ExceptionsType = ExceptionHandling::None; + + // TODO: UseIntegratedAssembler? + + // WebAssembly's stack is never executable. + UsesNonexecutableStackSection = false; +} + +WebAssemblyMCAsmInfo::~WebAssemblyMCAsmInfo() {} + +WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T) { + CodePointerSize = CalleeSaveStackSlotSize = T.isArch64Bit() ? 8 : 4; + + // TODO: What should MaxInstLength be? + + UseDataRegionDirectives = true; + + // Use .skip instead of .zero because .zero is confusing when used with two + // arguments (it doesn't actually zero things out). + ZeroDirective = "\t.skip\t"; + + Data8bitsDirective = "\t.int8\t"; + Data16bitsDirective = "\t.int16\t"; + Data32bitsDirective = "\t.int32\t"; + Data64bitsDirective = "\t.int64\t"; + + AlignmentIsInBytes = false; + COMMDirectiveAlignmentIsInBytes = false; + LCOMMDirectiveAlignmentType = LCOMM::Log2Alignment; + + SupportsDebugInformation = true; + + // For now, WebAssembly does not support exceptions. + ExceptionsType = ExceptionHandling::None; + + // TODO: UseIntegratedAssembler? +} diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.h new file mode 100644 index 000000000000..d9547096190e --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.h @@ -0,0 +1,39 @@ +//===-- WebAssemblyMCAsmInfo.h - WebAssembly asm properties -----*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file contains the declaration of the WebAssemblyMCAsmInfo class. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYMCASMINFO_H +#define LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYMCASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" +#include "llvm/MC/MCAsmInfoWasm.h" + +namespace llvm { + +class Triple; + +class WebAssemblyMCAsmInfoELF final : public MCAsmInfoELF { +public: + explicit WebAssemblyMCAsmInfoELF(const Triple &T); + ~WebAssemblyMCAsmInfoELF() override; +}; + +class WebAssemblyMCAsmInfo final : public MCAsmInfoWasm { +public: + explicit WebAssemblyMCAsmInfo(const Triple &T); + ~WebAssemblyMCAsmInfo() override; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp new file mode 100644 index 000000000000..77744e53d62f --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -0,0 +1,152 @@ +//=- WebAssemblyMCCodeEmitter.cpp - Convert WebAssembly code to machine code -// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file implements the WebAssemblyMCCodeEmitter class. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/WebAssemblyFixupKinds.h" +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/Statistic.h" +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/EndianStream.h" +#include "llvm/Support/LEB128.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "mccodeemitter" + +STATISTIC(MCNumEmitted, "Number of MC instructions emitted."); +STATISTIC(MCNumFixups, "Number of MC fixups created."); + +namespace { +class WebAssemblyMCCodeEmitter final : public MCCodeEmitter { + const MCInstrInfo &MCII; + + // Implementation generated by tablegen. + uint64_t getBinaryCodeForInstr(const MCInst &MI, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const; + + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const override; + +public: + WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {} +}; +} // end anonymous namespace + +MCCodeEmitter *llvm::createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII) { + return new WebAssemblyMCCodeEmitter(MCII); +} + +void WebAssemblyMCCodeEmitter::encodeInstruction( + const MCInst &MI, raw_ostream &OS, SmallVectorImpl<MCFixup> &Fixups, + const MCSubtargetInfo &STI) const { + uint64_t Start = OS.tell(); + + uint64_t Binary = getBinaryCodeForInstr(MI, Fixups, STI); + if (Binary <= UINT8_MAX) { + OS << uint8_t(Binary); + } else { + assert(Binary <= UINT16_MAX && "Several-byte opcodes not supported yet"); + OS << uint8_t(Binary >> 8) + << 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); + if (MO.isReg()) { + /* nothing to encode */ + } else if (MO.isImm()) { + if (i < Desc.getNumOperands()) { + assert(Desc.TSFlags == 0 && + "WebAssembly non-variable_ops don't use TSFlags"); + const MCOperandInfo &Info = Desc.OpInfo[i]; + if (Info.OperandType == WebAssembly::OPERAND_I32IMM) { + 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) { + llvm_unreachable("wasm globals should only be accessed symbolicly"); + } else if (Info.OperandType == WebAssembly::OPERAND_SIGNATURE) { + encodeSLEB128(int64_t(MO.getImm()), OS); + } else { + encodeULEB128(uint64_t(MO.getImm()), OS); + } + } else { + assert(Desc.TSFlags == (WebAssemblyII::VariableOpIsImmediate | + WebAssemblyII::VariableOpImmediateIsLabel)); + encodeULEB128(uint64_t(MO.getImm()), OS); + } + } else if (MO.isFPImm()) { + assert(i < Desc.getNumOperands() && + "Unexpected floating-point immediate as a non-fixed operand"); + assert(Desc.TSFlags == 0 && + "WebAssembly variable_ops floating point ops don't use TSFlags"); + const MCOperandInfo &Info = Desc.OpInfo[i]; + if (Info.OperandType == WebAssembly::OPERAND_F32IMM) { + // TODO: MC converts all floating point immediate operands to double. + // This is fine for numeric values, but may cause NaNs to change bits. + float f = float(MO.getFPImm()); + support::endian::Writer<support::little>(OS).write<float>(f); + } else { + assert(Info.OperandType == WebAssembly::OPERAND_F64IMM); + double d = MO.getFPImm(); + 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 = 5; + if (Info.OperandType == WebAssembly::OPERAND_I32IMM) { + FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32); + } 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); + } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) { + FixupKind = MCFixupKind(WebAssembly::fixup_code_global_index); + } else { + llvm_unreachable("unexpected symbolic operand kind"); + } + Fixups.push_back(MCFixup::create( + OS.tell() - Start, MO.getExpr(), + FixupKind, MI.getLoc())); + ++MCNumFixups; + encodeULEB128(0, OS, PaddedSize); + } else { + llvm_unreachable("unexpected operand kind"); + } + } + + ++MCNumEmitted; // Keep track of the # of mi's emitted. +} + +#include "WebAssemblyGenMCCodeEmitter.inc" diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp new file mode 100644 index 000000000000..e7c8809de70e --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp @@ -0,0 +1,140 @@ +//===-- WebAssemblyMCTargetDesc.cpp - WebAssembly Target Descriptions -----===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file provides WebAssembly-specific target descriptions. +/// +//===----------------------------------------------------------------------===// + +#include "WebAssemblyMCTargetDesc.h" +#include "InstPrinter/WebAssemblyInstPrinter.h" +#include "WebAssemblyMCAsmInfo.h" +#include "WebAssemblyTargetStreamer.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +using namespace llvm; + +#define DEBUG_TYPE "wasm-mc-target-desc" + +#define GET_INSTRINFO_MC_DESC +#include "WebAssemblyGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "WebAssemblyGenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "WebAssemblyGenRegisterInfo.inc" + +static MCAsmInfo *createMCAsmInfo(const MCRegisterInfo & /*MRI*/, + const Triple &TT) { + if (TT.isOSBinFormatELF()) + return new WebAssemblyMCAsmInfoELF(TT); + return new WebAssemblyMCAsmInfo(TT); +} + +static MCInstrInfo *createMCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitWebAssemblyMCInstrInfo(X); + return X; +} + +static MCRegisterInfo *createMCRegisterInfo(const Triple & /*T*/) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitWebAssemblyMCRegisterInfo(X, 0); + return X; +} + +static MCInstPrinter *createMCInstPrinter(const Triple & /*T*/, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + assert(SyntaxVariant == 0 && "WebAssembly only has one syntax variant"); + return new WebAssemblyInstPrinter(MAI, MII, MRI); +} + +static MCCodeEmitter *createCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo & /*MRI*/, + MCContext &Ctx) { + return createWebAssemblyMCCodeEmitter(MCII); +} + +static MCAsmBackend *createAsmBackend(const Target & /*T*/, + const MCSubtargetInfo &STI, + const MCRegisterInfo & /*MRI*/, + const MCTargetOptions & /*Options*/) { + return createWebAssemblyAsmBackend(STI.getTargetTriple()); +} + +static MCSubtargetInfo *createMCSubtargetInfo(const Triple &TT, StringRef CPU, + StringRef FS) { + return createWebAssemblyMCSubtargetInfoImpl(TT, CPU, FS); +} + +static MCTargetStreamer * +createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) { + const Triple &TT = STI.getTargetTriple(); + if (TT.isOSBinFormatELF()) + return new WebAssemblyTargetELFStreamer(S); + + return new WebAssemblyTargetWasmStreamer(S); +} + +static MCTargetStreamer *createAsmTargetStreamer(MCStreamer &S, + formatted_raw_ostream &OS, + MCInstPrinter * /*InstPrint*/, + bool /*isVerboseAsm*/) { + return new WebAssemblyTargetAsmStreamer(S, OS); +} + +// Force static initialization. +extern "C" void LLVMInitializeWebAssemblyTargetMC() { + for (Target *T : + {&getTheWebAssemblyTarget32(), &getTheWebAssemblyTarget64()}) { + // Register the MC asm info. + RegisterMCAsmInfoFn X(*T, createMCAsmInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(*T, createMCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(*T, createMCRegisterInfo); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(*T, createMCInstPrinter); + + // Register the MC code emitter. + TargetRegistry::RegisterMCCodeEmitter(*T, createCodeEmitter); + + // Register the ASM Backend. + TargetRegistry::RegisterMCAsmBackend(*T, createAsmBackend); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(*T, createMCSubtargetInfo); + + // Register the object target streamer. + TargetRegistry::RegisterObjectTargetStreamer(*T, + createObjectTargetStreamer); + // Register the asm target streamer. + TargetRegistry::RegisterAsmTargetStreamer(*T, createAsmTargetStreamer); + } +} + +wasm::ValType WebAssembly::toValType(const MVT &Ty) { + switch (Ty.SimpleTy) { + case MVT::i32: return wasm::ValType::I32; + case MVT::i64: return wasm::ValType::I64; + case MVT::f32: return wasm::ValType::F32; + case MVT::f64: return wasm::ValType::F64; + default: llvm_unreachable("unexpected type"); + } +} diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h new file mode 100644 index 000000000000..7dca89ab822d --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -0,0 +1,185 @@ +//==- WebAssemblyMCTargetDesc.h - WebAssembly Target Descriptions -*- C++ -*-=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file provides WebAssembly-specific target descriptions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYMCTARGETDESC_H +#define LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYMCTARGETDESC_H + +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/Support/DataTypes.h" +#include <memory> + +namespace llvm { + +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCObjectWriter; +class MCSubtargetInfo; +class MVT; +class Target; +class Triple; +class raw_pwrite_stream; + +Target &getTheWebAssemblyTarget32(); +Target &getTheWebAssemblyTarget64(); + +MCCodeEmitter *createWebAssemblyMCCodeEmitter(const MCInstrInfo &MCII); + +MCAsmBackend *createWebAssemblyAsmBackend(const Triple &TT); + +std::unique_ptr<MCObjectWriter> +createWebAssemblyELFObjectWriter(raw_pwrite_stream &OS, + bool Is64Bit, uint8_t OSABI); + +std::unique_ptr<MCObjectWriter> +createWebAssemblyWasmObjectWriter(raw_pwrite_stream &OS, + bool Is64Bit); + +namespace WebAssembly { +enum OperandType { + /// Basic block label in a branch construct. + OPERAND_BASIC_BLOCK = MCOI::OPERAND_FIRST_TARGET, + /// Local index. + OPERAND_LOCAL, + /// Global index. + OPERAND_GLOBAL, + /// 32-bit integer immediates. + OPERAND_I32IMM, + /// 64-bit integer immediates. + OPERAND_I64IMM, + /// 32-bit floating-point immediates. + OPERAND_F32IMM, + /// 64-bit floating-point immediates. + OPERAND_F64IMM, + /// 32-bit unsigned function indices. + OPERAND_FUNCTION32, + /// 32-bit unsigned memory offsets. + OPERAND_OFFSET32, + /// p2align immediate for load and store address alignment. + OPERAND_P2ALIGN, + /// signature immediate for block/loop. + OPERAND_SIGNATURE, + /// type signature immediate for call_indirect. + OPERAND_TYPEINDEX, +}; +} // end namespace WebAssembly + +namespace WebAssemblyII { +enum { + // For variadic instructions, this flag indicates whether an operand + // in the variable_ops range is an immediate value. + VariableOpIsImmediate = (1 << 0), + // For immediate values in the variable_ops range, this flag indicates + // whether the value represents a control-flow label. + VariableOpImmediateIsLabel = (1 << 1) +}; +} // end namespace WebAssemblyII + +} // end namespace llvm + +// Defines symbolic names for WebAssembly registers. This defines a mapping from +// register name to register number. +// +#define GET_REGINFO_ENUM +#include "WebAssemblyGenRegisterInfo.inc" + +// Defines symbolic names for the WebAssembly instructions. +// +#define GET_INSTRINFO_ENUM +#include "WebAssemblyGenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "WebAssemblyGenSubtargetInfo.inc" + +namespace llvm { +namespace WebAssembly { + +/// Return the default p2align value for a load or store with the given opcode. +inline unsigned GetDefaultP2Align(unsigned Opcode) { + switch (Opcode) { + case WebAssembly::LOAD8_S_I32: + case WebAssembly::LOAD8_U_I32: + case WebAssembly::LOAD8_S_I64: + case WebAssembly::LOAD8_U_I64: + case WebAssembly::ATOMIC_LOAD8_U_I32: + case WebAssembly::ATOMIC_LOAD8_U_I64: + case WebAssembly::STORE8_I32: + case WebAssembly::STORE8_I64: + return 0; + case WebAssembly::LOAD16_S_I32: + case WebAssembly::LOAD16_U_I32: + case WebAssembly::LOAD16_S_I64: + case WebAssembly::LOAD16_U_I64: + case WebAssembly::ATOMIC_LOAD16_U_I32: + case WebAssembly::ATOMIC_LOAD16_U_I64: + case WebAssembly::STORE16_I32: + case WebAssembly::STORE16_I64: + return 1; + case WebAssembly::LOAD_I32: + case WebAssembly::LOAD_F32: + case WebAssembly::STORE_I32: + case WebAssembly::STORE_F32: + case WebAssembly::LOAD32_S_I64: + case WebAssembly::LOAD32_U_I64: + case WebAssembly::STORE32_I64: + case WebAssembly::ATOMIC_LOAD_I32: + case WebAssembly::ATOMIC_LOAD32_U_I64: + return 2; + case WebAssembly::LOAD_I64: + case WebAssembly::LOAD_F64: + case WebAssembly::STORE_I64: + case WebAssembly::STORE_F64: + case WebAssembly::ATOMIC_LOAD_I64: + return 3; + default: + llvm_unreachable("Only loads and stores have p2align values"); + } +} + +/// The operand number of the load or store address in load/store instructions. +static const unsigned LoadAddressOperandNo = 3; +static const unsigned StoreAddressOperandNo = 2; + +/// The operand number of the load or store p2align in load/store instructions. +static const unsigned LoadP2AlignOperandNo = 1; +static const unsigned StoreP2AlignOperandNo = 0; + +/// This is used to indicate block signatures. +enum class ExprType { + Void = -0x40, + I32 = -0x01, + I64 = -0x02, + F32 = -0x03, + F64 = -0x04, + I8x16 = -0x05, + I16x8 = -0x06, + I32x4 = -0x07, + F32x4 = -0x08, + B8x16 = -0x09, + B16x8 = -0x0a, + B32x4 = -0x0b +}; + +/// Instruction opcodes emitted via means other than CodeGen. +static const unsigned Nop = 0x01; +static const unsigned End = 0x0b; + +wasm::ValType toValType(const MVT &Ty); + +} // end namespace WebAssembly +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp new file mode 100644 index 000000000000..0ca52ad651b5 --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -0,0 +1,264 @@ +//==-- WebAssemblyTargetStreamer.cpp - WebAssembly Target Streamer Methods --=// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file defines WebAssembly-specific target streamer classes. +/// These are for implementing support for target-specific assembly directives. +/// +//===----------------------------------------------------------------------===// + +#include "WebAssemblyTargetStreamer.h" +#include "InstPrinter/WebAssemblyInstPrinter.h" +#include "WebAssemblyMCTargetDesc.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSectionWasm.h" +#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" +using namespace llvm; + +WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S) + : MCTargetStreamer(S) {} + +void WebAssemblyTargetStreamer::emitValueType(wasm::ValType Type) { + Streamer.EmitSLEB128IntValue(int32_t(Type)); +} + +WebAssemblyTargetAsmStreamer::WebAssemblyTargetAsmStreamer( + MCStreamer &S, formatted_raw_ostream &OS) + : WebAssemblyTargetStreamer(S), OS(OS) {} + +WebAssemblyTargetELFStreamer::WebAssemblyTargetELFStreamer(MCStreamer &S) + : WebAssemblyTargetStreamer(S) {} + +WebAssemblyTargetWasmStreamer::WebAssemblyTargetWasmStreamer(MCStreamer &S) + : WebAssemblyTargetStreamer(S) {} + +static void PrintTypes(formatted_raw_ostream &OS, ArrayRef<MVT> Types) { + bool First = true; + for (MVT Type : Types) { + if (First) + First = false; + else + OS << ", "; + OS << WebAssembly::TypeToString(Type); + } + OS << '\n'; +} + +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(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) { + if (!Types.empty()) { + OS << "\t.local \t"; + PrintTypes(OS, Types); + } +} + +void WebAssemblyTargetAsmStreamer::emitGlobal( + ArrayRef<wasm::Global> Globals) { + if (!Globals.empty()) { + OS << "\t.globalvar \t"; + + bool First = true; + for (const wasm::Global &G : Globals) { + if (First) + First = false; + else + OS << ", "; + OS << WebAssembly::TypeToString(G.Type); + if (!G.InitialModule.empty()) + OS << '=' << G.InitialModule << ':' << G.InitialName; + else + OS << '=' << G.InitialValue; + } + OS << '\n'; + } +} + +void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; } + +void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType( + MCSymbol *Symbol, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) { + OS << "\t.functype\t" << Symbol->getName(); + if (Results.empty()) + OS << ", void"; + else { + assert(Results.size() == 1); + OS << ", " << WebAssembly::TypeToString(Results.front()); + } + for (auto Ty : Params) + OS << ", " << WebAssembly::TypeToString(Ty); + OS << '\n'; +} + +void WebAssemblyTargetAsmStreamer::emitGlobalImport(StringRef name) { + OS << "\t.import_global\t" << name << '\n'; +} + +void WebAssemblyTargetAsmStreamer::emitIndIdx(const MCExpr *Value) { + OS << "\t.indidx \t" << *Value << '\n'; +} + +void WebAssemblyTargetELFStreamer::emitParam(MCSymbol *Symbol, + ArrayRef<MVT> Types) { + // Nothing to emit; params are declared as part of the function signature. +} + +void WebAssemblyTargetELFStreamer::emitResult(MCSymbol *Symbol, + ArrayRef<MVT> Types) { + // Nothing to emit; results are declared as part of the function signature. +} + +void WebAssemblyTargetELFStreamer::emitLocal(ArrayRef<MVT> Types) { + Streamer.EmitULEB128IntValue(Types.size()); + for (MVT Type : Types) + emitValueType(WebAssembly::toValType(Type)); +} + +void WebAssemblyTargetELFStreamer::emitGlobal( + ArrayRef<wasm::Global> Globals) { + llvm_unreachable(".globalvar encoding not yet implemented"); +} + +void WebAssemblyTargetELFStreamer::emitEndFunc() { + Streamer.EmitIntValue(WebAssembly::End, 1); +} + +void WebAssemblyTargetELFStreamer::emitIndIdx(const MCExpr *Value) { + llvm_unreachable(".indidx encoding not yet implemented"); +} + +void WebAssemblyTargetELFStreamer::emitIndirectFunctionType( + MCSymbol *Symbol, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) { + // Nothing to emit here. TODO: Re-design how linking works and re-evaluate + // whether it's necessary for .o files to declare indirect function types. +} + +void WebAssemblyTargetELFStreamer::emitGlobalImport(StringRef name) { +} + +void WebAssemblyTargetWasmStreamer::emitParam(MCSymbol *Symbol, + ArrayRef<MVT> Types) { + SmallVector<wasm::ValType, 4> Params; + for (MVT Ty : Types) + Params.push_back(WebAssembly::toValType(Ty)); + + cast<MCSymbolWasm>(Symbol)->setParams(std::move(Params)); +} + +void WebAssemblyTargetWasmStreamer::emitResult(MCSymbol *Symbol, + ArrayRef<MVT> Types) { + SmallVector<wasm::ValType, 4> Returns; + for (MVT Ty : Types) + Returns.push_back(WebAssembly::toValType(Ty)); + + cast<MCSymbolWasm>(Symbol)->setReturns(std::move(Returns)); +} + +void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef<MVT> Types) { + 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); + emitValueType(WebAssembly::toValType(Pair.first)); + } +} + +void WebAssemblyTargetWasmStreamer::emitGlobal( + ArrayRef<wasm::Global> Globals) { + // Encode the globals use by the funciton into the special .global_variables + // section. This will later be decoded and turned into contents for the + // Globals Section. + Streamer.PushSection(); + Streamer.SwitchSection(Streamer.getContext().getWasmSection( + ".global_variables", SectionKind::getMetadata())); + for (const wasm::Global &G : Globals) { + Streamer.EmitIntValue(int32_t(G.Type), 1); + Streamer.EmitIntValue(G.Mutable, 1); + if (G.InitialModule.empty()) { + Streamer.EmitIntValue(0, 1); // indicate that we have an int value + Streamer.EmitSLEB128IntValue(0); + } else { + Streamer.EmitIntValue(1, 1); // indicate that we have a module import + Streamer.EmitBytes(G.InitialModule); + Streamer.EmitIntValue(0, 1); // nul-terminate + Streamer.EmitBytes(G.InitialName); + Streamer.EmitIntValue(0, 1); // nul-terminate + } + } + Streamer.PopSection(); +} + +void WebAssemblyTargetWasmStreamer::emitEndFunc() { + llvm_unreachable(".end_func is not needed for direct wasm output"); +} + +void WebAssemblyTargetWasmStreamer::emitIndIdx(const MCExpr *Value) { + llvm_unreachable(".indidx encoding not yet implemented"); +} + +void WebAssemblyTargetWasmStreamer::emitIndirectFunctionType( + MCSymbol *Symbol, SmallVectorImpl<MVT> &Params, + SmallVectorImpl<MVT> &Results) { + MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Symbol); + if (WasmSym->isFunction()) { + // Symbol already has its arguments and result set. + return; + } + + SmallVector<wasm::ValType, 4> ValParams; + for (MVT Ty : Params) + ValParams.push_back(WebAssembly::toValType(Ty)); + + SmallVector<wasm::ValType, 1> ValResults; + for (MVT Ty : Results) + ValResults.push_back(WebAssembly::toValType(Ty)); + + WasmSym->setParams(std::move(ValParams)); + WasmSym->setReturns(std::move(ValResults)); + WasmSym->setIsFunction(true); +} + +void WebAssemblyTargetWasmStreamer::emitGlobalImport(StringRef name) { + llvm_unreachable(".global_import is not needed for direct wasm output"); +} diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h new file mode 100644 index 000000000000..2cb21a20580b --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -0,0 +1,112 @@ +//==-- WebAssemblyTargetStreamer.h - WebAssembly Target Streamer -*- C++ -*-==// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file declares WebAssembly-specific target streamer classes. +/// These are for implementing support for target-specific assembly directives. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYTARGETSTREAMER_H +#define LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYTARGETSTREAMER_H + +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/CodeGen/MachineValueType.h" +#include "llvm/MC/MCStreamer.h" + +namespace llvm { + +class MCELFStreamer; +class MCWasmStreamer; + +/// WebAssembly-specific streamer interface, to implement support +/// WebAssembly-specific assembly directives. +class WebAssemblyTargetStreamer : public MCTargetStreamer { +public: + explicit WebAssemblyTargetStreamer(MCStreamer &S); + + /// .param + virtual void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) = 0; + /// .result + virtual void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) = 0; + /// .local + virtual void emitLocal(ArrayRef<MVT> Types) = 0; + /// .globalvar + virtual void emitGlobal(ArrayRef<wasm::Global> Globals) = 0; + /// .endfunc + virtual void emitEndFunc() = 0; + /// .functype + virtual void emitIndirectFunctionType(MCSymbol *Symbol, + SmallVectorImpl<MVT> &Params, + SmallVectorImpl<MVT> &Results) = 0; + /// .indidx + virtual void emitIndIdx(const MCExpr *Value) = 0; + /// .import_global + virtual void emitGlobalImport(StringRef name) = 0; + +protected: + void emitValueType(wasm::ValType Type); +}; + +/// This part is for ascii assembly output +class WebAssemblyTargetAsmStreamer final : public WebAssemblyTargetStreamer { + formatted_raw_ostream &OS; + +public: + WebAssemblyTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS); + + void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override; + void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override; + void emitLocal(ArrayRef<MVT> Types) override; + void emitGlobal(ArrayRef<wasm::Global> Globals) override; + void emitEndFunc() override; + void emitIndirectFunctionType(MCSymbol *Symbol, + SmallVectorImpl<MVT> &Params, + SmallVectorImpl<MVT> &Results) override; + void emitIndIdx(const MCExpr *Value) override; + void emitGlobalImport(StringRef name) override; +}; + +/// This part is for ELF object output +class WebAssemblyTargetELFStreamer final : public WebAssemblyTargetStreamer { +public: + explicit WebAssemblyTargetELFStreamer(MCStreamer &S); + + void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override; + void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override; + void emitLocal(ArrayRef<MVT> Types) override; + void emitGlobal(ArrayRef<wasm::Global> Globals) override; + void emitEndFunc() override; + void emitIndirectFunctionType(MCSymbol *Symbol, + SmallVectorImpl<MVT> &Params, + SmallVectorImpl<MVT> &Results) override; + void emitIndIdx(const MCExpr *Value) override; + void emitGlobalImport(StringRef name) override; +}; + +/// This part is for Wasm object output +class WebAssemblyTargetWasmStreamer final : public WebAssemblyTargetStreamer { +public: + explicit WebAssemblyTargetWasmStreamer(MCStreamer &S); + + void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override; + void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override; + void emitLocal(ArrayRef<MVT> Types) override; + void emitGlobal(ArrayRef<wasm::Global> Globals) override; + void emitEndFunc() override; + void emitIndirectFunctionType(MCSymbol *Symbol, + SmallVectorImpl<MVT> &Params, + SmallVectorImpl<MVT> &Results) override; + void emitIndIdx(const MCExpr *Value) override; + void emitGlobalImport(StringRef name) override; +}; + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp new file mode 100644 index 000000000000..39abde26df7f --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -0,0 +1,102 @@ +//===-- WebAssemblyWasmObjectWriter.cpp - WebAssembly Wasm Writer ---------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// \brief This file handles Wasm-specific object emission, converting LLVM's +/// internal fixups into the appropriate relocations. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/WebAssemblyFixupKinds.h" +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "llvm/BinaryFormat/Wasm.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCFixup.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/MC/MCWasmObjectWriter.h" +#include "llvm/MC/MCValue.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; + +namespace { +class WebAssemblyWasmObjectWriter final : public MCWasmObjectTargetWriter { +public: + explicit WebAssemblyWasmObjectWriter(bool Is64Bit); + +private: + unsigned getRelocType(const MCValue &Target, + const MCFixup &Fixup) const override; +}; +} // end anonymous namespace + +WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit) + : MCWasmObjectTargetWriter(Is64Bit) {} + +// Test whether the given expression computes a function address. +static bool IsFunctionExpr(const MCExpr *Expr) { + if (auto SyExp = dyn_cast<MCSymbolRefExpr>(Expr)) + return cast<MCSymbolWasm>(SyExp->getSymbol()).isFunction(); + + if (auto BinOp = dyn_cast<MCBinaryExpr>(Expr)) + return IsFunctionExpr(BinOp->getLHS()) != IsFunctionExpr(BinOp->getRHS()); + + if (auto UnOp = dyn_cast<MCUnaryExpr>(Expr)) + return IsFunctionExpr(UnOp->getSubExpr()); + + return false; +} + +static bool IsFunctionType(const MCValue &Target) { + const MCSymbolRefExpr *RefA = Target.getSymA(); + return RefA && RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX; +} + +unsigned +WebAssemblyWasmObjectWriter::getRelocType(const MCValue &Target, + const MCFixup &Fixup) const { + // 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()); + + switch (unsigned(Fixup.getKind())) { + case WebAssembly::fixup_code_global_index: + return wasm::R_WEBASSEMBLY_GLOBAL_INDEX_LEB; + case WebAssembly::fixup_code_sleb128_i32: + if (IsFunction) + return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB; + return wasm::R_WEBASSEMBLY_MEMORY_ADDR_SLEB; + case WebAssembly::fixup_code_sleb128_i64: + llvm_unreachable("fixup_sleb128_i64 not implemented yet"); + case WebAssembly::fixup_code_uleb128_i32: + if (IsFunctionType(Target)) + return wasm::R_WEBASSEMBLY_TYPE_INDEX_LEB; + if (IsFunction) + return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB; + return wasm::R_WEBASSEMBLY_MEMORY_ADDR_LEB; + case FK_Data_4: + if (IsFunction) + return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32; + return wasm::R_WEBASSEMBLY_MEMORY_ADDR_I32; + case FK_Data_8: + llvm_unreachable("FK_Data_8 not implemented yet"); + default: + llvm_unreachable("unimplemented fixup kind"); + } +} + +std::unique_ptr<MCObjectWriter> +llvm::createWebAssemblyWasmObjectWriter(raw_pwrite_stream &OS, + bool Is64Bit) { + auto MOTW = llvm::make_unique<WebAssemblyWasmObjectWriter>(Is64Bit); + return createWasmObjectWriter(std::move(MOTW), OS); +} |