diff options
author | dim <dim@FreeBSD.org> | 2017-09-26 19:56:36 +0000 |
---|---|---|
committer | Luiz Souza <luiz@netgate.com> | 2018-02-21 15:12:19 -0300 |
commit | 1dcd2e8d24b295bc73e513acec2ed1514bb66be4 (patch) | |
tree | 4bd13a34c251e980e1a6b13584ca1f63b0dfe670 /contrib/llvm/lib/Target/WebAssembly | |
parent | f45541ca2a56a1ba1202f94c080b04e96c1fa239 (diff) | |
download | FreeBSD-src-1dcd2e8d24b295bc73e513acec2ed1514bb66be4.zip FreeBSD-src-1dcd2e8d24b295bc73e513acec2ed1514bb66be4.tar.gz |
Merge clang, llvm, lld, lldb, compiler-rt and libc++ 5.0.0 release.
MFC r309126 (by emaste):
Correct lld llvm-tblgen dependency file name
MFC r309169:
Get rid of separate Subversion mergeinfo properties for llvm-dwarfdump
and llvm-lto. The mergeinfo confuses Subversion enormously, and these
directories will just use the mergeinfo for llvm itself.
MFC r312765:
Pull in r276136 from upstream llvm trunk (by Wei Mi):
Use ValueOffsetPair to enhance value reuse during SCEV expansion.
In D12090, the ExprValueMap was added to reuse existing value during
SCEV expansion. However, const folding and sext/zext distribution can
make the reuse still difficult.
A simplified case is: suppose we know S1 expands to V1 in
ExprValueMap, and
S1 = S2 + C_a
S3 = S2 + C_b
where C_a and C_b are different SCEVConstants. Then we'd like to
expand S3 as V1 - C_a + C_b instead of expanding S2 literally. It is
helpful when S2 is a complex SCEV expr and S2 has no entry in
ExprValueMap, which is usually caused by the fact that S3 is
generated from S1 after const folding.
In order to do that, we represent ExprValueMap as a mapping from SCEV
to ValueOffsetPair. We will save both S1->{V1, 0} and S2->{V1, C_a}
into the ExprValueMap when we create SCEV for V1. When S3 is
expanded, it will first expand S2 to V1 - C_a because of S2->{V1,
C_a} in the map, then expand S3 to V1 - C_a + C_b.
Differential Revision: https://reviews.llvm.org/D21313
This should fix assertion failures when building OpenCV >= 3.1.
PR: 215649
MFC r312831:
Revert r312765 for now, since it causes assertions when building
lang/spidermonkey24.
Reported by: antoine
PR: 215649
MFC r316511 (by jhb):
Add an implementation of __ffssi2() derived from __ffsdi2().
Newer versions of GCC include an __ffssi2() symbol in libgcc and the
compiler can emit calls to it in generated code. This is true for at
least GCC 6.2 when compiling world for mips and mips64.
Reviewed by: jmallett, dim
Sponsored by: DARPA / AFRL
Differential Revision: https://reviews.freebsd.org/D10086
MFC r318601 (by adrian):
[libcompiler-rt] add bswapdi2/bswapsi2
This is required for mips gcc 6.3 userland to build/run.
Reviewed by: emaste, dim
Approved by: emaste
Differential Revision: https://reviews.freebsd.org/D10838
MFC r318884 (by emaste):
lldb: map TRAP_CAP to a trace trap
In the absense of a more specific handler for TRAP_CAP (generated by
ENOTCAPABLE or ECAPMODE while in capability mode) treat it as a trace
trap.
Example usage (testing the bug in PR219173):
% proccontrol -m trapcap lldb usr.bin/hexdump/obj/hexdump -- -Cv -s 1 /bin/ls
...
(lldb) run
Process 12980 launching
Process 12980 launched: '.../usr.bin/hexdump/obj/hexdump' (x86_64)
Process 12980 stopped
* thread #1, stop reason = trace
frame #0: 0x0000004b80c65f1a libc.so.7`__sys_lseek + 10
...
In the future we should have LLDB control the trapcap procctl itself
(as it does with ASLR), as well as report a specific stop reason.
This change eliminates an assertion failure from LLDB for now.
MFC r319796:
Remove a few unneeded files from libllvm, libclang and liblldb.
MFC r319885 (by emaste):
lld: ELF: Fix ICF crash on absolute symbol relocations.
If two sections contained relocations to absolute symbols with the same
value we would crash when trying to access their sections. Add a check that
both symbols point to sections before accessing their sections, and treat
absolute symbols as equal if their values are equal.
Obtained from: LLD commit r292578
MFC r319918:
Revert r319796 for now, it can cause undefined references when linking
in some circumstances.
Reported by: Shawn Webb <shawn.webb@hardenedbsd.org>
MFC r319957 (by emaste):
lld: Add armelf emulation mode
Obtained from: LLD r305375
MFC r321369:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
5.0.0 (trunk r308421). Upstream has branched for the 5.0.0 release,
which should be in about a month. Please report bugs and regressions,
so we can get them into the release.
Please note that from 3.5.0 onwards, clang, llvm and lldb require C++11
support to build; see UPDATING for more information.
MFC r321420:
Add a few more object files to liblldb, which should solve errors when
linking the lldb executable in some cases. In particular, when the
-ffunction-sections -fdata-sections options are turned off, or
ineffective.
Reported by: Shawn Webb, Mark Millard
MFC r321433:
Cleanup stale Options.inc files from the previous libllvm build for
clang 4.0.0. Otherwise, these can get included before the two newly
generated ones (which are different) for clang 5.0.0.
Reported by: Mark Millard
MFC r321439 (by bdrewery):
Move llvm Options.inc hack from r321433 for NO_CLEAN to lib/clang/libllvm.
The files are only ever generated to .OBJDIR, not to WORLDTMP (as a
sysroot) and are only ever included from a compilation. So using
a beforebuild target here removes the file before the compilation
tries to include it.
MFC r321664:
Pull in r308891 from upstream llvm trunk (by Benjamin Kramer):
[CodeGenPrepare] Cut off FindAllMemoryUses if there are too many uses.
This avoids excessive compile time. The case I'm looking at is
Function.cpp from an old version of LLVM that still had the giant
memcmp string matcher in it. Before r308322 this compiled in about 2
minutes, after it, clang takes infinite* time to compile it. With
this patch we're at 5 min, which is still bad but this is a
pathological case.
The cut off at 20 uses was chosen by looking at other cut-offs in LLVM
for user scanning. It's probably too high, but does the job and is
very unlikely to regress anything.
Fixes PR33900.
* I'm impatient and aborted after 15 minutes, on the bug report it was
killed after 2h.
Pull in r308986 from upstream llvm trunk (by Simon Pilgrim):
[X86][CGP] Reduce memcmp() expansion to 2 load pairs (PR33914)
D35067/rL308322 attempted to support up to 4 load pairs for memcmp
inlining which resulted in regressions for some optimized libc memcmp
implementations (PR33914).
Until we can match these more optimal cases, this patch reduces the
memcmp expansion to a maximum of 2 load pairs (which matches what we
do for -Os).
This patch should be considered for the 5.0.0 release branch as well
Differential Revision: https://reviews.llvm.org/D35830
These fix a hang (or extremely long compile time) when building older
LLVM ports.
Reported by: antoine
PR: 219139
MFC r321719:
Pull in r309503 from upstream clang trunk (by Richard Smith):
PR33902: Invalidate line number cache when adding more text to
existing buffer.
This led to crashes as the line number cache would report a bogus
line number for a line of code, and we'd try to find a nonexistent
column within the line when printing diagnostics.
This fixes an assertion when building the graphics/champlain port.
Reported by: antoine, kwm
PR: 219139
MFC r321723:
Upgrade our copies of clang, llvm, lld and lldb to r309439 from the
upstream release_50 branch. This is just after upstream's 5.0.0-rc1.
MFC r322320:
Upgrade our copies of clang, llvm and libc++ to r310316 from the
upstream release_50 branch.
MFC r322326 (by emaste):
lldb: Make i386-*-freebsd expression work on JIT path
* Enable i386 ABI creation for freebsd
* Added an extra argument in ABISysV_i386::PrepareTrivialCall for mmap
syscall
* Unlike linux, the last argument of mmap is actually 64-bit(off_t).
This requires us to push an additional word for the higher order bits.
* Prior to this change, ktrace dump will show mmap failures due to
invalid argument coming from the 6th mmap argument.
Submitted by: Karnajit Wangkhem
Differential Revision: https://reviews.llvm.org/D34776
MFC r322360 (by emaste):
lldb: Report inferior signals as signals, not exceptions, on FreeBSD
This is the FreeBSD equivalent of LLVM r238549.
This serves 2 purposes:
* LLDB should handle inferior process signals SIGSEGV/SIGILL/SIGBUS/
SIGFPE the way it is suppose to be handled. Prior to this fix these
signals will neither create a coredump, nor exit from the debugger
or work for signal handling scenario.
* eInvalidCrashReason need not report "unknown crash reason" if we have
a valid si_signo
llvm.org/pr23699
Patch by Karnajit Wangkhem
Differential Revision: https://reviews.llvm.org/D35223
Submitted by: Karnajit Wangkhem
Obtained from: LLVM r310591
MFC r322474 (by emaste):
lld: Add `-z muldefs` option.
Obtained from: LLVM r310757
MFC r322740:
Upgrade our copies of clang, llvm, lld and libc++ to r311219 from the
upstream release_50 branch.
MFC r322855:
Upgrade our copies of clang, llvm, lldb and compiler-rt to r311606 from
the upstream release_50 branch.
As of this version, lib/msun's trig test should also work correctly
again (see bug 220989 for more information).
PR: 220989
MFC r323112:
Upgrade our copies of clang, llvm, lldb and compiler-rt to r312293 from
the upstream release_50 branch. This corresponds to 5.0.0 rc4.
As of this version, the cad/stepcode port should now compile in a more
reasonable time on i386 (see bug 221836 for more information).
PR: 221836
MFC r323245:
Upgrade our copies of clang, llvm, lld, lldb, compiler-rt and libc++ to
5.0.0 release (upstream r312559).
Release notes for llvm, clang and lld will be available here soon:
<http://releases.llvm.org/5.0.0/docs/ReleaseNotes.html>
<http://releases.llvm.org/5.0.0/tools/clang/docs/ReleaseNotes.html>
<http://releases.llvm.org/5.0.0/tools/lld/docs/ReleaseNotes.html>
Relnotes: yes
(cherry picked from commit 12cd91cf4c6b96a24427c0de5374916f2808d263)
Diffstat (limited to 'contrib/llvm/lib/Target/WebAssembly')
58 files changed, 2914 insertions, 631 deletions
diff --git a/contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp b/contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp index b4763ca..9be11da 100644 --- a/contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/Disassembler/WebAssemblyDisassembler.cpp @@ -15,8 +15,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCInst.h" @@ -63,89 +63,8 @@ extern "C" void LLVMInitializeWebAssemblyDisassembler() { MCDisassembler::DecodeStatus WebAssemblyDisassembler::getInstruction( MCInst &MI, uint64_t &Size, ArrayRef<uint8_t> Bytes, uint64_t /*Address*/, raw_ostream &OS, raw_ostream &CS) const { - Size = 0; - uint64_t Pos = 0; - - // Read the opcode. - if (Pos + sizeof(uint64_t) > Bytes.size()) - return MCDisassembler::Fail; - uint64_t Opcode = support::endian::read64le(Bytes.data() + Pos); - Pos += sizeof(uint64_t); - - if (Opcode >= WebAssembly::INSTRUCTION_LIST_END) - return MCDisassembler::Fail; - - MI.setOpcode(Opcode); - const MCInstrDesc &Desc = MCII->get(Opcode); - unsigned NumFixedOperands = Desc.NumOperands; - - // If it's variadic, read the number of extra operands. - unsigned NumExtraOperands = 0; - if (Desc.isVariadic()) { - if (Pos + sizeof(uint64_t) > Bytes.size()) - return MCDisassembler::Fail; - NumExtraOperands = support::endian::read64le(Bytes.data() + Pos); - Pos += sizeof(uint64_t); - } - - // Read the fixed operands. These are described by the MCInstrDesc. - for (unsigned i = 0; i < NumFixedOperands; ++i) { - const MCOperandInfo &Info = Desc.OpInfo[i]; - switch (Info.OperandType) { - case MCOI::OPERAND_IMMEDIATE: - case WebAssembly::OPERAND_LOCAL: - case WebAssembly::OPERAND_P2ALIGN: - case WebAssembly::OPERAND_BASIC_BLOCK: { - if (Pos + sizeof(uint64_t) > Bytes.size()) - return MCDisassembler::Fail; - uint64_t Imm = support::endian::read64le(Bytes.data() + Pos); - Pos += sizeof(uint64_t); - MI.addOperand(MCOperand::createImm(Imm)); - break; - } - case MCOI::OPERAND_REGISTER: { - if (Pos + sizeof(uint64_t) > Bytes.size()) - return MCDisassembler::Fail; - uint64_t Reg = support::endian::read64le(Bytes.data() + Pos); - Pos += sizeof(uint64_t); - MI.addOperand(MCOperand::createReg(Reg)); - break; - } - case WebAssembly::OPERAND_F32IMM: - case WebAssembly::OPERAND_F64IMM: { - // TODO: MC converts all floating point immediate operands to double. - // This is fine for numeric values, but may cause NaNs to change bits. - if (Pos + sizeof(uint64_t) > Bytes.size()) - return MCDisassembler::Fail; - uint64_t Bits = support::endian::read64le(Bytes.data() + Pos); - Pos += sizeof(uint64_t); - double Imm; - memcpy(&Imm, &Bits, sizeof(Imm)); - MI.addOperand(MCOperand::createFPImm(Imm)); - break; - } - default: - llvm_unreachable("unimplemented operand kind"); - } - } - // Read the extra operands. - assert(NumExtraOperands == 0 || Desc.isVariadic()); - for (unsigned i = 0; i < NumExtraOperands; ++i) { - if (Pos + sizeof(uint64_t) > Bytes.size()) - return MCDisassembler::Fail; - if (Desc.TSFlags & WebAssemblyII::VariableOpIsImmediate) { - // Decode extra immediate operands. - uint64_t Imm = support::endian::read64le(Bytes.data() + Pos); - MI.addOperand(MCOperand::createImm(Imm)); - } else { - // Decode extra register operands. - uint64_t Reg = support::endian::read64le(Bytes.data() + Pos); - MI.addOperand(MCOperand::createReg(Reg)); - } - Pos += sizeof(uint64_t); - } + // TODO: Implement disassembly. - Size = Pos; - return MCDisassembler::Success; + return MCDisassembler::Fail; } diff --git a/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp b/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp index 0af13cf..f31dde0 100644 --- a/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.cpp @@ -242,3 +242,17 @@ const char *llvm::WebAssembly::TypeToString(MVT Ty) { llvm_unreachable("unsupported type"); } } + +const char *llvm::WebAssembly::TypeToString(wasm::ValType Type) { + switch (Type) { + case wasm::ValType::I32: + return "i32"; + case wasm::ValType::I64: + return "i64"; + case wasm::ValType::F32: + return "f32"; + case wasm::ValType::F64: + return "f64"; + } + llvm_unreachable("unsupported type"); +} diff --git a/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h b/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h index d11f99c..b1de84d 100644 --- a/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h +++ b/contrib/llvm/lib/Target/WebAssembly/InstPrinter/WebAssemblyInstPrinter.h @@ -16,6 +16,7 @@ #define LLVM_LIB_TARGET_WEBASSEMBLY_INSTPRINTER_WEBASSEMBLYINSTPRINTER_H #include "llvm/ADT/SmallVector.h" +#include "llvm/BinaryFormat/Wasm.h" #include "llvm/CodeGen/MachineValueType.h" #include "llvm/MC/MCInstPrinter.h" @@ -50,6 +51,7 @@ public: namespace WebAssembly { const char *TypeToString(MVT Ty); +const char *TypeToString(wasm::ValType Type); } // end namespace WebAssembly diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp index 97454a8..1357cb5 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp @@ -12,6 +12,7 @@ /// //===----------------------------------------------------------------------===// +#include "MCTargetDesc/WebAssemblyFixupKinds.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "llvm/MC/MCAsmBackend.h" #include "llvm/MC/MCAssembler.h" @@ -22,20 +23,22 @@ #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 WebAssemblyAsmBackend final : public MCAsmBackend { +class WebAssemblyAsmBackendELF final : public MCAsmBackend { bool Is64Bit; public: - explicit WebAssemblyAsmBackend(bool Is64Bit) + explicit WebAssemblyAsmBackendELF(bool Is64Bit) : MCAsmBackend(), Is64Bit(Is64Bit) {} - ~WebAssemblyAsmBackend() override {} + ~WebAssemblyAsmBackendELF() override {} - void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize, + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef<char> Data, uint64_t Value, bool IsPCRel) const override; MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override; @@ -61,6 +64,98 @@ public: 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; + + 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); +} + +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) @@ -72,13 +167,15 @@ bool WebAssemblyAsmBackend::writeNopData(uint64_t Count, return true; } -void WebAssemblyAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, - unsigned DataSize, uint64_t Value, - bool IsPCRel) const { +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 = (Info.TargetSize + 7) / 8; + unsigned NumBytes = alignTo(Info.TargetSize, 8) / 8; if (Value == 0) return; // Doesn't change encoding. @@ -86,7 +183,7 @@ void WebAssemblyAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, Value <<= Info.TargetOffset; unsigned Offset = Fixup.getOffset(); - assert(Offset + NumBytes <= DataSize && "Invalid fixup offset!"); + 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. @@ -96,10 +193,12 @@ void WebAssemblyAsmBackend::applyFixup(const MCFixup &Fixup, char *Data, MCObjectWriter * WebAssemblyAsmBackend::createObjectWriter(raw_pwrite_stream &OS) const { - return createWebAssemblyELFObjectWriter(OS, Is64Bit, 0); + 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/WebAssemblyFixupKinds.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h new file mode 100644 index 0000000..b0af63c --- /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 index d8c3921..5f8c78e 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.cpp @@ -19,10 +19,10 @@ using namespace llvm; #define DEBUG_TYPE "wasm-mc-asm-info" -WebAssemblyMCAsmInfo::~WebAssemblyMCAsmInfo() {} +WebAssemblyMCAsmInfoELF::~WebAssemblyMCAsmInfoELF() {} -WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T) { - PointerSize = CalleeSaveStackSlotSize = T.isArch64Bit() ? 8 : 4; +WebAssemblyMCAsmInfoELF::WebAssemblyMCAsmInfoELF(const Triple &T) { + CodePointerSize = CalleeSaveStackSlotSize = T.isArch64Bit() ? 8 : 4; // TODO: What should MaxInstLength be? @@ -51,3 +51,33 @@ WebAssemblyMCAsmInfo::WebAssemblyMCAsmInfo(const Triple &T) { // 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 index 2dcf2cd..d954709 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.h +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCAsmInfo.h @@ -16,12 +16,19 @@ #define LLVM_LIB_TARGET_WEBASSEMBLY_MCTARGETDESC_WEBASSEMBLYMCASMINFO_H #include "llvm/MC/MCAsmInfoELF.h" +#include "llvm/MC/MCAsmInfoWasm.h" namespace llvm { class Triple; -class WebAssemblyMCAsmInfo final : public MCAsmInfoELF { +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; diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp index d0e0eec..3e3b52f 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp @@ -12,6 +12,7 @@ /// //===----------------------------------------------------------------------===// +#include "MCTargetDesc/WebAssemblyFixupKinds.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "llvm/ADT/STLExtras.h" #include "llvm/ADT/Statistic.h" @@ -46,7 +47,7 @@ class WebAssemblyMCCodeEmitter final : public MCCodeEmitter { const MCSubtargetInfo &STI) const override; public: - explicit WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {} + WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii) : MCII(mcii) {} }; } // end anonymous namespace @@ -63,6 +64,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); @@ -77,6 +85,10 @@ 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) { + 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); } @@ -102,14 +114,31 @@ 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 if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) { + FixupKind = MCFixupKind(WebAssembly::fixup_code_global_index); + 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/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp index 3dc1ded..9580eea 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.cpp @@ -36,6 +36,8 @@ using namespace llvm; static MCAsmInfo *createMCAsmInfo(const MCRegisterInfo & /*MRI*/, const Triple &TT) { + if (TT.isOSBinFormatELF()) + return new WebAssemblyMCAsmInfoELF(TT); return new WebAssemblyMCAsmInfo(TT); } @@ -71,7 +73,7 @@ static MCInstPrinter *createMCInstPrinter(const Triple & /*T*/, static MCCodeEmitter *createCodeEmitter(const MCInstrInfo &MCII, const MCRegisterInfo & /*MRI*/, - MCContext & /*Ctx*/) { + MCContext &Ctx) { return createWebAssemblyMCCodeEmitter(MCII); } @@ -88,8 +90,12 @@ static MCSubtargetInfo *createMCSubtargetInfo(const Triple &TT, StringRef CPU, } static MCTargetStreamer * -createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo & /*STI*/) { - return new WebAssemblyTargetELFStreamer(S); +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, @@ -135,12 +141,12 @@ extern "C" void LLVMInitializeWebAssemblyTargetMC() { } } -WebAssembly::ValType WebAssembly::toValType(const MVT &Ty) { +wasm::ValType WebAssembly::toValType(const MVT &Ty) { switch (Ty.SimpleTy) { - case MVT::i32: return WebAssembly::ValType::I32; - case MVT::i64: return WebAssembly::ValType::I64; - case MVT::f32: return WebAssembly::ValType::F32; - case MVT::f64: return WebAssembly::ValType::F64; + 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 index 8583b77..4d676c3 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h @@ -15,6 +15,7 @@ #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" @@ -41,12 +42,17 @@ MCAsmBackend *createWebAssemblyAsmBackend(const Triple &TT); MCObjectWriter *createWebAssemblyELFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit, uint8_t OSABI); +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. @@ -62,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 @@ -141,40 +149,25 @@ static const unsigned StoreP2AlignOperandNo = 0; /// This is used to indicate block signatures. enum class ExprType { - Void = 0x40, - I32 = 0x7f, - I64 = 0x7e, - F32 = 0x7d, - F64 = 0x7c, - I8x16 = 0x7b, - I16x8 = 0x7a, - I32x4 = 0x79, - F32x4 = 0x78, - B8x16 = 0x77, - B16x8 = 0x76, - B32x4 = 0x75 -}; - -/// This is used to indicate local types. -enum class ValType { - I32 = 0x7f, - I64 = 0x7e, - F32 = 0x7d, - F64 = 0x7c, - I8x16 = 0x7b, - I16x8 = 0x7a, - I32x4 = 0x79, - F32x4 = 0x78, - B8x16 = 0x77, - B16x8 = 0x76, - B32x4 = 0x75 + 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; -ValType toValType(const MVT &Ty); +wasm::ValType toValType(const MVT &Ty); } // end namespace WebAssembly } // end namespace llvm diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp index 3cee8b2..00bf024 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp @@ -18,9 +18,11 @@ #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/Support/ELF.h" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/FormattedStream.h" using namespace llvm; @@ -28,6 +30,10 @@ 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) {} @@ -35,6 +41,9 @@ WebAssemblyTargetAsmStreamer::WebAssemblyTargetAsmStreamer( 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) { @@ -47,14 +56,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) { @@ -64,11 +87,36 @@ void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<MVT> 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::emitStackPointer(uint32_t Index) { + OS << "\t.stack_pointer\t" << Index << '\n'; +} + void WebAssemblyTargetAsmStreamer::emitEndFunc() { OS << "\t.endfunc\n"; } void WebAssemblyTargetAsmStreamer::emitIndirectFunctionType( - StringRef name, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) { - OS << "\t.functype\t" << name; + MCSymbol *Symbol, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) { + OS << "\t.functype\t" << Symbol->getName(); if (Results.empty()) OS << ", void"; else { @@ -88,18 +136,30 @@ 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. } void WebAssemblyTargetELFStreamer::emitLocal(ArrayRef<MVT> Types) { Streamer.EmitULEB128IntValue(Types.size()); for (MVT Type : Types) - Streamer.EmitIntValue(int64_t(WebAssembly::toValType(Type)), 1); + emitValueType(WebAssembly::toValType(Type)); +} + +void WebAssemblyTargetELFStreamer::emitGlobal( + ArrayRef<wasm::Global> Globals) { + llvm_unreachable(".globalvar encoding not yet implemented"); +} + +void WebAssemblyTargetELFStreamer::emitStackPointer( + uint32_t Index) { + llvm_unreachable(".stack_pointer encoding not yet implemented"); } void WebAssemblyTargetELFStreamer::emitEndFunc() { @@ -111,10 +171,110 @@ void WebAssemblyTargetELFStreamer::emitIndIdx(const MCExpr *Value) { } void WebAssemblyTargetELFStreamer::emitIndirectFunctionType( - StringRef name, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) { + 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) { -}
\ No newline at end of file +} + +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", 0, 0)); + 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::emitStackPointer(uint32_t Index) { + Streamer.PushSection(); + Streamer.SwitchSection(Streamer.getContext() + .getWasmSection(".stack_pointer", 0, 0)); + Streamer.EmitIntValue(Index, 4); + 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) { +} diff --git a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h index 23ac319..102d721 100644 --- a/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h @@ -16,12 +16,14 @@ #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. @@ -30,23 +32,28 @@ 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; + /// .globalvar + virtual void emitGlobal(ArrayRef<wasm::Global> Globals) = 0; + /// .stack_pointer + virtual void emitStackPointer(uint32_t Index) = 0; /// .endfunc virtual void emitEndFunc() = 0; /// .functype - virtual void emitIndirectFunctionType(StringRef name, + virtual void emitIndirectFunctionType(MCSymbol *Symbol, SmallVectorImpl<MVT> &Params, - SmallVectorImpl<MVT> &Results) { - llvm_unreachable("emitIndirectFunctionType not implemented"); - } + 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 @@ -56,11 +63,13 @@ 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 emitGlobal(ArrayRef<wasm::Global> Globals) override; + void emitStackPointer(uint32_t Index) override; void emitEndFunc() override; - void emitIndirectFunctionType(StringRef name, + void emitIndirectFunctionType(MCSymbol *Symbol, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) override; void emitIndIdx(const MCExpr *Value) override; @@ -72,11 +81,31 @@ 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 emitGlobal(ArrayRef<wasm::Global> Globals) override; + void emitStackPointer(uint32_t Index) 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 emitStackPointer(uint32_t Index) override; void emitEndFunc() override; - void emitIndirectFunctionType(StringRef name, + void emitIndirectFunctionType(MCSymbol *Symbol, SmallVectorImpl<MVT> &Params, SmallVectorImpl<MVT> &Results) override; void emitIndIdx(const MCExpr *Value) override; 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 0000000..9cf7782 --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp @@ -0,0 +1,100 @@ +//===-- 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/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_GLOBAL_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_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, + bool Is64Bit) { + MCWasmObjectTargetWriter *MOTW = new WebAssemblyWasmObjectWriter(Is64Bit); + return createWasmObjectWriter(MOTW, OS); +} diff --git a/contrib/llvm/lib/Target/WebAssembly/README.txt b/contrib/llvm/lib/Target/WebAssembly/README.txt index 64991ad..3433b15 100644 --- a/contrib/llvm/lib/Target/WebAssembly/README.txt +++ b/contrib/llvm/lib/Target/WebAssembly/README.txt @@ -145,3 +145,24 @@ WebAssemblyRegStackify could be extended, or possibly rewritten, to take advantage of the new opportunities. //===---------------------------------------------------------------------===// + +Add support for mergeable sections in the Wasm writer, such as for strings and +floating-point constants. + +//===---------------------------------------------------------------------===// + +The function @dynamic_alloca_redzone in test/CodeGen/WebAssembly/userstack.ll +ends up with a tee_local in its prolog which has an unused result, requiring +an extra drop: + + get_global $push8=, 0 + tee_local $push9=, 1, $pop8 + drop $pop9 + [...] + +The prologue code initially thinks it needs an FP register, but later it +turns out to be unneeded, so one could either approach this by being more +clever about not inserting code for an FP in the first place, or optimizing +away the copy later. + +//===---------------------------------------------------------------------===// diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssembly.h b/contrib/llvm/lib/Target/WebAssembly/WebAssembly.h index 8738263..e04c4db 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssembly.h +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssembly.h @@ -46,6 +46,7 @@ FunctionPass *createWebAssemblyRegStackify(); FunctionPass *createWebAssemblyRegColoring(); FunctionPass *createWebAssemblyExplicitLocals(); FunctionPass *createWebAssemblyFixIrreducibleControlFlow(); +FunctionPass *createWebAssemblyCFGSort(); FunctionPass *createWebAssemblyCFGStackify(); FunctionPass *createWebAssemblyLowerBrUnless(); FunctionPass *createWebAssemblyRegNumbering(); diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp index 5b4b82e..211358a 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp +++ b/contrib/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,16 +22,19 @@ #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/CodeGen/MachineModuleInfoImpls.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" +#include "llvm/MC/MCSymbolWasm.h" +#include "llvm/MC/MCSymbolELF.h" #include "llvm/Support/Debug.h" #include "llvm/Support/TargetRegistry.h" #include "llvm/Support/raw_ostream.h" @@ -38,65 +42,16 @@ 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. //===----------------------------------------------------------------------===// MVT WebAssemblyAsmPrinter::getRegType(unsigned RegNo) const { + const TargetRegisterInfo *TRI = Subtarget->getRegisterInfo(); const TargetRegisterClass *TRC = MRI->getRegClass(RegNo); for (MVT T : {MVT::i32, MVT::i64, MVT::f32, MVT::f64, MVT::v16i8, MVT::v8i16, MVT::v4i32, MVT::v4f32}) - if (TRC->hasType(T)) + if (TRI->isTypeLegalForClass(*TRC, T)) return T; DEBUG(errs() << "Unknown type for register number: " << RegNo); llvm_unreachable("Unknown register type"); @@ -129,13 +84,16 @@ void WebAssemblyAsmPrinter::EmitEndOfAsmFile(Module &M) { SmallVector<MVT, 4> Results; SmallVector<MVT, 4> Params; ComputeSignatureVTs(F, TM, Params, Results); - getTargetStreamer()->emitIndirectFunctionType(F.getName(), Params, + getTargetStreamer()->emitIndirectFunctionType(getSymbol(&F), Params, Results); } } 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 +108,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 +126,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 +154,8 @@ void WebAssemblyAsmPrinter::EmitFunctionBodyStart() { } void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() { - getTargetStreamer()->emitEndFunc(); + if (TM.getTargetTriple().isOSBinFormatELF()) + getTargetStreamer()->emitEndFunc(); } void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { @@ -252,9 +213,10 @@ void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) { const MCExpr *WebAssemblyAsmPrinter::lowerConstant(const Constant *CV) { if (const GlobalValue *GV = dyn_cast<GlobalValue>(CV)) - if (GV->getValueType()->isFunctionTy()) + if (GV->getValueType()->isFunctionTy()) { return MCSymbolRefExpr::create( getSymbol(GV), MCSymbolRefExpr::VK_WebAssembly_FUNCTION, OutContext); + } return AsmPrinter::lowerConstant(CV); } diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h new file mode 100644 index 0000000..c8917b8 --- /dev/null +++ b/contrib/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/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp new file mode 100644 index 0000000..7001117 --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGSort.cpp @@ -0,0 +1,277 @@ +//===-- WebAssemblyCFGSort.cpp - CFG Sorting ------------------------------===// +// +// 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 a CFG sorting pass. +/// +/// This pass reorders the blocks in a function to put them into topological +/// order, ignoring loop backedges, and without any loop being interrupted +/// by a block not dominated by the loop header, with special care to keep the +/// order as similar as possible to the original order. +/// +////===----------------------------------------------------------------------===// + +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" +#include "WebAssemblySubtarget.h" +#include "WebAssemblyUtilities.h" +#include "llvm/ADT/PriorityQueue.h" +#include "llvm/ADT/SetVector.h" +#include "llvm/CodeGen/MachineDominators.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineLoopInfo.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/CodeGen/Passes.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +#define DEBUG_TYPE "wasm-cfg-sort" + +namespace { +class WebAssemblyCFGSort final : public MachineFunctionPass { + StringRef getPassName() const override { return "WebAssembly CFG Sort"; } + + void getAnalysisUsage(AnalysisUsage &AU) const override { + AU.setPreservesCFG(); + AU.addRequired<MachineDominatorTree>(); + AU.addPreserved<MachineDominatorTree>(); + AU.addRequired<MachineLoopInfo>(); + AU.addPreserved<MachineLoopInfo>(); + MachineFunctionPass::getAnalysisUsage(AU); + } + + bool runOnMachineFunction(MachineFunction &MF) override; + +public: + static char ID; // Pass identification, replacement for typeid + WebAssemblyCFGSort() : MachineFunctionPass(ID) {} +}; +} // end anonymous namespace + +char WebAssemblyCFGSort::ID = 0; +FunctionPass *llvm::createWebAssemblyCFGSort() { + return new WebAssemblyCFGSort(); +} + +static void MaybeUpdateTerminator(MachineBasicBlock *MBB) { +#ifndef NDEBUG + bool AnyBarrier = false; +#endif + bool AllAnalyzable = true; + for (const MachineInstr &Term : MBB->terminators()) { +#ifndef NDEBUG + AnyBarrier |= Term.isBarrier(); +#endif + AllAnalyzable &= Term.isBranch() && !Term.isIndirectBranch(); + } + assert((AnyBarrier || AllAnalyzable) && + "AnalyzeBranch needs to analyze any block with a fallthrough"); + if (AllAnalyzable) + MBB->updateTerminator(); +} + +namespace { +/// Sort blocks by their number. +struct CompareBlockNumbers { + bool operator()(const MachineBasicBlock *A, + const MachineBasicBlock *B) const { + return A->getNumber() > B->getNumber(); + } +}; +/// Sort blocks by their number in the opposite order.. +struct CompareBlockNumbersBackwards { + bool operator()(const MachineBasicBlock *A, + const MachineBasicBlock *B) const { + return A->getNumber() < B->getNumber(); + } +}; +/// Bookkeeping for a loop to help ensure that we don't mix blocks not dominated +/// by the loop header among the loop's blocks. +struct Entry { + const MachineLoop *Loop; + unsigned NumBlocksLeft; + + /// List of blocks not dominated by Loop's header that are deferred until + /// after all of Loop's blocks have been seen. + std::vector<MachineBasicBlock *> Deferred; + + explicit Entry(const MachineLoop *L) + : Loop(L), NumBlocksLeft(L->getNumBlocks()) {} +}; +} // end anonymous namespace + +/// Sort the blocks, taking special care to make sure that loops are not +/// interrupted by blocks not dominated by their header. +/// TODO: There are many opportunities for improving the heuristics here. +/// Explore them. +static void SortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI, + const MachineDominatorTree &MDT) { + // Prepare for a topological sort: Record the number of predecessors each + // block has, ignoring loop backedges. + MF.RenumberBlocks(); + SmallVector<unsigned, 16> NumPredsLeft(MF.getNumBlockIDs(), 0); + for (MachineBasicBlock &MBB : MF) { + unsigned N = MBB.pred_size(); + if (MachineLoop *L = MLI.getLoopFor(&MBB)) + if (L->getHeader() == &MBB) + for (const MachineBasicBlock *Pred : MBB.predecessors()) + if (L->contains(Pred)) + --N; + NumPredsLeft[MBB.getNumber()] = N; + } + + // Topological sort the CFG, with additional constraints: + // - Between a loop header and the last block in the loop, there can be + // no blocks not dominated by the loop header. + // - It's desirable to preserve the original block order when possible. + // We use two ready lists; Preferred and Ready. Preferred has recently + // processed successors, to help preserve block sequences from the original + // order. Ready has the remaining ready blocks. + PriorityQueue<MachineBasicBlock *, std::vector<MachineBasicBlock *>, + CompareBlockNumbers> + Preferred; + PriorityQueue<MachineBasicBlock *, std::vector<MachineBasicBlock *>, + CompareBlockNumbersBackwards> + Ready; + SmallVector<Entry, 4> Loops; + for (MachineBasicBlock *MBB = &MF.front();;) { + const MachineLoop *L = MLI.getLoopFor(MBB); + if (L) { + // If MBB is a loop header, add it to the active loop list. We can't put + // any blocks that it doesn't dominate until we see the end of the loop. + if (L->getHeader() == MBB) + Loops.push_back(Entry(L)); + // For each active loop the block is in, decrement the count. If MBB is + // the last block in an active loop, take it off the list and pick up any + // blocks deferred because the header didn't dominate them. + for (Entry &E : Loops) + if (E.Loop->contains(MBB) && --E.NumBlocksLeft == 0) + for (auto DeferredBlock : E.Deferred) + Ready.push(DeferredBlock); + while (!Loops.empty() && Loops.back().NumBlocksLeft == 0) + Loops.pop_back(); + } + // The main topological sort logic. + for (MachineBasicBlock *Succ : MBB->successors()) { + // Ignore backedges. + if (MachineLoop *SuccL = MLI.getLoopFor(Succ)) + if (SuccL->getHeader() == Succ && SuccL->contains(MBB)) + continue; + // Decrement the predecessor count. If it's now zero, it's ready. + if (--NumPredsLeft[Succ->getNumber()] == 0) + Preferred.push(Succ); + } + // Determine the block to follow MBB. First try to find a preferred block, + // to preserve the original block order when possible. + MachineBasicBlock *Next = nullptr; + while (!Preferred.empty()) { + Next = Preferred.top(); + Preferred.pop(); + // If X isn't dominated by the top active loop header, defer it until that + // loop is done. + if (!Loops.empty() && + !MDT.dominates(Loops.back().Loop->getHeader(), Next)) { + Loops.back().Deferred.push_back(Next); + Next = nullptr; + continue; + } + // If Next was originally ordered before MBB, and it isn't because it was + // loop-rotated above the header, it's not preferred. + if (Next->getNumber() < MBB->getNumber() && + (!L || !L->contains(Next) || + L->getHeader()->getNumber() < Next->getNumber())) { + Ready.push(Next); + Next = nullptr; + continue; + } + break; + } + // If we didn't find a suitable block in the Preferred list, check the + // general Ready list. + if (!Next) { + // If there are no more blocks to process, we're done. + if (Ready.empty()) { + MaybeUpdateTerminator(MBB); + break; + } + for (;;) { + Next = Ready.top(); + Ready.pop(); + // If Next isn't dominated by the top active loop header, defer it until + // that loop is done. + if (!Loops.empty() && + !MDT.dominates(Loops.back().Loop->getHeader(), Next)) { + Loops.back().Deferred.push_back(Next); + continue; + } + break; + } + } + // Move the next block into place and iterate. + Next->moveAfter(MBB); + MaybeUpdateTerminator(MBB); + MBB = Next; + } + assert(Loops.empty() && "Active loop list not finished"); + MF.RenumberBlocks(); + +#ifndef NDEBUG + SmallSetVector<MachineLoop *, 8> OnStack; + + // Insert a sentinel representing the degenerate loop that starts at the + // function entry block and includes the entire function as a "loop" that + // executes once. + OnStack.insert(nullptr); + + for (auto &MBB : MF) { + assert(MBB.getNumber() >= 0 && "Renumbered blocks should be non-negative."); + + MachineLoop *Loop = MLI.getLoopFor(&MBB); + if (Loop && &MBB == Loop->getHeader()) { + // Loop header. The loop predecessor should be sorted above, and the other + // predecessors should be backedges below. + for (auto Pred : MBB.predecessors()) + assert( + (Pred->getNumber() < MBB.getNumber() || Loop->contains(Pred)) && + "Loop header predecessors must be loop predecessors or backedges"); + assert(OnStack.insert(Loop) && "Loops should be declared at most once."); + } else { + // Not a loop header. All predecessors should be sorted above. + for (auto Pred : MBB.predecessors()) + assert(Pred->getNumber() < MBB.getNumber() && + "Non-loop-header predecessors should be topologically sorted"); + assert(OnStack.count(MLI.getLoopFor(&MBB)) && + "Blocks must be nested in their loops"); + } + while (OnStack.size() > 1 && &MBB == LoopBottom(OnStack.back())) + OnStack.pop_back(); + } + assert(OnStack.pop_back_val() == nullptr && + "The function entry block shouldn't actually be a loop header"); + assert(OnStack.empty() && + "Control flow stack pushes and pops should be balanced."); +#endif +} + +bool WebAssemblyCFGSort::runOnMachineFunction(MachineFunction &MF) { + DEBUG(dbgs() << "********** CFG Sorting **********\n" + "********** Function: " + << MF.getName() << '\n'); + + const auto &MLI = getAnalysis<MachineLoopInfo>(); + auto &MDT = getAnalysis<MachineDominatorTree>(); + // Liveness is not tracked for VALUE_STACK physreg. + MF.getRegInfo().invalidateLiveness(); + + // Sort the blocks, with contiguous loops. + SortBlocks(MF, MLI, MDT); + + return true; +} diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp index 49b9754..21e0f6b 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp @@ -10,12 +10,7 @@ /// \file /// \brief This file implements a CFG stacking pass. /// -/// This pass reorders the blocks in a function to put them into topological -/// order, ignoring loop backedges, and without any loop being interrupted -/// by a block not dominated by the loop header, with special care to keep the -/// order as similar as possible to the original order. -/// -/// Then, it inserts BLOCK and LOOP markers to mark the start of scopes, since +/// This pass inserts BLOCK and LOOP markers to mark the start of scopes, since /// scope boundaries serve as the labels for WebAssembly's control transfers. /// /// This is sufficient to convert arbitrary CFGs into a form that works on @@ -23,13 +18,11 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyUtilities.h" -#include "llvm/ADT/PriorityQueue.h" -#include "llvm/ADT/SetVector.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstrBuilder.h" @@ -68,217 +61,6 @@ FunctionPass *llvm::createWebAssemblyCFGStackify() { return new WebAssemblyCFGStackify(); } -/// Return the "bottom" block of a loop. This differs from -/// MachineLoop::getBottomBlock in that it works even if the loop is -/// discontiguous. -static MachineBasicBlock *LoopBottom(const MachineLoop *Loop) { - MachineBasicBlock *Bottom = Loop->getHeader(); - for (MachineBasicBlock *MBB : Loop->blocks()) - if (MBB->getNumber() > Bottom->getNumber()) - Bottom = MBB; - return Bottom; -} - -static void MaybeUpdateTerminator(MachineBasicBlock *MBB) { -#ifndef NDEBUG - bool AnyBarrier = false; -#endif - bool AllAnalyzable = true; - for (const MachineInstr &Term : MBB->terminators()) { -#ifndef NDEBUG - AnyBarrier |= Term.isBarrier(); -#endif - AllAnalyzable &= Term.isBranch() && !Term.isIndirectBranch(); - } - assert((AnyBarrier || AllAnalyzable) && - "AnalyzeBranch needs to analyze any block with a fallthrough"); - if (AllAnalyzable) - MBB->updateTerminator(); -} - -namespace { -/// Sort blocks by their number. -struct CompareBlockNumbers { - bool operator()(const MachineBasicBlock *A, - const MachineBasicBlock *B) const { - return A->getNumber() > B->getNumber(); - } -}; -/// Sort blocks by their number in the opposite order.. -struct CompareBlockNumbersBackwards { - bool operator()(const MachineBasicBlock *A, - const MachineBasicBlock *B) const { - return A->getNumber() < B->getNumber(); - } -}; -/// Bookkeeping for a loop to help ensure that we don't mix blocks not dominated -/// by the loop header among the loop's blocks. -struct Entry { - const MachineLoop *Loop; - unsigned NumBlocksLeft; - - /// List of blocks not dominated by Loop's header that are deferred until - /// after all of Loop's blocks have been seen. - std::vector<MachineBasicBlock *> Deferred; - - explicit Entry(const MachineLoop *L) - : Loop(L), NumBlocksLeft(L->getNumBlocks()) {} -}; -} - -/// Sort the blocks, taking special care to make sure that loops are not -/// interrupted by blocks not dominated by their header. -/// TODO: There are many opportunities for improving the heuristics here. -/// Explore them. -static void SortBlocks(MachineFunction &MF, const MachineLoopInfo &MLI, - const MachineDominatorTree &MDT) { - // Prepare for a topological sort: Record the number of predecessors each - // block has, ignoring loop backedges. - MF.RenumberBlocks(); - SmallVector<unsigned, 16> NumPredsLeft(MF.getNumBlockIDs(), 0); - for (MachineBasicBlock &MBB : MF) { - unsigned N = MBB.pred_size(); - if (MachineLoop *L = MLI.getLoopFor(&MBB)) - if (L->getHeader() == &MBB) - for (const MachineBasicBlock *Pred : MBB.predecessors()) - if (L->contains(Pred)) - --N; - NumPredsLeft[MBB.getNumber()] = N; - } - - // Topological sort the CFG, with additional constraints: - // - Between a loop header and the last block in the loop, there can be - // no blocks not dominated by the loop header. - // - It's desirable to preserve the original block order when possible. - // We use two ready lists; Preferred and Ready. Preferred has recently - // processed sucessors, to help preserve block sequences from the original - // order. Ready has the remaining ready blocks. - PriorityQueue<MachineBasicBlock *, std::vector<MachineBasicBlock *>, - CompareBlockNumbers> - Preferred; - PriorityQueue<MachineBasicBlock *, std::vector<MachineBasicBlock *>, - CompareBlockNumbersBackwards> - Ready; - SmallVector<Entry, 4> Loops; - for (MachineBasicBlock *MBB = &MF.front();;) { - const MachineLoop *L = MLI.getLoopFor(MBB); - if (L) { - // If MBB is a loop header, add it to the active loop list. We can't put - // any blocks that it doesn't dominate until we see the end of the loop. - if (L->getHeader() == MBB) - Loops.push_back(Entry(L)); - // For each active loop the block is in, decrement the count. If MBB is - // the last block in an active loop, take it off the list and pick up any - // blocks deferred because the header didn't dominate them. - for (Entry &E : Loops) - if (E.Loop->contains(MBB) && --E.NumBlocksLeft == 0) - for (auto DeferredBlock : E.Deferred) - Ready.push(DeferredBlock); - while (!Loops.empty() && Loops.back().NumBlocksLeft == 0) - Loops.pop_back(); - } - // The main topological sort logic. - for (MachineBasicBlock *Succ : MBB->successors()) { - // Ignore backedges. - if (MachineLoop *SuccL = MLI.getLoopFor(Succ)) - if (SuccL->getHeader() == Succ && SuccL->contains(MBB)) - continue; - // Decrement the predecessor count. If it's now zero, it's ready. - if (--NumPredsLeft[Succ->getNumber()] == 0) - Preferred.push(Succ); - } - // Determine the block to follow MBB. First try to find a preferred block, - // to preserve the original block order when possible. - MachineBasicBlock *Next = nullptr; - while (!Preferred.empty()) { - Next = Preferred.top(); - Preferred.pop(); - // If X isn't dominated by the top active loop header, defer it until that - // loop is done. - if (!Loops.empty() && - !MDT.dominates(Loops.back().Loop->getHeader(), Next)) { - Loops.back().Deferred.push_back(Next); - Next = nullptr; - continue; - } - // If Next was originally ordered before MBB, and it isn't because it was - // loop-rotated above the header, it's not preferred. - if (Next->getNumber() < MBB->getNumber() && - (!L || !L->contains(Next) || - L->getHeader()->getNumber() < Next->getNumber())) { - Ready.push(Next); - Next = nullptr; - continue; - } - break; - } - // If we didn't find a suitable block in the Preferred list, check the - // general Ready list. - if (!Next) { - // If there are no more blocks to process, we're done. - if (Ready.empty()) { - MaybeUpdateTerminator(MBB); - break; - } - for (;;) { - Next = Ready.top(); - Ready.pop(); - // If Next isn't dominated by the top active loop header, defer it until - // that loop is done. - if (!Loops.empty() && - !MDT.dominates(Loops.back().Loop->getHeader(), Next)) { - Loops.back().Deferred.push_back(Next); - continue; - } - break; - } - } - // Move the next block into place and iterate. - Next->moveAfter(MBB); - MaybeUpdateTerminator(MBB); - MBB = Next; - } - assert(Loops.empty() && "Active loop list not finished"); - MF.RenumberBlocks(); - -#ifndef NDEBUG - SmallSetVector<MachineLoop *, 8> OnStack; - - // Insert a sentinel representing the degenerate loop that starts at the - // function entry block and includes the entire function as a "loop" that - // executes once. - OnStack.insert(nullptr); - - for (auto &MBB : MF) { - assert(MBB.getNumber() >= 0 && "Renumbered blocks should be non-negative."); - - MachineLoop *Loop = MLI.getLoopFor(&MBB); - if (Loop && &MBB == Loop->getHeader()) { - // Loop header. The loop predecessor should be sorted above, and the other - // predecessors should be backedges below. - for (auto Pred : MBB.predecessors()) - assert( - (Pred->getNumber() < MBB.getNumber() || Loop->contains(Pred)) && - "Loop header predecessors must be loop predecessors or backedges"); - assert(OnStack.insert(Loop) && "Loops should be declared at most once."); - } else { - // Not a loop header. All predecessors should be sorted above. - for (auto Pred : MBB.predecessors()) - assert(Pred->getNumber() < MBB.getNumber() && - "Non-loop-header predecessors should be topologically sorted"); - assert(OnStack.count(MLI.getLoopFor(&MBB)) && - "Blocks must be nested in their loops"); - } - while (OnStack.size() > 1 && &MBB == LoopBottom(OnStack.back())) - OnStack.pop_back(); - } - assert(OnStack.pop_back_val() == nullptr && - "The function entry block shouldn't actually be a loop header"); - assert(OnStack.empty() && - "Control flow stack pushes and pops should be balanced."); -#endif -} - /// Test whether Pred has any terminators explicitly branching to MBB, as /// opposed to falling through. Note that it's possible (eg. in unoptimized /// code) for a branch instruction to both branch to a block and fallthrough @@ -488,6 +270,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 +346,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) { @@ -569,9 +365,6 @@ bool WebAssemblyCFGStackify::runOnMachineFunction(MachineFunction &MF) { WebAssemblyFunctionInfo &MFI = *MF.getInfo<WebAssemblyFunctionInfo>(); MF.getRegInfo().invalidateLiveness(); - // Sort the blocks, with contiguous loops. - SortBlocks(MF, MLI, MDT); - // Place the BLOCK and LOOP markers to indicate the beginnings of scopes. PlaceMarkers(MF, MLI, TII, MDT, MFI); diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp index fc0a01c..b2330a2 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp @@ -22,8 +22,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "llvm/Analysis/AliasAnalysis.h" @@ -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/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp index 04ede7f..4124911 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp @@ -31,6 +31,14 @@ using namespace llvm; #define DEBUG_TYPE "wasm-explicit-locals" +// A command-line option to disable this pass. Note that this produces output +// which is not valid WebAssembly, though it may be more convenient for writing +// LLVM unit tests with. +static cl::opt<bool> DisableWebAssemblyExplicitLocals( + "disable-wasm-explicit-locals", cl::ReallyHidden, + cl::desc("WebAssembly: Disable emission of get_local/set_local."), + cl::init(false)); + namespace { class WebAssemblyExplicitLocals final : public MachineFunctionPass { StringRef getPassName() const override { @@ -60,7 +68,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. @@ -146,6 +172,10 @@ bool WebAssemblyExplicitLocals::runOnMachineFunction(MachineFunction &MF) { "********** Function: " << MF.getName() << '\n'); + // Disable this pass if directed to do so. + if (DisableWebAssemblyExplicitLocals) + return false; + // Disable this pass if we aren't doing direct wasm object emission. if (MF.getSubtarget<WebAssemblySubtarget>() .getTargetTriple().isOSBinFormatELF()) @@ -176,6 +206,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 +260,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 +325,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/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp index bc7020f..c980f4b 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFastISel.cpp @@ -16,8 +16,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyTargetMachine.h" @@ -63,12 +63,16 @@ class WebAssemblyFastISel final : public FastISel { public: // Innocuous defaults for our address. Address() : Kind(RegBase), Offset(0), GV(0) { Base.Reg = 0; } - void setKind(BaseKind K) { Kind = K; } + void setKind(BaseKind K) { + assert(!isSet() && "Can't change kind with non-zero base"); + Kind = K; + } BaseKind getKind() const { return Kind; } bool isRegBase() const { return Kind == RegBase; } bool isFIBase() const { return Kind == FrameIndexBase; } void setReg(unsigned Reg) { assert(isRegBase() && "Invalid base register access!"); + assert(Base.Reg == 0 && "Overwriting non-zero register"); Base.Reg = Reg; } unsigned getReg() const { @@ -77,6 +81,7 @@ class WebAssemblyFastISel final : public FastISel { } void setFI(unsigned FI) { assert(isFIBase() && "Invalid base frame index access!"); + assert(Base.FI == 0 && "Overwriting non-zero frame index"); Base.FI = FI; } unsigned getFI() const { @@ -91,6 +96,13 @@ class WebAssemblyFastISel final : public FastISel { int64_t getOffset() const { return Offset; } void setGlobalValue(const GlobalValue *G) { GV = G; } const GlobalValue *getGlobalValue() const { return GV; } + bool isSet() const { + if (isRegBase()) { + return Base.Reg != 0; + } else { + return Base.FI != 0; + } + } }; /// Keep a pointer to the WebAssemblySubtarget around so that we can make the @@ -116,6 +128,8 @@ private: case MVT::f32: case MVT::f64: return VT; + case MVT::f16: + return MVT::f32; case MVT::v16i8: case MVT::v8i16: case MVT::v4i32: @@ -295,6 +309,9 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) { DenseMap<const AllocaInst *, int>::iterator SI = FuncInfo.StaticAllocaMap.find(AI); if (SI != FuncInfo.StaticAllocaMap.end()) { + if (Addr.isSet()) { + return false; + } Addr.setKind(Address::FrameIndexBase); Addr.setFI(SI->second); return true; @@ -339,6 +356,9 @@ bool WebAssemblyFastISel::computeAddress(const Value *Obj, Address &Addr) { break; } } + if (Addr.isSet()) { + return false; + } Addr.setReg(getRegForValue(Obj)); return Addr.getReg() != 0; } @@ -594,12 +614,12 @@ bool WebAssemblyFastISel::fastLowerArguments() { unsigned i = 0; for (auto const &Arg : F->args()) { - const AttributeSet &Attrs = F->getAttributes(); - if (Attrs.hasAttribute(i+1, Attribute::ByVal) || - Attrs.hasAttribute(i+1, Attribute::SwiftSelf) || - Attrs.hasAttribute(i+1, Attribute::SwiftError) || - Attrs.hasAttribute(i+1, Attribute::InAlloca) || - Attrs.hasAttribute(i+1, Attribute::Nest)) + const AttributeList &Attrs = F->getAttributes(); + if (Attrs.hasParamAttribute(i, Attribute::ByVal) || + Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || + Attrs.hasParamAttribute(i, Attribute::SwiftError) || + Attrs.hasParamAttribute(i, Attribute::InAlloca) || + Attrs.hasParamAttribute(i, Attribute::Nest)) return false; Type *ArgTy = Arg.getType(); @@ -744,19 +764,19 @@ bool WebAssemblyFastISel::selectCall(const Instruction *I) { if (ArgTy == MVT::INVALID_SIMPLE_VALUE_TYPE) return false; - const AttributeSet &Attrs = Call->getAttributes(); - if (Attrs.hasAttribute(i+1, Attribute::ByVal) || - Attrs.hasAttribute(i+1, Attribute::SwiftSelf) || - Attrs.hasAttribute(i+1, Attribute::SwiftError) || - Attrs.hasAttribute(i+1, Attribute::InAlloca) || - Attrs.hasAttribute(i+1, Attribute::Nest)) + const AttributeList &Attrs = Call->getAttributes(); + if (Attrs.hasParamAttribute(i, Attribute::ByVal) || + Attrs.hasParamAttribute(i, Attribute::SwiftSelf) || + Attrs.hasParamAttribute(i, Attribute::SwiftError) || + Attrs.hasParamAttribute(i, Attribute::InAlloca) || + Attrs.hasParamAttribute(i, Attribute::Nest)) return false; unsigned Reg; - if (Attrs.hasAttribute(i+1, Attribute::SExt)) + if (Attrs.hasParamAttribute(i, Attribute::SExt)) Reg = getRegForSignedValue(V); - else if (Attrs.hasAttribute(i+1, Attribute::ZExt)) + else if (Attrs.hasParamAttribute(i, Attribute::ZExt)) Reg = getRegForUnsignedValue(V); else Reg = getRegForValue(V); diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp index adf904e..76a2ff3 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixFunctionBitcasts.cpp @@ -84,7 +84,7 @@ static void FindUses(Value *V, Function &F, // - Call with fewer arguments than needed: arguments are filled in with undef // - Return value is not needed: drop it // - Return value needed but not present: supply an undef -// +// // For now, return nullptr without creating a wrapper if the wrapper cannot // be generated due to incompatible types. static Function *CreateWrapper(Function *F, FunctionType *Ty) { @@ -148,6 +148,11 @@ bool FixFunctionBitcasts::runOnModule(Module &M) { if (!Ty) continue; + // Wasm varargs are not ABI-compatible with non-varargs. Just ignore + // such casts for now. + if (Ty->isVarArg() || F->isVarArg()) + continue; + auto Pair = Wrappers.insert(std::make_pair(std::make_pair(F, Ty), nullptr)); if (Pair.second) Pair.first->second = CreateWrapper(F, Ty); diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp index 2bbf7a2..41f315c 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFixIrreducibleControlFlow.cpp @@ -26,8 +26,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "llvm/ADT/PriorityQueue.h" diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp index a6a2c0b..a37d613 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp @@ -24,10 +24,11 @@ #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" -#include "llvm/CodeGen/MachineModuleInfo.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/Support/Debug.h" using namespace llvm; @@ -101,25 +102,33 @@ static void writeSPToMemory(unsigned SrcReg, MachineFunction &MF, MachineBasicBlock::iterator &InsertAddr, MachineBasicBlock::iterator &InsertStore, const DebugLoc &DL) { + const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); + const char *ES = "__stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); - MachineRegisterInfo &MRI = MF.getRegInfo(); - const TargetRegisterClass *PtrRC = - MRI.getTargetRegisterInfo()->getPointerRegClass(MF); - unsigned Zero = MRI.createVirtualRegister(PtrRC); - const auto *TII = MF.getSubtarget<WebAssemblySubtarget>().getInstrInfo(); + if (MF.getSubtarget<WebAssemblySubtarget>() + .getTargetTriple().isOSBinFormatELF()) { + MachineRegisterInfo &MRI = MF.getRegInfo(); + const TargetRegisterClass *PtrRC = + MRI.getTargetRegisterInfo()->getPointerRegClass(MF); + unsigned Zero = MRI.createVirtualRegister(PtrRC); - BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), Zero) - .addImm(0); - MachineMemOperand *MMO = MF.getMachineMemOperand( - MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)), - MachineMemOperand::MOStore, 4, 4); - BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32)) - .addImm(2) // p2align - .addExternalSymbol(SPSymbol) - .addReg(Zero) - .addReg(SrcReg) - .addMemOperand(MMO); + BuildMI(MBB, InsertAddr, DL, TII->get(WebAssembly::CONST_I32), Zero) + .addImm(0); + MachineMemOperand *MMO = MF.getMachineMemOperand( + MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)), + MachineMemOperand::MOStore, 4, 4); + BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::STORE_I32)) + .addImm(2) // p2align + .addExternalSymbol(SPSymbol) + .addReg(Zero) + .addReg(SrcReg) + .addMemOperand(MMO); + } else { + BuildMI(MBB, InsertStore, DL, TII->get(WebAssembly::SET_GLOBAL_I32)) + .addExternalSymbol(SPSymbol) + .addReg(SrcReg); + } } MachineBasicBlock::iterator @@ -151,27 +160,37 @@ 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 = MRI.getTargetRegisterInfo()->getPointerRegClass(MF); - unsigned Zero = MRI.createVirtualRegister(PtrRC); unsigned SPReg = WebAssembly::SP32; if (StackSize) SPReg = MRI.createVirtualRegister(PtrRC); + const char *ES = "__stack_pointer"; auto *SPSymbol = MF.createExternalSymbolName(ES); - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero) - .addImm(0); - MachineMemOperand *LoadMMO = MF.getMachineMemOperand( - MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)), - MachineMemOperand::MOLoad, 4, 4); - // Load the SP value. - BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg) - .addImm(2) // p2align - .addExternalSymbol(SPSymbol) - .addReg(Zero) // addr - .addMemOperand(LoadMMO); + if (MF.getSubtarget<WebAssemblySubtarget>() + .getTargetTriple().isOSBinFormatELF()) { + unsigned Zero = MRI.createVirtualRegister(PtrRC); + + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::CONST_I32), Zero) + .addImm(0); + MachineMemOperand *LoadMMO = MF.getMachineMemOperand( + MachinePointerInfo(MF.getPSVManager().getExternalSymbolCallEntry(ES)), + MachineMemOperand::MOLoad, 4, 4); + // Load the SP value. + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::LOAD_I32), SPReg) + .addImm(2) // p2align + .addExternalSymbol(SPSymbol) + .addReg(Zero) // addr + .addMemOperand(LoadMMO); + } else { + BuildMI(MBB, InsertPt, DL, TII->get(WebAssembly::GET_GLOBAL_I32), SPReg) + .addExternalSymbol(SPSymbol); + } bool HasBP = hasBP(MF); if (HasBP) { diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp index a67137f..4f3ae57 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelDAGToDAG.cpp @@ -12,12 +12,13 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyTargetMachine.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/IR/Function.h" // To access function attributes. #include "llvm/Support/Debug.h" +#include "llvm/Support/KnownBits.h" #include "llvm/Support/MathExtras.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp index 6a7f75a..8143770 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.cpp @@ -84,8 +84,8 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( ISD::SETULT, ISD::SETULE, ISD::SETUGT, ISD::SETUGE}) setCondCodeAction(CC, T, Expand); // Expand floating-point library function operators. - for (auto Op : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOWI, ISD::FPOW, - ISD::FREM, ISD::FMA}) + for (auto Op : {ISD::FSIN, ISD::FCOS, ISD::FSINCOS, ISD::FPOW, ISD::FREM, + ISD::FMA}) setOperationAction(Op, T, Expand); // Note supported floating-point library function operators that otherwise // default to expand. @@ -95,6 +95,11 @@ WebAssemblyTargetLowering::WebAssemblyTargetLowering( // Support minnan and maxnan, which otherwise default to expand. setOperationAction(ISD::FMINNAN, T, Legal); setOperationAction(ISD::FMAXNAN, T, Legal); + // WebAssembly currently has no builtin f16 support. + setOperationAction(ISD::FP16_TO_FP, T, Expand); + setOperationAction(ISD::FP_TO_FP16, T, Expand); + setLoadExtAction(ISD::EXTLOAD, T, MVT::f16, Expand); + setTruncStoreAction(T, MVT::f16, Expand); } for (auto T : {MVT::i32, MVT::i64}) { @@ -253,7 +258,8 @@ bool WebAssemblyTargetLowering::allowsMisalignedMemoryAccesses( return true; } -bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT, AttributeSet Attr) const { +bool WebAssemblyTargetLowering::isIntDivCheap(EVT VT, + AttributeList Attr) const { // The current thinking is that wasm engines will perform this optimization, // so we can save on code size. return true; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h index 5bc7230..99d3d0d 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyISelLowering.h @@ -58,7 +58,7 @@ class WebAssemblyTargetLowering final : public TargetLowering { unsigned AS) const override; bool allowsMisalignedMemoryAccesses(EVT, unsigned AddrSpace, unsigned Align, bool *Fast) const override; - bool isIntDivCheap(EVT VT, AttributeSet Attr) const override; + bool isIntDivCheap(EVT VT, AttributeList Attr) const override; SDValue LowerCall(CallLoweringInfo &CLI, SmallVectorImpl<SDValue> &InVals) const override; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td index 047f4be..6b45839 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrCall.td @@ -19,8 +19,8 @@ let Defs = [ARGUMENTS] in { // Call sequence markers. These have an immediate which represents the amount of // stack space to allocate or free, which is used for varargs lowering. let Uses = [SP32, SP64], Defs = [SP32, SP64], isCodeGenOnly = 1 in { -def ADJCALLSTACKDOWN : I<(outs), (ins i32imm:$amt), - [(WebAssemblycallseq_start timm:$amt)]>; +def ADJCALLSTACKDOWN : I<(outs), (ins i32imm:$amt, i32imm:$amt2), + [(WebAssemblycallseq_start timm:$amt, timm:$amt2)]>; def ADJCALLSTACKUP : I<(outs), (ins i32imm:$amt, i32imm:$amt2), [(WebAssemblycallseq_end timm:$amt, timm:$amt2)]>; } // isCodeGenOnly = 1 @@ -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/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td index 1146431..1297941 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrControl.td @@ -57,16 +57,21 @@ def BR_TABLE_I64 : I<(outs), (ins I64:$index, variable_ops), } } // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 -// Placemarkers to indicate the start or end of a block or loop scope. These -// use/clobber VALUE_STACK to prevent them from being moved into the middle of -// an expression tree. +// Placemarkers to indicate the start or end of a block, loop, or try scope. +// These use/clobber VALUE_STACK to prevent them from being moved into the +// middle of an expression tree. 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>; +def TRY : I<(outs), (ins Signature:$sig), [], "try \t$sig", 0x06>; -// END_BLOCK and END_LOOP are represented with the same opcode in wasm. +// END_BLOCK, END_LOOP, END_TRY, 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>; +def END_TRY : I<(outs), (ins), [], "end_try", 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> { @@ -109,6 +114,20 @@ let isReturn = 1 in { def UNREACHABLE : I<(outs), (ins), [(trap)], "unreachable", 0x00>; +def THROW_I32 : I<(outs), (ins i32imm:$tag, I32:$obj), + [(int_wasm_throw imm:$tag, I32:$obj)], "throw \t$tag, $obj", + 0x08>; +def THROW_I64 : I<(outs), (ins i32imm:$tag, I64:$obj), + [(int_wasm_throw imm:$tag, I64:$obj)], "throw \t$tag, $obj", + 0x08>; +def RETHROW : I<(outs), (ins i32imm:$rel_depth), [], "rethrow \t$rel_depth", + 0x09>; + } // isTerminator = 1, hasCtrlDep = 1, isBarrier = 1 } // Defs = [ARGUMENTS] + +// rethrow takes a relative depth as an argument, for which currently only 0 is +// possible for C++. Once other languages need depths other than 0, depths will +// be computed in CFGStackify. +def : Pat<(int_wasm_rethrow), (RETHROW 0)>; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td index 030be08..03c9c1f 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrFloat.td @@ -55,8 +55,8 @@ defm EQ : ComparisonFP<SETOEQ, "eq ", 0x5b, 0x61>; defm NE : ComparisonFP<SETUNE, "ne ", 0x5c, 0x62>; } // isCommutable = 1 defm LT : ComparisonFP<SETOLT, "lt ", 0x5d, 0x63>; -defm LE : ComparisonFP<SETOLE, "le ", 0x5e, 0x64>; -defm GT : ComparisonFP<SETOGT, "gt ", 0x5f, 0x65>; +defm LE : ComparisonFP<SETOLE, "le ", 0x5f, 0x65>; +defm GT : ComparisonFP<SETOGT, "gt ", 0x5e, 0x64>; defm GE : ComparisonFP<SETOGE, "ge ", 0x60, 0x66>; } // Defs = [ARGUMENTS] diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp index 0e2d8bb..8846952 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.cpp @@ -183,11 +183,9 @@ unsigned WebAssemblyInstrInfo::insertBranch(MachineBasicBlock &MBB, assert(Cond.size() == 2 && "Expected a flag and a successor block"); if (Cond[0].getImm()) { - BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).addOperand(Cond[1]); + BuildMI(&MBB, DL, get(WebAssembly::BR_IF)).addMBB(TBB).add(Cond[1]); } else { - BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)) - .addMBB(TBB) - .addOperand(Cond[1]); + BuildMI(&MBB, DL, get(WebAssembly::BR_UNLESS)).addMBB(TBB).add(Cond[1]); } if (!FBB) return 1; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td index dcfd1a4..fa2146f 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrInfo.td @@ -25,7 +25,8 @@ def HasSIMD128 : Predicate<"Subtarget->hasSIMD128()">, // WebAssembly-specific DAG Node Types. //===----------------------------------------------------------------------===// -def SDT_WebAssemblyCallSeqStart : SDCallSeqStart<[SDTCisVT<0, iPTR>]>; +def SDT_WebAssemblyCallSeqStart : SDCallSeqStart<[SDTCisVT<0, iPTR>, + SDTCisVT<1, iPTR>]>; def SDT_WebAssemblyCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, iPTR>, SDTCisVT<1, iPTR>]>; def SDT_WebAssemblyCall0 : SDTypeProfile<0, -1, [SDTCisPtrTy<0>]>; @@ -74,6 +75,9 @@ def bb_op : Operand<OtherVT>; let OperandType = "OPERAND_LOCAL" in def local_op : Operand<i32>; +let OperandType = "OPERAND_GLOBAL" in +def global_op : Operand<i32>; + let OperandType = "OPERAND_I32IMM" in def i32imm_op : Operand<i32>; @@ -104,6 +108,9 @@ def Signature : Operand<i32> { } } // OperandType = "OPERAND_SIGNATURE" +let OperandType = "OPERAND_TYPEINDEX" in +def TypeIndex : Operand<i32>; + } // OperandNamespace = "WebAssembly" //===----------------------------------------------------------------------===// @@ -178,6 +185,18 @@ let hasSideEffects = 0 in { def TEE_LOCAL_#vt : I<(outs vt:$res), (ins local_op:$local, vt:$src), [], "tee_local\t$res, $local, $src", 0x22>; + // Unused values must be dropped in some contexts. + def DROP_#vt : I<(outs), (ins vt:$src), [], + "drop\t$src", 0x1a>; + + let mayLoad = 1 in + def GET_GLOBAL_#vt : I<(outs vt:$res), (ins global_op:$local), [], + "get_global\t$res, $local", 0x23>; + + let mayStore = 1 in + def SET_GLOBAL_#vt : I<(outs), (ins global_op:$local, vt:$src), [], + "set_global\t$local, $src", 0x24>; + } // hasSideEffects = 0 } defm : LOCAL<I32>; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td index b606ebb..365b327 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyInstrMemory.td @@ -26,18 +26,18 @@ // offset for an add that needs wrapping. def regPlusImm : PatFrag<(ops node:$addr, node:$off), (add node:$addr, node:$off), - [{ return N->getFlags()->hasNoUnsignedWrap(); }]>; + [{ return N->getFlags().hasNoUnsignedWrap(); }]>; // Treat an 'or' node as an 'add' if the or'ed bits are known to be zero. def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(N->getOperand(1))) return CurDAG->MaskedValueIsZero(N->getOperand(0), CN->getAPIntValue()); - APInt KnownZero0, KnownOne0; - CurDAG->computeKnownBits(N->getOperand(0), KnownZero0, KnownOne0, 0); - APInt KnownZero1, KnownOne1; - CurDAG->computeKnownBits(N->getOperand(1), KnownZero1, KnownOne1, 0); - return (~KnownZero0 & ~KnownZero1) == 0; + KnownBits Known0; + CurDAG->computeKnownBits(N->getOperand(0), Known0, 0); + KnownBits Known1; + CurDAG->computeKnownBits(N->getOperand(1), Known1, 0); + return (~Known0.Zero & ~Known1.Zero) == 0; }]>; // GlobalAddresses are conceptually unsigned values, so we can also fold them @@ -47,7 +47,7 @@ def or_is_add : PatFrag<(ops node:$lhs, node:$rhs), (or node:$lhs, node:$rhs),[{ def regPlusGA : PatFrag<(ops node:$addr, node:$off), (add node:$addr, node:$off), [{ - return N->getFlags()->hasNoUnsignedWrap(); + return N->getFlags().hasNoUnsignedWrap(); }]>; // We don't need a regPlusES because external symbols never have constant @@ -673,9 +673,9 @@ def CURRENT_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags), Requires<[HasAddr32]>; // Grow memory. -def GROW_MEMORY_I32 : I<(outs), (ins i32imm:$flags, I32:$delta), +def GROW_MEMORY_I32 : I<(outs I32:$dst), (ins i32imm:$flags, I32:$delta), [], - "grow_memory\t$delta", 0x40>, + "grow_memory\t$dst, $delta", 0x40>, Requires<[HasAddr32]>; } // Defs = [ARGUMENTS] diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp index 7ea5d05..576b71d 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerBrUnless.cpp @@ -15,8 +15,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -118,7 +118,7 @@ bool WebAssemblyLowerBrUnless::runOnMachineFunction(MachineFunction &MF) { // delete the br_unless. assert(Inverted); BuildMI(MBB, MI, MI->getDebugLoc(), TII.get(WebAssembly::BR_IF)) - .addOperand(MI->getOperand(0)) + .add(MI->getOperand(0)) .addReg(Cond); MBB.erase(MI); } diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp index 72cb1cc..f0b6a3e 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyLowerEmscriptenEHSjLj.cpp @@ -412,7 +412,7 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) { if (CI->doesNotReturn()) { if (auto *F = dyn_cast<Function>(CI->getCalledValue())) F->removeFnAttr(Attribute::NoReturn); - CI->removeAttribute(AttributeSet::FunctionIndex, Attribute::NoReturn); + CI->removeAttribute(AttributeList::FunctionIndex, Attribute::NoReturn); } IRBuilder<> IRB(C); @@ -435,25 +435,20 @@ Value *WebAssemblyLowerEmscriptenEHSjLj::wrapInvoke(CallOrInvoke *CI) { // Because we added the pointer to the callee as first argument, all // argument attribute indices have to be incremented by one. - SmallVector<AttributeSet, 8> AttributesVec; - const AttributeSet &InvokePAL = CI->getAttributes(); - CallSite::arg_iterator AI = CI->arg_begin(); - unsigned i = 1; // Argument attribute index starts from 1 - for (unsigned e = CI->getNumArgOperands(); i <= e; ++AI, ++i) { - if (InvokePAL.hasAttributes(i)) { - AttrBuilder B(InvokePAL, i); - AttributesVec.push_back(AttributeSet::get(C, i + 1, B)); - } - } - // Add any return attributes. - if (InvokePAL.hasAttributes(AttributeSet::ReturnIndex)) - AttributesVec.push_back(AttributeSet::get(C, InvokePAL.getRetAttributes())); - // Add any function attributes. - if (InvokePAL.hasAttributes(AttributeSet::FunctionIndex)) - AttributesVec.push_back(AttributeSet::get(C, InvokePAL.getFnAttributes())); + SmallVector<AttributeSet, 8> ArgAttributes; + const AttributeList &InvokeAL = CI->getAttributes(); + + // No attributes for the callee pointer. + ArgAttributes.push_back(AttributeSet()); + // Copy the argument attributes from the original + for (unsigned i = 0, e = CI->getNumArgOperands(); i < e; ++i) + ArgAttributes.push_back(InvokeAL.getParamAttributes(i)); + // Reconstruct the AttributesList based on the vector we constructed. - AttributeSet NewCallPAL = AttributeSet::get(C, AttributesVec); - NewCall->setAttributes(NewCallPAL); + AttributeList NewCallAL = + AttributeList::get(C, InvokeAL.getFnAttributes(), + InvokeAL.getRetAttributes(), ArgAttributes); + NewCall->setAttributes(NewCallAL); CI->replaceAllUsesWith(NewCall); @@ -624,7 +619,7 @@ void WebAssemblyLowerEmscriptenEHSjLj::createSetThrewFunction(Module &M) { Function *F = Function::Create(FTy, GlobalValue::ExternalLinkage, SetThrewFName, &M); Argument *Arg1 = &*(F->arg_begin()); - Argument *Arg2 = &*(++F->arg_begin()); + Argument *Arg2 = &*std::next(F->arg_begin()); Arg1->setName("threw"); Arg2->setName("value"); BasicBlock *EntryBB = BasicBlock::Create(C, "entry", F); @@ -902,7 +897,7 @@ bool WebAssemblyLowerEmscriptenEHSjLj::runEHOnFunction(Function &F) { } } - // Look for orphan landingpads, can occur in blocks with no predecesors + // Look for orphan landingpads, can occur in blocks with no predecessors for (BasicBlock &BB : F) { Instruction *I = BB.getFirstNonPHI(); if (auto *LPI = dyn_cast<LandingPadInst>(I)) diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp index 022a448..8880539 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp +++ b/contrib/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<wasm::ValType, 4> Returns; + SmallVector<wasm::ValType, 4> Params; + + wasm::ValType iPTR = + MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() ? + wasm::ValType::I64 : + wasm::ValType::I32; + + SmallVector<MVT, 4> ResultMVTs; + ComputeLegalValueVTs(CurrentFunc, TM, FuncTy->getReturnType(), ResultMVTs); + // WebAssembly can't currently handle returning tuples. + if (ResultMVTs.size() <= 1) + for (MVT ResultMVT : ResultMVTs) + Returns.push_back(WebAssembly::toValType(ResultMVT)); + else + Params.push_back(iPTR); + + for (Type *Ty : FuncTy->params()) { + SmallVector<MVT, 4> ParamMVTs; + ComputeLegalValueVTs(CurrentFunc, TM, Ty, ParamMVTs); + for (MVT ParamMVT : ParamMVTs) + Params.push_back(WebAssembly::toValType(ParamMVT)); + } + + if (FuncTy->isVarArg()) + Params.push_back(iPTR); + + 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<wasm::ValType, 4> Returns; + SmallVector<wasm::ValType, 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,7 @@ MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym, MCSymbolRefExpr::VariantKind VK = IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION : MCSymbolRefExpr::VK_None; + const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx); if (Offset != 0) { @@ -54,20 +125,34 @@ MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym, return MCOperand::createExpr(Expr); } +// Return the WebAssembly type associated with the given register class. +static wasm::ValType getType(const TargetRegisterClass *RC) { + if (RC == &WebAssembly::I32RegClass) + return wasm::ValType::I32; + if (RC == &WebAssembly::I64RegClass) + return wasm::ValType::I64; + if (RC == &WebAssembly::F32RegClass) + return wasm::ValType::F32; + if (RC == &WebAssembly::F64RegClass) + return wasm::ValType::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); MCOperand MCOp; switch (MO.getType()) { default: - MI->dump(); + MI->print(errs()); llvm_unreachable("unknown operand type"); case MachineOperand::MO_MachineBasicBlock: - MI->dump(); + MI->print(errs()); llvm_unreachable("MachineBasicBlock operand should have been rewritten"); case MachineOperand::MO_Register: { // Ignore all implicit register operands. @@ -80,6 +165,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<wasm::ValType, 4> Returns; + SmallVector<wasm::ValType, 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/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.h index ab4ba1c..d1d2794 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMCInstLower.h +++ b/contrib/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/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h index 756619b..1fcbb77 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h +++ b/contrib/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/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp index 96520aa..559165e 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyOptimizeReturned.cpp @@ -54,7 +54,7 @@ FunctionPass *llvm::createWebAssemblyOptimizeReturned() { void OptimizeReturned::visitCallSite(CallSite CS) { for (unsigned i = 0, e = CS.getNumArgOperands(); i < e; ++i) - if (CS.paramHasAttr(1 + i, Attribute::Returned)) { + if (CS.paramHasAttr(i, Attribute::Returned)) { Instruction *Inst = CS.getInstruction(); Value *Arg = CS.getArgOperand(i); // Ignore constants, globals, undef, etc. diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp index 32dde88..d2fbc5a 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPeephole.cpp @@ -80,19 +80,31 @@ 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 the operand isn't stackified, insert a COPY to read the operand and - // stackify it. - MachineOperand &MO = MI.getOperand(0); - unsigned Reg = MO.getReg(); - if (!MFI.isVRegStackified(Reg)) { - unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); - BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg) - .addReg(Reg); - MO.setReg(NewReg); - MFI.stackifyVReg(NewReg); + if (FallthroughOpc != WebAssembly::FALLTHROUGH_RETURN_VOID) { + // If the operand isn't stackified, insert a COPY to read the operand and + // stackify it. + MachineOperand &MO = MI.getOperand(0); + unsigned Reg = MO.getReg(); + if (!MFI.isVRegStackified(Reg)) { + unsigned NewReg = MRI.createVirtualRegister(MRI.getRegClass(Reg)); + BuildMI(MBB, MI, MI.getDebugLoc(), TII.get(CopyLocalOpc), NewReg) + .addReg(Reg); + MO.setReg(NewReg); + MFI.stackifyVReg(NewReg); + } } // Rewrite the return. @@ -127,7 +139,7 @@ bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) { if (Name == TLI.getLibcallName(RTLIB::MEMCPY) || Name == TLI.getLibcallName(RTLIB::MEMMOVE) || Name == TLI.getLibcallName(RTLIB::MEMSET)) { - LibFunc::Func Func; + LibFunc Func; if (LibInfo.getLibFunc(Name, Func)) { const auto &Op2 = MI.getOperand(2); if (!Op2.isReg()) @@ -188,9 +200,9 @@ bool WebAssemblyPeephole::runOnMachineFunction(MachineFunction &MF) { WebAssembly::COPY_V128); break; case WebAssembly::RETURN_VOID: - if (!DisableWebAssemblyFallthroughReturnOpt && - &MBB == &MF.back() && &MI == &MBB.back()) - MI.setDesc(TII.get(WebAssembly::FALLTHROUGH_RETURN_VOID)); + Changed |= MaybeRewriteToFallthrough( + MI, MBB, MF, MFI, MRI, TII, WebAssembly::FALLTHROUGH_RETURN_VOID, + WebAssembly::INSTRUCTION_LIST_END); break; } diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp index 473dcb7..1462c49 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyPrepareForLiveIntervals.cpp @@ -19,8 +19,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyUtilities.h" diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp index 5fd4a8d..ba39b6c 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegColoring.cpp @@ -140,8 +140,7 @@ bool WebAssemblyRegColoring::runOnMachineFunction(MachineFunction &MF) { // Check if it's possible to reuse any of the used colors. if (!MRI->isLiveIn(Old)) - for (int C(UsedColors.find_first()); C != -1; - C = UsedColors.find_next(C)) { + for (unsigned C : UsedColors.set_bits()) { if (MRI->getRegClass(SortedIntervals[C]->reg) != RC) continue; for (LiveInterval *OtherLI : Assignments[C]) diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp index e347082..766ab45 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegNumbering.cpp @@ -13,8 +13,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyUtilities.h" diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp index 32ee09e..ea9e3fa 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRegStackify.cpp @@ -20,8 +20,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" // for WebAssembly::ARGUMENT_* +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "WebAssemblyUtilities.h" @@ -30,6 +30,7 @@ #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineDominators.h" #include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineModuleInfoImpls.h" #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/Passes.h" #include "llvm/Support/Debug.h" @@ -152,7 +153,7 @@ static void QueryCallee(const MachineInstr &MI, unsigned CalleeOpNo, bool &Read, } // Determine whether MI reads memory, writes memory, has side effects, -// and/or uses the __stack_pointer value. +// and/or uses the stack pointer value. static void Query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read, bool &Write, bool &Effects, bool &StackPointer) { assert(!MI.isPosition()); @@ -176,8 +177,9 @@ static void Query(const MachineInstr &MI, AliasAnalysis &AA, bool &Read, auto PSV = MPI.V.get<const PseudoSourceValue *>(); if (const ExternalSymbolPseudoSourceValue *EPSV = dyn_cast<ExternalSymbolPseudoSourceValue>(PSV)) - if (StringRef(EPSV->getSymbol()) == "__stack_pointer") + if (StringRef(EPSV->getSymbol()) == "__stack_pointer") { StackPointer = true; + } } } } else if (MI.hasOrderedMemoryRef()) { diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp index 9e944df..878ffd0 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyReplacePhysRegs.cpp @@ -19,8 +19,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "llvm/CodeGen/MachineFunctionPass.h" diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp new file mode 100644 index 0000000..2599064 --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.cpp @@ -0,0 +1,1323 @@ +// CodeGen/RuntimeLibcallSignatures.cpp - R.T. Lib. Call Signatures -*- 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 signature information for runtime libcalls. +/// +/// CodeGen uses external symbols, which it refers to by name. The WebAssembly +/// target needs type information for all functions. This file contains a big +/// table providing type signatures for all runtime library functions that LLVM +/// uses. +/// +/// This is currently a fairly heavy-handed solution. +/// +//===----------------------------------------------------------------------===// + +#include "WebAssemblyRuntimeLibcallSignatures.h" +#include "WebAssemblySubtarget.h" +#include "llvm/CodeGen/RuntimeLibcalls.h" + +using namespace llvm; + +namespace { + +enum RuntimeLibcallSignature { + func, + f32_func_f32, + f32_func_f64, + f32_func_i32, + f32_func_i64, + f32_func_i16, + f64_func_f32, + f64_func_f64, + f64_func_i32, + f64_func_i64, + i32_func_f32, + i32_func_f64, + i32_func_i32, + i64_func_f32, + i64_func_f64, + i64_func_i64, + f32_func_f32_f32, + f32_func_f32_i32, + f32_func_i64_i64, + f64_func_f64_f64, + f64_func_f64_i32, + f64_func_i64_i64, + i16_func_f32, + i8_func_i8_i8, + func_f32_iPTR_iPTR, + func_f64_iPTR_iPTR, + i16_func_i16_i16, + i32_func_f32_f32, + i32_func_f64_f64, + i32_func_i32_i32, + i64_func_i64_i64, + i64_i64_func_f32, + i64_i64_func_f64, + i16_i16_func_i16_i16, + i32_i32_func_i32_i32, + i64_i64_func_i64_i64, + i64_i64_func_i64_i64_i64_i64, + i64_i64_i64_i64_func_i64_i64_i64_i64, + i64_i64_func_i64_i64_i32, + iPTR_func_iPTR_i32_iPTR, + iPTR_func_iPTR_iPTR_iPTR, + f32_func_f32_f32_f32, + f64_func_f64_f64_f64, + func_i64_i64_iPTR_iPTR, + func_iPTR_f32, + func_iPTR_f64, + func_iPTR_i32, + func_iPTR_i64, + func_iPTR_i64_i64, + func_iPTR_i64_i64_i64_i64, + func_iPTR_i64_i64_i64_i64_i64_i64, + i32_func_i64_i64, + i32_func_i64_i64_i64_i64, + unsupported +}; + +} // end anonymous namespace + +static const RuntimeLibcallSignature +RuntimeLibcallSignatures[RTLIB::UNKNOWN_LIBCALL] = { +// Integer +/* SHL_I16 */ i16_func_i16_i16, +/* SHL_I32 */ i32_func_i32_i32, +/* SHL_I64 */ i64_func_i64_i64, +/* SHL_I128 */ i64_i64_func_i64_i64_i32, +/* SRL_I16 */ i16_func_i16_i16, +/* SRL_I32 */ i32_func_i32_i32, +/* SRL_I64 */ i64_func_i64_i64, +/* SRL_I128 */ i64_i64_func_i64_i64_i32, +/* SRA_I16 */ i16_func_i16_i16, +/* SRA_I32 */ i32_func_i32_i32, +/* SRA_I64 */ i64_func_i64_i64, +/* SRA_I128 */ i64_i64_func_i64_i64_i32, +/* MUL_I8 */ i8_func_i8_i8, +/* MUL_I16 */ i16_func_i16_i16, +/* MUL_I32 */ i32_func_i32_i32, +/* MUL_I64 */ i64_func_i64_i64, +/* MUL_I128 */ i64_i64_func_i64_i64_i64_i64, +/* MULO_I32 */ i32_func_i32_i32, +/* MULO_I64 */ i64_func_i64_i64, +/* MULO_I128 */ i64_i64_func_i64_i64_i64_i64, +/* SDIV_I8 */ i8_func_i8_i8, +/* SDIV_I16 */ i16_func_i16_i16, +/* SDIV_I32 */ i32_func_i32_i32, +/* SDIV_I64 */ i64_func_i64_i64, +/* SDIV_I128 */ i64_i64_func_i64_i64_i64_i64, +/* UDIV_I8 */ i8_func_i8_i8, +/* UDIV_I16 */ i16_func_i16_i16, +/* UDIV_I32 */ i32_func_i32_i32, +/* UDIV_I64 */ i64_func_i64_i64, +/* UDIV_I128 */ i64_i64_func_i64_i64_i64_i64, +/* SREM_I8 */ i8_func_i8_i8, +/* SREM_I16 */ i16_func_i16_i16, +/* SREM_I32 */ i32_func_i32_i32, +/* SREM_I64 */ i64_func_i64_i64, +/* SREM_I128 */ i64_i64_func_i64_i64_i64_i64, +/* UREM_I8 */ i8_func_i8_i8, +/* UREM_I16 */ i16_func_i16_i16, +/* UREM_I32 */ i32_func_i32_i32, +/* UREM_I64 */ i64_func_i64_i64, +/* UREM_I128 */ i64_i64_func_i64_i64_i64_i64, +/* SDIVREM_I8 */ i8_func_i8_i8, +/* SDIVREM_I16 */ i16_i16_func_i16_i16, +/* SDIVREM_I32 */ i32_i32_func_i32_i32, +/* SDIVREM_I64 */ i64_func_i64_i64, +/* SDIVREM_I128 */ i64_i64_i64_i64_func_i64_i64_i64_i64, +/* UDIVREM_I8 */ i8_func_i8_i8, +/* UDIVREM_I16 */ i16_i16_func_i16_i16, +/* UDIVREM_I32 */ i32_i32_func_i32_i32, +/* UDIVREM_I64 */ i64_i64_func_i64_i64, +/* UDIVREM_I128 */ i64_i64_i64_i64_func_i64_i64_i64_i64, +/* NEG_I32 */ i32_func_i32, +/* NEG_I64 */ i64_func_i64, + +// FLOATING POINT +/* ADD_F32 */ f32_func_f32_f32, +/* ADD_F64 */ f64_func_f64_f64, +/* ADD_F80 */ unsupported, +/* ADD_F128 */ func_iPTR_i64_i64_i64_i64, +/* ADD_PPCF128 */ unsupported, +/* SUB_F32 */ f32_func_f32_f32, +/* SUB_F64 */ f64_func_f64_f64, +/* SUB_F80 */ unsupported, +/* SUB_F128 */ func_iPTR_i64_i64_i64_i64, +/* SUB_PPCF128 */ unsupported, +/* MUL_F32 */ f32_func_f32_f32, +/* MUL_F64 */ f64_func_f64_f64, +/* MUL_F80 */ unsupported, +/* MUL_F128 */ func_iPTR_i64_i64_i64_i64, +/* MUL_PPCF128 */ unsupported, +/* DIV_F32 */ f32_func_f32_f32, +/* DIV_F64 */ f64_func_f64_f64, +/* DIV_F80 */ unsupported, +/* DIV_F128 */ func_iPTR_i64_i64_i64_i64, +/* DIV_PPCF128 */ unsupported, +/* REM_F32 */ f32_func_f32_f32, +/* REM_F64 */ f64_func_f64_f64, +/* REM_F80 */ unsupported, +/* REM_F128 */ func_iPTR_i64_i64_i64_i64, +/* REM_PPCF128 */ unsupported, +/* FMA_F32 */ f32_func_f32_f32_f32, +/* FMA_F64 */ f64_func_f64_f64_f64, +/* FMA_F80 */ unsupported, +/* FMA_F128 */ func_iPTR_i64_i64_i64_i64_i64_i64, +/* FMA_PPCF128 */ unsupported, +/* POWI_F32 */ f32_func_f32_i32, +/* POWI_F64 */ f64_func_f64_i32, +/* POWI_F80 */ unsupported, +/* POWI_F128 */ func_iPTR_i64_i64_i64_i64, +/* POWI_PPCF128 */ unsupported, +/* SQRT_F32 */ f32_func_f32, +/* SQRT_F64 */ f64_func_f64, +/* SQRT_F80 */ unsupported, +/* SQRT_F128 */ func_iPTR_i64_i64, +/* SQRT_PPCF128 */ unsupported, +/* LOG_F32 */ f32_func_f32, +/* LOG_F64 */ f64_func_f64, +/* LOG_F80 */ unsupported, +/* LOG_F128 */ func_iPTR_i64_i64, +/* LOG_PPCF128 */ unsupported, +/* LOG2_F32 */ f32_func_f32, +/* LOG2_F64 */ f64_func_f64, +/* LOG2_F80 */ unsupported, +/* LOG2_F128 */ func_iPTR_i64_i64, +/* LOG2_PPCF128 */ unsupported, +/* LOG10_F32 */ f32_func_f32, +/* LOG10_F64 */ f64_func_f64, +/* LOG10_F80 */ unsupported, +/* LOG10_F128 */ func_iPTR_i64_i64, +/* LOG10_PPCF128 */ unsupported, +/* EXP_F32 */ f32_func_f32, +/* EXP_F64 */ f64_func_f64, +/* EXP_F80 */ unsupported, +/* EXP_F128 */ func_iPTR_i64_i64, +/* EXP_PPCF128 */ unsupported, +/* EXP2_F32 */ f32_func_f32, +/* EXP2_F64 */ f64_func_f64, +/* EXP2_F80 */ unsupported, +/* EXP2_F128 */ func_iPTR_i64_i64, +/* EXP2_PPCF128 */ unsupported, +/* SIN_F32 */ f32_func_f32, +/* SIN_F64 */ f64_func_f64, +/* SIN_F80 */ unsupported, +/* SIN_F128 */ func_iPTR_i64_i64, +/* SIN_PPCF128 */ unsupported, +/* COS_F32 */ f32_func_f32, +/* COS_F64 */ f64_func_f64, +/* COS_F80 */ unsupported, +/* COS_F128 */ func_iPTR_i64_i64, +/* COS_PPCF128 */ unsupported, +/* SINCOS_F32 */ func_f32_iPTR_iPTR, +/* SINCOS_F64 */ func_f64_iPTR_iPTR, +/* SINCOS_F80 */ unsupported, +/* SINCOS_F128 */ func_i64_i64_iPTR_iPTR, +/* SINCOS_PPCF128 */ unsupported, +/* POW_F32 */ f32_func_f32_f32, +/* POW_F64 */ f64_func_f64_f64, +/* POW_F80 */ unsupported, +/* POW_F128 */ func_iPTR_i64_i64_i64_i64, +/* POW_PPCF128 */ unsupported, +/* CEIL_F32 */ f32_func_f32, +/* CEIL_F64 */ f64_func_f64, +/* CEIL_F80 */ unsupported, +/* CEIL_F128 */ func_iPTR_i64_i64, +/* CEIL_PPCF128 */ unsupported, +/* TRUNC_F32 */ f32_func_f32, +/* TRUNC_F64 */ f64_func_f64, +/* TRUNC_F80 */ unsupported, +/* TRUNC_F128 */ func_iPTR_i64_i64, +/* TRUNC_PPCF128 */ unsupported, +/* RINT_F32 */ f32_func_f32, +/* RINT_F64 */ f64_func_f64, +/* RINT_F80 */ unsupported, +/* RINT_F128 */ func_iPTR_i64_i64, +/* RINT_PPCF128 */ unsupported, +/* NEARBYINT_F32 */ f32_func_f32, +/* NEARBYINT_F64 */ f64_func_f64, +/* NEARBYINT_F80 */ unsupported, +/* NEARBYINT_F128 */ func_iPTR_i64_i64, +/* NEARBYINT_PPCF128 */ unsupported, +/* ROUND_F32 */ f32_func_f32, +/* ROUND_F64 */ f64_func_f64, +/* ROUND_F80 */ unsupported, +/* ROUND_F128 */ func_iPTR_i64_i64, +/* ROUND_PPCF128 */ unsupported, +/* FLOOR_F32 */ f32_func_f32, +/* FLOOR_F64 */ f64_func_f64, +/* FLOOR_F80 */ unsupported, +/* FLOOR_F128 */ func_iPTR_i64_i64, +/* FLOOR_PPCF128 */ unsupported, +/* COPYSIGN_F32 */ f32_func_f32_f32, +/* COPYSIGN_F64 */ f64_func_f64_f64, +/* COPYSIGN_F80 */ unsupported, +/* COPYSIGN_F128 */ func_iPTR_i64_i64_i64_i64, +/* COPYSIGN_PPCF128 */ unsupported, +/* FMIN_F32 */ f32_func_f32_f32, +/* FMIN_F64 */ f64_func_f64_f64, +/* FMIN_F80 */ unsupported, +/* FMIN_F128 */ func_iPTR_i64_i64_i64_i64, +/* FMIN_PPCF128 */ unsupported, +/* FMAX_F32 */ f32_func_f32_f32, +/* FMAX_F64 */ f64_func_f64_f64, +/* FMAX_F80 */ unsupported, +/* FMAX_F128 */ func_iPTR_i64_i64_i64_i64, +/* FMAX_PPCF128 */ unsupported, + +// CONVERSION +/* FPEXT_F32_PPCF128 */ unsupported, +/* FPEXT_F64_PPCF128 */ unsupported, +/* FPEXT_F64_F128 */ func_iPTR_f64, +/* FPEXT_F32_F128 */ func_iPTR_f32, +/* FPEXT_F32_F64 */ f64_func_f32, +/* FPEXT_F16_F32 */ f32_func_i16, +/* FPROUND_F32_F16 */ i16_func_f32, +/* FPROUND_F64_F16 */ unsupported, +/* FPROUND_F80_F16 */ unsupported, +/* FPROUND_F128_F16 */ unsupported, +/* FPROUND_PPCF128_F16 */ unsupported, +/* FPROUND_F64_F32 */ f32_func_f64, +/* FPROUND_F80_F32 */ unsupported, +/* FPROUND_F128_F32 */ f32_func_i64_i64, +/* FPROUND_PPCF128_F32 */ unsupported, +/* FPROUND_F80_F64 */ unsupported, +/* FPROUND_F128_F64 */ f64_func_i64_i64, +/* FPROUND_PPCF128_F64 */ unsupported, +/* FPTOSINT_F32_I32 */ i32_func_f32, +/* FPTOSINT_F32_I64 */ i64_func_f32, +/* FPTOSINT_F32_I128 */ i64_i64_func_f32, +/* FPTOSINT_F64_I32 */ i32_func_f64, +/* FPTOSINT_F64_I64 */ i64_func_f64, +/* FPTOSINT_F64_I128 */ i64_i64_func_f64, +/* FPTOSINT_F80_I32 */ unsupported, +/* FPTOSINT_F80_I64 */ unsupported, +/* FPTOSINT_F80_I128 */ unsupported, +/* FPTOSINT_F128_I32 */ i32_func_i64_i64, +/* FPTOSINT_F128_I64 */ i64_func_i64_i64, +/* FPTOSINT_F128_I128 */ i64_i64_func_i64_i64, +/* FPTOSINT_PPCF128_I32 */ unsupported, +/* FPTOSINT_PPCF128_I64 */ unsupported, +/* FPTOSINT_PPCF128_I128 */ unsupported, +/* FPTOUINT_F32_I32 */ i32_func_f32, +/* FPTOUINT_F32_I64 */ i64_func_f32, +/* FPTOUINT_F32_I128 */ i64_i64_func_f32, +/* FPTOUINT_F64_I32 */ i32_func_f64, +/* FPTOUINT_F64_I64 */ i64_func_f64, +/* FPTOUINT_F64_I128 */ i64_i64_func_f64, +/* FPTOUINT_F80_I32 */ unsupported, +/* FPTOUINT_F80_I64 */ unsupported, +/* FPTOUINT_F80_I128 */ unsupported, +/* FPTOUINT_F128_I32 */ i32_func_i64_i64, +/* FPTOUINT_F128_I64 */ i64_func_i64_i64, +/* FPTOUINT_F128_I128 */ i64_i64_func_i64_i64, +/* FPTOUINT_PPCF128_I32 */ unsupported, +/* FPTOUINT_PPCF128_I64 */ unsupported, +/* FPTOUINT_PPCF128_I128 */ unsupported, +/* SINTTOFP_I32_F32 */ f32_func_i32, +/* SINTTOFP_I32_F64 */ f64_func_i32, +/* SINTTOFP_I32_F80 */ unsupported, +/* SINTTOFP_I32_F128 */ func_iPTR_i32, +/* SINTTOFP_I32_PPCF128 */ unsupported, +/* SINTTOFP_I64_F32 */ f32_func_i64, +/* SINTTOFP_I64_F64 */ f64_func_i64, +/* SINTTOFP_I64_F80 */ unsupported, +/* SINTTOFP_I64_F128 */ func_iPTR_i64, +/* SINTTOFP_I64_PPCF128 */ unsupported, +/* SINTTOFP_I128_F32 */ f32_func_i64_i64, +/* SINTTOFP_I128_F64 */ f64_func_i64_i64, +/* SINTTOFP_I128_F80 */ unsupported, +/* SINTTOFP_I128_F128 */ func_iPTR_i64_i64, +/* SINTTOFP_I128_PPCF128 */ unsupported, +/* UINTTOFP_I32_F32 */ f32_func_i32, +/* UINTTOFP_I32_F64 */ f64_func_i64, +/* UINTTOFP_I32_F80 */ unsupported, +/* UINTTOFP_I32_F128 */ func_iPTR_i32, +/* UINTTOFP_I32_PPCF128 */ unsupported, +/* UINTTOFP_I64_F32 */ f32_func_i64, +/* UINTTOFP_I64_F64 */ f64_func_i64, +/* UINTTOFP_I64_F80 */ unsupported, +/* UINTTOFP_I64_F128 */ func_iPTR_i64, +/* UINTTOFP_I64_PPCF128 */ unsupported, +/* UINTTOFP_I128_F32 */ f32_func_i64_i64, +/* UINTTOFP_I128_F64 */ f64_func_i64_i64, +/* UINTTOFP_I128_F80 */ unsupported, +/* UINTTOFP_I128_F128 */ func_iPTR_i64_i64, +/* UINTTOFP_I128_PPCF128 */ unsupported, + +// COMPARISON +/* OEQ_F32 */ i32_func_f32_f32, +/* OEQ_F64 */ i32_func_f64_f64, +/* OEQ_F128 */ i32_func_i64_i64_i64_i64, +/* OEQ_PPCF128 */ unsupported, +/* UNE_F32 */ i32_func_f32_f32, +/* UNE_F64 */ i32_func_f64_f64, +/* UNE_F128 */ i32_func_i64_i64_i64_i64, +/* UNE_PPCF128 */ unsupported, +/* OGE_F32 */ i32_func_f32_f32, +/* OGE_F64 */ i32_func_f64_f64, +/* OGE_F128 */ i32_func_i64_i64_i64_i64, +/* OGE_PPCF128 */ unsupported, +/* OLT_F32 */ i32_func_f32_f32, +/* OLT_F64 */ i32_func_f64_f64, +/* OLT_F128 */ i32_func_i64_i64_i64_i64, +/* OLT_PPCF128 */ unsupported, +/* OLE_F32 */ i32_func_f32_f32, +/* OLE_F64 */ i32_func_f64_f64, +/* OLE_F128 */ i32_func_i64_i64_i64_i64, +/* OLE_PPCF128 */ unsupported, +/* OGT_F32 */ i32_func_f32_f32, +/* OGT_F64 */ i32_func_f64_f64, +/* OGT_F128 */ i32_func_i64_i64_i64_i64, +/* OGT_PPCF128 */ unsupported, +/* UO_F32 */ i32_func_f32_f32, +/* UO_F64 */ i32_func_f64_f64, +/* UO_F128 */ i32_func_i64_i64_i64_i64, +/* UO_PPCF128 */ unsupported, +/* O_F32 */ i32_func_f32_f32, +/* O_F64 */ i32_func_f64_f64, +/* O_F128 */ i32_func_i64_i64_i64_i64, +/* O_PPCF128 */ unsupported, + +// MEMORY +/* MEMCPY */ iPTR_func_iPTR_iPTR_iPTR, +/* MEMSET */ iPTR_func_iPTR_i32_iPTR, +/* MEMMOVE */ iPTR_func_iPTR_iPTR_iPTR, + +// ELEMENT-WISE ATOMIC MEMORY +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_1 */ unsupported, +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_2 */ unsupported, +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_4 */ unsupported, +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_8 */ unsupported, +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_16 */ unsupported, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1 */ unsupported, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2 */ unsupported, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4 */ unsupported, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8 */ unsupported, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16 */ unsupported, + +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_1 */ unsupported, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_2 */ unsupported, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_4 */ unsupported, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_8 */ unsupported, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_16 */ unsupported, + +// EXCEPTION HANDLING +/* UNWIND_RESUME */ unsupported, + +// Note: there's two sets of atomics libcalls; see +// <http://llvm.org/docs/Atomics.html> for more info on the +// difference between them. + +// Atomic '__sync_*' libcalls. +/* SYNC_VAL_COMPARE_AND_SWAP_1 */ unsupported, +/* SYNC_VAL_COMPARE_AND_SWAP_2 */ unsupported, +/* SYNC_VAL_COMPARE_AND_SWAP_4 */ unsupported, +/* SYNC_VAL_COMPARE_AND_SWAP_8 */ unsupported, +/* SYNC_VAL_COMPARE_AND_SWAP_16 */ unsupported, +/* SYNC_LOCK_TEST_AND_SET_1 */ unsupported, +/* SYNC_LOCK_TEST_AND_SET_2 */ unsupported, +/* SYNC_LOCK_TEST_AND_SET_4 */ unsupported, +/* SYNC_LOCK_TEST_AND_SET_8 */ unsupported, +/* SYNC_LOCK_TEST_AND_SET_16 */ unsupported, +/* SYNC_FETCH_AND_ADD_1 */ unsupported, +/* SYNC_FETCH_AND_ADD_2 */ unsupported, +/* SYNC_FETCH_AND_ADD_4 */ unsupported, +/* SYNC_FETCH_AND_ADD_8 */ unsupported, +/* SYNC_FETCH_AND_ADD_16 */ unsupported, +/* SYNC_FETCH_AND_SUB_1 */ unsupported, +/* SYNC_FETCH_AND_SUB_2 */ unsupported, +/* SYNC_FETCH_AND_SUB_4 */ unsupported, +/* SYNC_FETCH_AND_SUB_8 */ unsupported, +/* SYNC_FETCH_AND_SUB_16 */ unsupported, +/* SYNC_FETCH_AND_AND_1 */ unsupported, +/* SYNC_FETCH_AND_AND_2 */ unsupported, +/* SYNC_FETCH_AND_AND_4 */ unsupported, +/* SYNC_FETCH_AND_AND_8 */ unsupported, +/* SYNC_FETCH_AND_AND_16 */ unsupported, +/* SYNC_FETCH_AND_OR_1 */ unsupported, +/* SYNC_FETCH_AND_OR_2 */ unsupported, +/* SYNC_FETCH_AND_OR_4 */ unsupported, +/* SYNC_FETCH_AND_OR_8 */ unsupported, +/* SYNC_FETCH_AND_OR_16 */ unsupported, +/* SYNC_FETCH_AND_XOR_1 */ unsupported, +/* SYNC_FETCH_AND_XOR_2 */ unsupported, +/* SYNC_FETCH_AND_XOR_4 */ unsupported, +/* SYNC_FETCH_AND_XOR_8 */ unsupported, +/* SYNC_FETCH_AND_XOR_16 */ unsupported, +/* SYNC_FETCH_AND_NAND_1 */ unsupported, +/* SYNC_FETCH_AND_NAND_2 */ unsupported, +/* SYNC_FETCH_AND_NAND_4 */ unsupported, +/* SYNC_FETCH_AND_NAND_8 */ unsupported, +/* SYNC_FETCH_AND_NAND_16 */ unsupported, +/* SYNC_FETCH_AND_MAX_1 */ unsupported, +/* SYNC_FETCH_AND_MAX_2 */ unsupported, +/* SYNC_FETCH_AND_MAX_4 */ unsupported, +/* SYNC_FETCH_AND_MAX_8 */ unsupported, +/* SYNC_FETCH_AND_MAX_16 */ unsupported, +/* SYNC_FETCH_AND_UMAX_1 */ unsupported, +/* SYNC_FETCH_AND_UMAX_2 */ unsupported, +/* SYNC_FETCH_AND_UMAX_4 */ unsupported, +/* SYNC_FETCH_AND_UMAX_8 */ unsupported, +/* SYNC_FETCH_AND_UMAX_16 */ unsupported, +/* SYNC_FETCH_AND_MIN_1 */ unsupported, +/* SYNC_FETCH_AND_MIN_2 */ unsupported, +/* SYNC_FETCH_AND_MIN_4 */ unsupported, +/* SYNC_FETCH_AND_MIN_8 */ unsupported, +/* SYNC_FETCH_AND_MIN_16 */ unsupported, +/* SYNC_FETCH_AND_UMIN_1 */ unsupported, +/* SYNC_FETCH_AND_UMIN_2 */ unsupported, +/* SYNC_FETCH_AND_UMIN_4 */ unsupported, +/* SYNC_FETCH_AND_UMIN_8 */ unsupported, +/* SYNC_FETCH_AND_UMIN_16 */ unsupported, + +// Atomic '__atomic_*' libcalls. +/* ATOMIC_LOAD */ unsupported, +/* ATOMIC_LOAD_1 */ unsupported, +/* ATOMIC_LOAD_2 */ unsupported, +/* ATOMIC_LOAD_4 */ unsupported, +/* ATOMIC_LOAD_8 */ unsupported, +/* ATOMIC_LOAD_16 */ unsupported, + +/* ATOMIC_STORE */ unsupported, +/* ATOMIC_STORE_1 */ unsupported, +/* ATOMIC_STORE_2 */ unsupported, +/* ATOMIC_STORE_4 */ unsupported, +/* ATOMIC_STORE_8 */ unsupported, +/* ATOMIC_STORE_16 */ unsupported, + +/* ATOMIC_EXCHANGE */ unsupported, +/* ATOMIC_EXCHANGE_1 */ unsupported, +/* ATOMIC_EXCHANGE_2 */ unsupported, +/* ATOMIC_EXCHANGE_4 */ unsupported, +/* ATOMIC_EXCHANGE_8 */ unsupported, +/* ATOMIC_EXCHANGE_16 */ unsupported, + +/* ATOMIC_COMPARE_EXCHANGE */ unsupported, +/* ATOMIC_COMPARE_EXCHANGE_1 */ unsupported, +/* ATOMIC_COMPARE_EXCHANGE_2 */ unsupported, +/* ATOMIC_COMPARE_EXCHANGE_4 */ unsupported, +/* ATOMIC_COMPARE_EXCHANGE_8 */ unsupported, +/* ATOMIC_COMPARE_EXCHANGE_16 */ unsupported, + +/* ATOMIC_FETCH_ADD_1 */ unsupported, +/* ATOMIC_FETCH_ADD_2 */ unsupported, +/* ATOMIC_FETCH_ADD_4 */ unsupported, +/* ATOMIC_FETCH_ADD_8 */ unsupported, +/* ATOMIC_FETCH_ADD_16 */ unsupported, + +/* ATOMIC_FETCH_SUB_1 */ unsupported, +/* ATOMIC_FETCH_SUB_2 */ unsupported, +/* ATOMIC_FETCH_SUB_4 */ unsupported, +/* ATOMIC_FETCH_SUB_8 */ unsupported, +/* ATOMIC_FETCH_SUB_16 */ unsupported, + +/* ATOMIC_FETCH_AND_1 */ unsupported, +/* ATOMIC_FETCH_AND_2 */ unsupported, +/* ATOMIC_FETCH_AND_4 */ unsupported, +/* ATOMIC_FETCH_AND_8 */ unsupported, +/* ATOMIC_FETCH_AND_16 */ unsupported, + +/* ATOMIC_FETCH_OR_1 */ unsupported, +/* ATOMIC_FETCH_OR_2 */ unsupported, +/* ATOMIC_FETCH_OR_4 */ unsupported, +/* ATOMIC_FETCH_OR_8 */ unsupported, +/* ATOMIC_FETCH_OR_16 */ unsupported, + +/* ATOMIC_FETCH_XOR_1 */ unsupported, +/* ATOMIC_FETCH_XOR_2 */ unsupported, +/* ATOMIC_FETCH_XOR_4 */ unsupported, +/* ATOMIC_FETCH_XOR_8 */ unsupported, +/* ATOMIC_FETCH_XOR_16 */ unsupported, + +/* ATOMIC_FETCH_NAND_1 */ unsupported, +/* ATOMIC_FETCH_NAND_2 */ unsupported, +/* ATOMIC_FETCH_NAND_4 */ unsupported, +/* ATOMIC_FETCH_NAND_8 */ unsupported, +/* ATOMIC_FETCH_NAND_16 */ unsupported, + +// Stack Protector Fail. +/* STACKPROTECTOR_CHECK_FAIL */ func, + +// Deoptimization. +/* DEOPTIMIZE */ unsupported, + +}; + +static const char * +RuntimeLibcallNames[RTLIB::UNKNOWN_LIBCALL] = { +/* SHL_I16 */ "__ashlhi3", +/* SHL_I32 */ "__ashlsi3", +/* SHL_I64 */ "__ashldi3", +/* SHL_I128 */ "__ashlti3", +/* SRL_I16 */ "__lshrhi3", +/* SRL_I32 */ "__lshrsi3", +/* SRL_I64 */ "__lshrdi3", +/* SRL_I128 */ "__lshrti3", +/* SRA_I16 */ "__ashrhi3", +/* SRA_I32 */ "__ashrsi3", +/* SRA_I64 */ "__ashrdi3", +/* SRA_I128 */ "__ashrti3", +/* MUL_I8 */ "__mulqi3", +/* MUL_I16 */ "__mulhi3", +/* MUL_I32 */ "__mulsi3", +/* MUL_I64 */ "__muldi3", +/* MUL_I128 */ "__multi3", +/* MULO_I32 */ "__mulosi4", +/* MULO_I64 */ "__mulodi4", +/* MULO_I128 */ "__muloti4", +/* SDIV_I8 */ "__divqi3", +/* SDIV_I16 */ "__divhi3", +/* SDIV_I32 */ "__divsi3", +/* SDIV_I64 */ "__divdi3", +/* SDIV_I128 */ "__divti3", +/* UDIV_I8 */ "__udivqi3", +/* UDIV_I16 */ "__udivhi3", +/* UDIV_I32 */ "__udivsi3", +/* UDIV_I64 */ "__udivdi3", +/* UDIV_I128 */ "__udivti3", +/* SREM_I8 */ "__modqi3", +/* SREM_I16 */ "__modhi3", +/* SREM_I32 */ "__modsi3", +/* SREM_I64 */ "__moddi3", +/* SREM_I128 */ "__modti3", +/* UREM_I8 */ "__umodqi3", +/* UREM_I16 */ "__umodhi3", +/* UREM_I32 */ "__umodsi3", +/* UREM_I64 */ "__umoddi3", +/* UREM_I128 */ "__umodti3", +/* SDIVREM_I8 */ nullptr, +/* SDIVREM_I16 */ nullptr, +/* SDIVREM_I32 */ nullptr, +/* SDIVREM_I64 */ nullptr, +/* SDIVREM_I128 */ nullptr, +/* UDIVREM_I8 */ nullptr, +/* UDIVREM_I16 */ nullptr, +/* UDIVREM_I32 */ nullptr, +/* UDIVREM_I64 */ nullptr, +/* UDIVREM_I128 */ nullptr, +/* NEG_I32 */ "__negsi2", +/* NEG_I64 */ "__negdi2", +/* ADD_F32 */ "__addsf3", +/* ADD_F64 */ "__adddf3", +/* ADD_F80 */ nullptr, +/* ADD_F128 */ "__addtf3", +/* ADD_PPCF128 */ nullptr, +/* SUB_F32 */ "__subsf3", +/* SUB_F64 */ "__subdf3", +/* SUB_F80 */ nullptr, +/* SUB_F128 */ "__subtf3", +/* SUB_PPCF128 */ nullptr, +/* MUL_F32 */ "__mulsf3", +/* MUL_F64 */ "__muldf3", +/* MUL_F80 */ nullptr, +/* MUL_F128 */ "__multf3", +/* MUL_PPCF128 */ nullptr, +/* DIV_F32 */ "__divsf3", +/* DIV_F64 */ "__divdf3", +/* DIV_F80 */ nullptr, +/* DIV_F128 */ "__divtf3", +/* DIV_PPCF128 */ nullptr, +/* REM_F32 */ "fmodf", +/* REM_F64 */ "fmod", +/* REM_F80 */ nullptr, +/* REM_F128 */ "fmodl", +/* REM_PPCF128 */ nullptr, +/* FMA_F32 */ "fmaf", +/* FMA_F64 */ "fma", +/* FMA_F80 */ nullptr, +/* FMA_F128 */ "fmal", +/* FMA_PPCF128 */ nullptr, +/* POWI_F32 */ "__powisf2", +/* POWI_F64 */ "__powidf2", +/* POWI_F80 */ nullptr, +/* POWI_F128 */ "__powitf2", +/* POWI_PPCF128 */ nullptr, +/* SQRT_F32 */ "sqrtf", +/* SQRT_F64 */ "sqrt", +/* SQRT_F80 */ nullptr, +/* SQRT_F128 */ "sqrtl", +/* SQRT_PPCF128 */ nullptr, +/* LOG_F32 */ "logf", +/* LOG_F64 */ "log", +/* LOG_F80 */ nullptr, +/* LOG_F128 */ "logl", +/* LOG_PPCF128 */ nullptr, +/* LOG2_F32 */ "log2f", +/* LOG2_F64 */ "log2", +/* LOG2_F80 */ nullptr, +/* LOG2_F128 */ "log2l", +/* LOG2_PPCF128 */ nullptr, +/* LOG10_F32 */ "log10f", +/* LOG10_F64 */ "log10", +/* LOG10_F80 */ nullptr, +/* LOG10_F128 */ "log10l", +/* LOG10_PPCF128 */ nullptr, +/* EXP_F32 */ "expf", +/* EXP_F64 */ "exp", +/* EXP_F80 */ nullptr, +/* EXP_F128 */ "expl", +/* EXP_PPCF128 */ nullptr, +/* EXP2_F32 */ "exp2f", +/* EXP2_F64 */ "exp2", +/* EXP2_F80 */ nullptr, +/* EXP2_F128 */ "exp2l", +/* EXP2_PPCF128 */ nullptr, +/* SIN_F32 */ "sinf", +/* SIN_F64 */ "sin", +/* SIN_F80 */ nullptr, +/* SIN_F128 */ "sinl", +/* SIN_PPCF128 */ nullptr, +/* COS_F32 */ "cosf", +/* COS_F64 */ "cos", +/* COS_F80 */ nullptr, +/* COS_F128 */ "cosl", +/* COS_PPCF128 */ nullptr, +/* SINCOS_F32 */ "sincosf", +/* SINCOS_F64 */ "sincos", +/* SINCOS_F80 */ nullptr, +/* SINCOS_F128 */ "sincosl", +/* SINCOS_PPCF128 */ nullptr, +/* POW_F32 */ "powf", +/* POW_F64 */ "pow", +/* POW_F80 */ nullptr, +/* POW_F128 */ "powl", +/* POW_PPCF128 */ nullptr, +/* CEIL_F32 */ "ceilf", +/* CEIL_F64 */ "ceil", +/* CEIL_F80 */ nullptr, +/* CEIL_F128 */ "ceill", +/* CEIL_PPCF128 */ nullptr, +/* TRUNC_F32 */ "truncf", +/* TRUNC_F64 */ "trunc", +/* TRUNC_F80 */ nullptr, +/* TRUNC_F128 */ "truncl", +/* TRUNC_PPCF128 */ nullptr, +/* RINT_F32 */ "rintf", +/* RINT_F64 */ "rint", +/* RINT_F80 */ nullptr, +/* RINT_F128 */ "rintl", +/* RINT_PPCF128 */ nullptr, +/* NEARBYINT_F32 */ "nearbyintf", +/* NEARBYINT_F64 */ "nearbyint", +/* NEARBYINT_F80 */ nullptr, +/* NEARBYINT_F128 */ "nearbyintl", +/* NEARBYINT_PPCF128 */ nullptr, +/* ROUND_F32 */ "roundf", +/* ROUND_F64 */ "round", +/* ROUND_F80 */ nullptr, +/* ROUND_F128 */ "roundl", +/* ROUND_PPCF128 */ nullptr, +/* FLOOR_F32 */ "floorf", +/* FLOOR_F64 */ "floor", +/* FLOOR_F80 */ nullptr, +/* FLOOR_F128 */ "floorl", +/* FLOOR_PPCF128 */ nullptr, +/* COPYSIGN_F32 */ "copysignf", +/* COPYSIGN_F64 */ "copysign", +/* COPYSIGN_F80 */ nullptr, +/* COPYSIGN_F128 */ "copysignl", +/* COPYSIGN_PPCF128 */ nullptr, +/* FMIN_F32 */ "fminf", +/* FMIN_F64 */ "fmin", +/* FMIN_F80 */ nullptr, +/* FMIN_F128 */ "fminl", +/* FMIN_PPCF128 */ nullptr, +/* FMAX_F32 */ "fmaxf", +/* FMAX_F64 */ "fmax", +/* FMAX_F80 */ nullptr, +/* FMAX_F128 */ "fmaxl", +/* FMAX_PPCF128 */ nullptr, +/* FPEXT_F32_PPCF128 */ nullptr, +/* FPEXT_F64_PPCF128 */ nullptr, +/* FPEXT_F64_F128 */ "__extenddftf2", +/* FPEXT_F32_F128 */ "__extendsftf2", +/* FPEXT_F32_F64 */ "__extendsfdf2", +/* FPEXT_F16_F32 */ "__gnu_h2f_ieee", +/* FPROUND_F32_F16 */ "__gnu_f2h_ieee", +/* FPROUND_F64_F16 */ nullptr, +/* FPROUND_F80_F16 */ nullptr, +/* FPROUND_F128_F16 */ nullptr, +/* FPROUND_PPCF128_F16 */ nullptr, +/* FPROUND_F64_F32 */ "__truncdfsf2", +/* FPROUND_F80_F32 */ "__truncxfsf2", +/* FPROUND_F128_F32 */ "__trunctfsf2", +/* FPROUND_PPCF128_F32 */ nullptr, +/* FPROUND_F80_F64 */ "__truncxfdf2", +/* FPROUND_F128_F64 */ "__trunctfdf2", +/* FPROUND_PPCF128_F64 */ nullptr, +/* FPTOSINT_F32_I32 */ "__fixsfsi", +/* FPTOSINT_F32_I64 */ "__fixsfdi", +/* FPTOSINT_F32_I128 */ "__fixsfti", +/* FPTOSINT_F64_I32 */ "__fixdfsi", +/* FPTOSINT_F64_I64 */ "__fixdfdi", +/* FPTOSINT_F64_I128 */ "__fixdfti", +/* FPTOSINT_F80_I32 */ "__fixxfsi", +/* FPTOSINT_F80_I64 */ "__fixxfdi", +/* FPTOSINT_F80_I128 */ "__fixxfti", +/* FPTOSINT_F128_I32 */ "__fixtfsi", +/* FPTOSINT_F128_I64 */ "__fixtfdi", +/* FPTOSINT_F128_I128 */ "__fixtfti", +/* FPTOSINT_PPCF128_I32 */ nullptr, +/* FPTOSINT_PPCF128_I64 */ nullptr, +/* FPTOSINT_PPCF128_I128 */ nullptr, +/* FPTOUINT_F32_I32 */ "__fixunssfsi", +/* FPTOUINT_F32_I64 */ "__fixunssfdi", +/* FPTOUINT_F32_I128 */ "__fixunssfti", +/* FPTOUINT_F64_I32 */ "__fixunsdfsi", +/* FPTOUINT_F64_I64 */ "__fixunsdfdi", +/* FPTOUINT_F64_I128 */ "__fixunsdfti", +/* FPTOUINT_F80_I32 */ "__fixunsxfsi", +/* FPTOUINT_F80_I64 */ "__fixunsxfdi", +/* FPTOUINT_F80_I128 */ "__fixunsxfti", +/* FPTOUINT_F128_I32 */ "__fixunstfsi", +/* FPTOUINT_F128_I64 */ "__fixunstfdi", +/* FPTOUINT_F128_I128 */ "__fixunstfti", +/* FPTOUINT_PPCF128_I32 */ nullptr, +/* FPTOUINT_PPCF128_I64 */ nullptr, +/* FPTOUINT_PPCF128_I128 */ nullptr, +/* SINTTOFP_I32_F32 */ "__floatsisf", +/* SINTTOFP_I32_F64 */ "__floatsidf", +/* SINTTOFP_I32_F80 */ nullptr, +/* SINTTOFP_I32_F128 */ "__floatsitf", +/* SINTTOFP_I32_PPCF128 */ nullptr, +/* SINTTOFP_I64_F32 */ "__floatdisf", +/* SINTTOFP_I64_F64 */ "__floatdidf", +/* SINTTOFP_I64_F80 */ nullptr, +/* SINTTOFP_I64_F128 */ "__floatditf", +/* SINTTOFP_I64_PPCF128 */ nullptr, +/* SINTTOFP_I128_F32 */ "__floattisf", +/* SINTTOFP_I128_F64 */ "__floattidf", +/* SINTTOFP_I128_F80 */ nullptr, +/* SINTTOFP_I128_F128 */ "__floattitf", +/* SINTTOFP_I128_PPCF128 */ nullptr, +/* UINTTOFP_I32_F32 */ "__floatunsisf", +/* UINTTOFP_I32_F64 */ "__floatunsidf", +/* UINTTOFP_I32_F80 */ nullptr, +/* UINTTOFP_I32_F128 */ "__floatunsitf", +/* UINTTOFP_I32_PPCF128 */ nullptr, +/* UINTTOFP_I64_F32 */ "__floatundisf", +/* UINTTOFP_I64_F64 */ "__floatundidf", +/* UINTTOFP_I64_F80 */ nullptr, +/* UINTTOFP_I64_F128 */ "__floatunditf", +/* UINTTOFP_I64_PPCF128 */ nullptr, +/* UINTTOFP_I128_F32 */ "__floatuntisf", +/* UINTTOFP_I128_F64 */ "__floatuntidf", +/* UINTTOFP_I128_F80 */ nullptr, +/* UINTTOFP_I128_F128 */ "__floatuntitf", +/* UINTTOFP_I128_PPCF128 */ nullptr, +/* OEQ_F32 */ "__eqsf2", +/* OEQ_F64 */ "__eqdf2", +/* OEQ_F128 */ "__eqtf2", +/* OEQ_PPCF128 */ nullptr, +/* UNE_F32 */ "__nesf2", +/* UNE_F64 */ "__nedf2", +/* UNE_F128 */ "__netf2", +/* UNE_PPCF128 */ nullptr, +/* OGE_F32 */ "__gesf2", +/* OGE_F64 */ "__gedf2", +/* OGE_F128 */ "__getf2", +/* OGE_PPCF128 */ nullptr, +/* OLT_F32 */ "__ltsf2", +/* OLT_F64 */ "__ltdf2", +/* OLT_F128 */ "__lttf2", +/* OLT_PPCF128 */ nullptr, +/* OLE_F32 */ "__lesf2", +/* OLE_F64 */ "__ledf2", +/* OLE_F128 */ "__letf2", +/* OLE_PPCF128 */ nullptr, +/* OGT_F32 */ "__gtsf2", +/* OGT_F64 */ "__gtdf2", +/* OGT_F128 */ "__gttf2", +/* OGT_PPCF128 */ nullptr, +/* UO_F32 */ "__unordsf2", +/* UO_F64 */ "__unorddf2", +/* UO_F128 */ "__unordtf2", +/* UO_PPCF128 */ nullptr, +/* O_F32 */ "__unordsf2", +/* O_F64 */ "__unorddf2", +/* O_F128 */ "__unordtf2", +/* O_PPCF128 */ nullptr, +/* MEMCPY */ "memcpy", +/* MEMMOVE */ "memset", +/* MEMSET */ "memmove", +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_1 */ nullptr, +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_2 */ nullptr, +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_4 */ nullptr, +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_8 */ nullptr, +/* MEMCPY_ELEMENT_UNORDERED_ATOMIC_16 */ nullptr, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_1 */ nullptr, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_2 */ nullptr, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_4 */ nullptr, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_8 */ nullptr, +/* MEMMOVE_ELEMENT_UNORDERED_ATOMIC_16 */ nullptr, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_1 */ nullptr, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_2 */ nullptr, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_4 */ nullptr, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_8 */ nullptr, +/* MEMSET_ELEMENT_UNORDERED_ATOMIC_16 */ nullptr, +/* UNWIND_RESUME */ "_Unwind_Resume", +/* SYNC_VAL_COMPARE_AND_SWAP_1 */ "__sync_val_compare_and_swap_1", +/* SYNC_VAL_COMPARE_AND_SWAP_2 */ "__sync_val_compare_and_swap_2", +/* SYNC_VAL_COMPARE_AND_SWAP_4 */ "__sync_val_compare_and_swap_4", +/* SYNC_VAL_COMPARE_AND_SWAP_8 */ "__sync_val_compare_and_swap_8", +/* SYNC_VAL_COMPARE_AND_SWAP_16 */ "__sync_val_compare_and_swap_16", +/* SYNC_LOCK_TEST_AND_SET_1 */ "__sync_lock_test_and_set_1", +/* SYNC_LOCK_TEST_AND_SET_2 */ "__sync_lock_test_and_set_2", +/* SYNC_LOCK_TEST_AND_SET_4 */ "__sync_lock_test_and_set_4", +/* SYNC_LOCK_TEST_AND_SET_8 */ "__sync_lock_test_and_set_8", +/* SYNC_LOCK_TEST_AND_SET_16 */ "__sync_lock_test_and_set_16", +/* SYNC_FETCH_AND_ADD_1 */ "__sync_fetch_and_add_1", +/* SYNC_FETCH_AND_ADD_2 */ "__sync_fetch_and_add_2", +/* SYNC_FETCH_AND_ADD_4 */ "__sync_fetch_and_add_4", +/* SYNC_FETCH_AND_ADD_8 */ "__sync_fetch_and_add_8", +/* SYNC_FETCH_AND_ADD_16 */ "__sync_fetch_and_add_16", +/* SYNC_FETCH_AND_SUB_1 */ "__sync_fetch_and_sub_1", +/* SYNC_FETCH_AND_SUB_2 */ "__sync_fetch_and_sub_2", +/* SYNC_FETCH_AND_SUB_4 */ "__sync_fetch_and_sub_4", +/* SYNC_FETCH_AND_SUB_8 */ "__sync_fetch_and_sub_8", +/* SYNC_FETCH_AND_SUB_16 */ "__sync_fetch_and_sub_16", +/* SYNC_FETCH_AND_AND_1 */ "__sync_fetch_and_and_1", +/* SYNC_FETCH_AND_AND_2 */ "__sync_fetch_and_and_2", +/* SYNC_FETCH_AND_AND_4 */ "__sync_fetch_and_and_4", +/* SYNC_FETCH_AND_AND_8 */ "__sync_fetch_and_and_8", +/* SYNC_FETCH_AND_AND_16 */ "__sync_fetch_and_and_16", +/* SYNC_FETCH_AND_OR_1 */ "__sync_fetch_and_or_1", +/* SYNC_FETCH_AND_OR_2 */ "__sync_fetch_and_or_2", +/* SYNC_FETCH_AND_OR_4 */ "__sync_fetch_and_or_4", +/* SYNC_FETCH_AND_OR_8 */ "__sync_fetch_and_or_8", +/* SYNC_FETCH_AND_OR_16 */ "__sync_fetch_and_or_16", +/* SYNC_FETCH_AND_XOR_1 */ "__sync_fetch_and_xor_1", +/* SYNC_FETCH_AND_XOR_2 */ "__sync_fetch_and_xor_2", +/* SYNC_FETCH_AND_XOR_4 */ "__sync_fetch_and_xor_4", +/* SYNC_FETCH_AND_XOR_8 */ "__sync_fetch_and_xor_8", +/* SYNC_FETCH_AND_XOR_16 */ "__sync_fetch_and_xor_16", +/* SYNC_FETCH_AND_NAND_1 */ "__sync_fetch_and_nand_1", +/* SYNC_FETCH_AND_NAND_2 */ "__sync_fetch_and_nand_2", +/* SYNC_FETCH_AND_NAND_4 */ "__sync_fetch_and_nand_4", +/* SYNC_FETCH_AND_NAND_8 */ "__sync_fetch_and_nand_8", +/* SYNC_FETCH_AND_NAND_16 */ "__sync_fetch_and_nand_16", +/* SYNC_FETCH_AND_MAX_1 */ "__sync_fetch_and_max_1", +/* SYNC_FETCH_AND_MAX_2 */ "__sync_fetch_and_max_2", +/* SYNC_FETCH_AND_MAX_4 */ "__sync_fetch_and_max_4", +/* SYNC_FETCH_AND_MAX_8 */ "__sync_fetch_and_max_8", +/* SYNC_FETCH_AND_MAX_16 */ "__sync_fetch_and_max_16", +/* SYNC_FETCH_AND_UMAX_1 */ "__sync_fetch_and_umax_1", +/* SYNC_FETCH_AND_UMAX_2 */ "__sync_fetch_and_umax_2", +/* SYNC_FETCH_AND_UMAX_4 */ "__sync_fetch_and_umax_4", +/* SYNC_FETCH_AND_UMAX_8 */ "__sync_fetch_and_umax_8", +/* SYNC_FETCH_AND_UMAX_16 */ "__sync_fetch_and_umax_16", +/* SYNC_FETCH_AND_MIN_1 */ "__sync_fetch_and_min_1", +/* SYNC_FETCH_AND_MIN_2 */ "__sync_fetch_and_min_2", +/* SYNC_FETCH_AND_MIN_4 */ "__sync_fetch_and_min_4", +/* SYNC_FETCH_AND_MIN_8 */ "__sync_fetch_and_min_8", +/* SYNC_FETCH_AND_MIN_16 */ "__sync_fetch_and_min_16", +/* SYNC_FETCH_AND_UMIN_1 */ "__sync_fetch_and_umin_1", +/* SYNC_FETCH_AND_UMIN_2 */ "__sync_fetch_and_umin_2", +/* SYNC_FETCH_AND_UMIN_4 */ "__sync_fetch_and_umin_4", +/* SYNC_FETCH_AND_UMIN_8 */ "__sync_fetch_and_umin_8", +/* SYNC_FETCH_AND_UMIN_16 */ "__sync_fetch_and_umin_16", + +/* ATOMIC_LOAD */ "__atomic_load", +/* ATOMIC_LOAD_1 */ "__atomic_load_1", +/* ATOMIC_LOAD_2 */ "__atomic_load_2", +/* ATOMIC_LOAD_4 */ "__atomic_load_4", +/* ATOMIC_LOAD_8 */ "__atomic_load_8", +/* ATOMIC_LOAD_16 */ "__atomic_load_16", + +/* ATOMIC_STORE */ "__atomic_store", +/* ATOMIC_STORE_1 */ "__atomic_store_1", +/* ATOMIC_STORE_2 */ "__atomic_store_2", +/* ATOMIC_STORE_4 */ "__atomic_store_4", +/* ATOMIC_STORE_8 */ "__atomic_store_8", +/* ATOMIC_STORE_16 */ "__atomic_store_16", + +/* ATOMIC_EXCHANGE */ "__atomic_exchange", +/* ATOMIC_EXCHANGE_1 */ "__atomic_exchange_1", +/* ATOMIC_EXCHANGE_2 */ "__atomic_exchange_2", +/* ATOMIC_EXCHANGE_4 */ "__atomic_exchange_4", +/* ATOMIC_EXCHANGE_8 */ "__atomic_exchange_8", +/* ATOMIC_EXCHANGE_16 */ "__atomic_exchange_16", + +/* ATOMIC_COMPARE_EXCHANGE */ "__atomic_compare_exchange", +/* ATOMIC_COMPARE_EXCHANGE_1 */ "__atomic_compare_exchange_1", +/* ATOMIC_COMPARE_EXCHANGE_2 */ "__atomic_compare_exchange_2", +/* ATOMIC_COMPARE_EXCHANGE_4 */ "__atomic_compare_exchange_4", +/* ATOMIC_COMPARE_EXCHANGE_8 */ "__atomic_compare_exchange_8", +/* ATOMIC_COMPARE_EXCHANGE_16 */ "__atomic_compare_exchange_16", + +/* ATOMIC_FETCH_ADD_1 */ "__atomic_fetch_add_1", +/* ATOMIC_FETCH_ADD_2 */ "__atomic_fetch_add_2", +/* ATOMIC_FETCH_ADD_4 */ "__atomic_fetch_add_4", +/* ATOMIC_FETCH_ADD_8 */ "__atomic_fetch_add_8", +/* ATOMIC_FETCH_ADD_16 */ "__atomic_fetch_add_16", +/* ATOMIC_FETCH_SUB_1 */ "__atomic_fetch_sub_1", +/* ATOMIC_FETCH_SUB_2 */ "__atomic_fetch_sub_2", +/* ATOMIC_FETCH_SUB_4 */ "__atomic_fetch_sub_4", +/* ATOMIC_FETCH_SUB_8 */ "__atomic_fetch_sub_8", +/* ATOMIC_FETCH_SUB_16 */ "__atomic_fetch_sub_16", +/* ATOMIC_FETCH_AND_1 */ "__atomic_fetch_and_1", +/* ATOMIC_FETCH_AND_2 */ "__atomic_fetch_and_2", +/* ATOMIC_FETCH_AND_4 */ "__atomic_fetch_and_4", +/* ATOMIC_FETCH_AND_8 */ "__atomic_fetch_and_8", +/* ATOMIC_FETCH_AND_16 */ "__atomic_fetch_and_16", +/* ATOMIC_FETCH_OR_1 */ "__atomic_fetch_or_1", +/* ATOMIC_FETCH_OR_2 */ "__atomic_fetch_or_2", +/* ATOMIC_FETCH_OR_4 */ "__atomic_fetch_or_4", +/* ATOMIC_FETCH_OR_8 */ "__atomic_fetch_or_8", +/* ATOMIC_FETCH_OR_16 */ "__atomic_fetch_or_16", +/* ATOMIC_FETCH_XOR_1 */ "__atomic_fetch_xor_1", +/* ATOMIC_FETCH_XOR_2 */ "__atomic_fetch_xor_2", +/* ATOMIC_FETCH_XOR_4 */ "__atomic_fetch_xor_4", +/* ATOMIC_FETCH_XOR_8 */ "__atomic_fetch_xor_8", +/* ATOMIC_FETCH_XOR_16 */ "__atomic_fetch_xor_16", +/* ATOMIC_FETCH_NAND_1 */ "__atomic_fetch_nand_1", +/* ATOMIC_FETCH_NAND_2 */ "__atomic_fetch_nand_2", +/* ATOMIC_FETCH_NAND_4 */ "__atomic_fetch_nand_4", +/* ATOMIC_FETCH_NAND_8 */ "__atomic_fetch_nand_8", +/* ATOMIC_FETCH_NAND_16 */ "__atomic_fetch_nand_16", + +/* STACKPROTECTOR_CHECK_FAIL */ "__stack_chk_fail", + +/* DEOPTIMIZE */ "__llvm_deoptimize", +}; + +void llvm::GetSignature(const WebAssemblySubtarget &Subtarget, + RTLIB::Libcall LC, SmallVectorImpl<wasm::ValType> &Rets, + SmallVectorImpl<wasm::ValType> &Params) { + assert(Rets.empty()); + assert(Params.empty()); + + WebAssembly::ExprType iPTR = Subtarget.hasAddr64() ? + WebAssembly::ExprType::I64 : + WebAssembly::ExprType::I32; + + switch (RuntimeLibcallSignatures[LC]) { + case func: + break; + case f32_func_f32: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F32); + break; + case f32_func_f64: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F64); + break; + case f32_func_i32: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::I32); + break; + case f32_func_i64: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::I64); + break; + case f32_func_i16: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::I32); + break; + case f64_func_f32: + Rets.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F32); + break; + case f64_func_f64: + Rets.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F64); + break; + case f64_func_i32: + Rets.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::I32); + break; + case f64_func_i64: + Rets.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::I64); + break; + case i32_func_f32: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::F32); + break; + case i32_func_f64: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::F64); + break; + case i32_func_i32: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + break; + case i64_func_f32: + Rets.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::F32); + break; + case i64_func_f64: + Rets.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::F64); + break; + case i64_func_i64: + Rets.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case f32_func_f32_f32: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F32); + break; + case f32_func_f32_i32: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::I32); + break; + case f32_func_i64_i64: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case f64_func_f64_f64: + Rets.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F64); + break; + case f64_func_f64_i32: + Rets.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::I32); + break; + case f64_func_i64_i64: + Rets.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case i16_func_f32: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::F32); + break; + case i8_func_i8_i8: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + break; + case func_f32_iPTR_iPTR: + Params.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType(iPTR)); + break; + case func_f64_iPTR_iPTR: + Params.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType(iPTR)); + break; + case i16_func_i16_i16: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + break; + case i32_func_f32_f32: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F32); + break; + case i32_func_f64_f64: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F64); + break; + case i32_func_i32_i32: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + break; + case i64_func_i64_i64: + Rets.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case i64_i64_func_f32: +#if 0 // TODO: Enable this when wasm gets multiple-return-value support. + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); +#else + Params.push_back(wasm::ValType(iPTR)); +#endif + Params.push_back(wasm::ValType::F32); + break; + case i64_i64_func_f64: +#if 0 // TODO: Enable this when wasm gets multiple-return-value support. + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); +#else + Params.push_back(wasm::ValType(iPTR)); +#endif + Params.push_back(wasm::ValType::F64); + break; + case i16_i16_func_i16_i16: +#if 0 // TODO: Enable this when wasm gets multiple-return-value support. + Rets.push_back(wasm::ValType::I32); + Rets.push_back(wasm::ValType::I32); +#else + Params.push_back(wasm::ValType(iPTR)); +#endif + Params.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + break; + case i32_i32_func_i32_i32: +#if 0 // TODO: Enable this when wasm gets multiple-return-value support. + Rets.push_back(wasm::ValType::I32); + Rets.push_back(wasm::ValType::I32); +#else + Params.push_back(wasm::ValType(iPTR)); +#endif + Params.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I32); + break; + case i64_i64_func_i64_i64: +#if 0 // TODO: Enable this when wasm gets multiple-return-value support. + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); +#else + Params.push_back(wasm::ValType(iPTR)); +#endif + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case i64_i64_func_i64_i64_i64_i64: +#if 0 // TODO: Enable this when wasm gets multiple-return-value support. + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); +#else + Params.push_back(wasm::ValType(iPTR)); +#endif + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case i64_i64_i64_i64_func_i64_i64_i64_i64: +#if 0 // TODO: Enable this when wasm gets multiple-return-value support. + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); +#else + Params.push_back(wasm::ValType(iPTR)); +#endif + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case i64_i64_func_i64_i64_i32: +#if 0 // TODO: Enable this when wasm gets multiple-return-value support. + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); + Rets.push_back(wasm::ValType::I64); +#else + Params.push_back(wasm::ValType(iPTR)); +#endif + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I32); + break; + case iPTR_func_iPTR_i32_iPTR: + Rets.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType(iPTR)); + break; + case iPTR_func_iPTR_iPTR_iPTR: + Rets.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType(iPTR)); + break; + case f32_func_f32_f32_f32: + Rets.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F32); + Params.push_back(wasm::ValType::F32); + break; + case f64_func_f64_f64_f64: + Rets.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F64); + Params.push_back(wasm::ValType::F64); + break; + case func_i64_i64_iPTR_iPTR: + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType(iPTR)); + break; + case func_iPTR_f32: + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType::F32); + break; + case func_iPTR_f64: + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType::F64); + break; + case func_iPTR_i32: + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType::I32); + break; + case func_iPTR_i64: + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType::I64); + break; + case func_iPTR_i64_i64: + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case func_iPTR_i64_i64_i64_i64: + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case func_iPTR_i64_i64_i64_i64_i64_i64: + Params.push_back(wasm::ValType(iPTR)); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case i32_func_i64_i64: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case i32_func_i64_i64_i64_i64: + Rets.push_back(wasm::ValType::I32); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + Params.push_back(wasm::ValType::I64); + break; + case unsupported: + llvm_unreachable("unsupported runtime library signature"); + } +} + +void llvm::GetSignature(const WebAssemblySubtarget &Subtarget, const char *Name, + SmallVectorImpl<wasm::ValType> &Rets, + SmallVectorImpl<wasm::ValType> &Params) { + assert(strcmp(RuntimeLibcallNames[RTLIB::DEOPTIMIZE], "__llvm_deoptimize") == + 0); + + for (size_t i = 0, e = RTLIB::UNKNOWN_LIBCALL; i < e; ++i) + if (RuntimeLibcallNames[i] && strcmp(RuntimeLibcallNames[i], Name) == 0) + return GetSignature(Subtarget, RTLIB::Libcall(i), Rets, Params); + + llvm_unreachable("unexpected runtime library name"); +} diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.h new file mode 100644 index 0000000..1290676 --- /dev/null +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyRuntimeLibcallSignatures.h @@ -0,0 +1,37 @@ +// CodeGen/RuntimeLibcallSignatures.h - R.T. Lib. Call Signatures -*- 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 signature information for runtime libcalls. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_WEBASSEMBLY_RUNTIME_LIBCALL_SIGNATURES_H +#define LLVM_LIB_TARGET_WEBASSEMBLY_RUNTIME_LIBCALL_SIGNATURES_H + +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "llvm/ADT/SmallVector.h" +#include "llvm/CodeGen/RuntimeLibcalls.h" + +namespace llvm { + +class WebAssemblySubtarget; + +extern void GetSignature(const WebAssemblySubtarget &Subtarget, + RTLIB::Libcall LC, + SmallVectorImpl<wasm::ValType> &Rets, + SmallVectorImpl<wasm::ValType> &Params); + +extern void GetSignature(const WebAssemblySubtarget &Subtarget, + const char *Name, SmallVectorImpl<wasm::ValType> &Rets, + SmallVectorImpl<wasm::ValType> &Params); + +} // end namespace llvm + +#endif diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp index 2441ead..b1385f4 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblySetP2AlignOperands.cpp @@ -12,8 +12,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "llvm/CodeGen/MachineBlockFrequencyInfo.h" #include "llvm/CodeGen/MachineMemOperand.h" diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp index 34ec6f2..8173364 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyStoreResults.cpp @@ -24,8 +24,8 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" #include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyMachineFunctionInfo.h" #include "WebAssemblySubtarget.h" #include "llvm/Analysis/TargetLibraryInfo.h" @@ -154,7 +154,7 @@ static bool optimizeCall(MachineBasicBlock &MBB, MachineInstr &MI, if (!callReturnsInput) return false; - LibFunc::Func Func; + LibFunc Func; if (!LibInfo.getLibFunc(Name, Func)) return false; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp index f5ef35a..7b05f67 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp @@ -12,9 +12,9 @@ /// //===----------------------------------------------------------------------===// -#include "WebAssembly.h" -#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" #include "WebAssemblyTargetMachine.h" +#include "MCTargetDesc/WebAssemblyMCTargetDesc.h" +#include "WebAssembly.h" #include "WebAssemblyTargetObjectFile.h" #include "WebAssemblyTargetTransformInfo.h" #include "llvm/CodeGen/MachineFunctionPass.h" @@ -74,13 +74,25 @@ WebAssemblyTargetMachine::WebAssemblyTargetMachine( : "e-m:e-p:32:32-i64:64-n32:64-S128", TT, CPU, FS, Options, getEffectiveRelocModel(RM), CM, OL), - TLOF(make_unique<WebAssemblyTargetObjectFile>()) { + TLOF(TT.isOSBinFormatELF() ? + static_cast<TargetLoweringObjectFile*>( + new WebAssemblyTargetObjectFileELF()) : + static_cast<TargetLoweringObjectFile*>( + new WebAssemblyTargetObjectFile())) { // WebAssembly type-checks instructions, but a noreturn function with a return // type that doesn't match the context will cause a check failure. So we lower // LLVM 'unreachable' to ISD::TRAP and then lower that to WebAssembly's // '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 @@ -117,7 +129,7 @@ namespace { /// WebAssembly Code Generator Pass Configuration Options. class WebAssemblyPassConfig final : public TargetPassConfig { public: - WebAssemblyPassConfig(WebAssemblyTargetMachine *TM, PassManagerBase &PM) + WebAssemblyPassConfig(WebAssemblyTargetMachine &TM, PassManagerBase &PM) : TargetPassConfig(TM, PM) {} WebAssemblyTargetMachine &getWebAssemblyTargetMachine() const { @@ -142,7 +154,7 @@ TargetIRAnalysis WebAssemblyTargetMachine::getTargetIRAnalysis() { TargetPassConfig * WebAssemblyTargetMachine::createPassConfig(PassManagerBase &PM) { - return new WebAssemblyPassConfig(this, PM); + return new WebAssemblyPassConfig(*this, PM); } FunctionPass *WebAssemblyPassConfig::createTargetRegisterAllocator(bool) { @@ -161,7 +173,7 @@ void WebAssemblyPassConfig::addIRPasses() { else // Expand some atomic operations. WebAssemblyTargetLowering has hooks which // control specifically what gets lowered. - addPass(createAtomicExpandPass(TM)); + addPass(createAtomicExpandPass()); // Fix function bitcasts, as WebAssembly requires caller and callee signatures // to match. @@ -260,13 +272,19 @@ 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()); + // Sort the blocks of the CFG into topological order, a prerequisite for + // BLOCK and LOOP markers. + addPass(createWebAssemblyCFGSort()); - // Put the CFG in structured form; insert BLOCK and LOOP markers. + // Insert BLOCK and LOOP markers. addPass(createWebAssemblyCFGStackify()); // Lower br_unless into br_if. diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetObjectFile.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetObjectFile.cpp index 74e33b9..b1fd108 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetObjectFile.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetObjectFile.cpp @@ -17,8 +17,14 @@ #include "WebAssemblyTargetMachine.h" using namespace llvm; -void WebAssemblyTargetObjectFile::Initialize(MCContext &Ctx, - const TargetMachine &TM) { +void WebAssemblyTargetObjectFileELF::Initialize(MCContext &Ctx, + const TargetMachine &TM) { TargetLoweringObjectFileELF::Initialize(Ctx, TM); InitializeELF(TM.Options.UseInitArray); } + +void WebAssemblyTargetObjectFile::Initialize(MCContext &Ctx, + const TargetMachine &TM) { + TargetLoweringObjectFileWasm::Initialize(Ctx, TM); + InitializeWasm(); +} diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetObjectFile.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetObjectFile.h index 39e50c9..ace87c9 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetObjectFile.h +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetObjectFile.h @@ -20,7 +20,13 @@ namespace llvm { -class WebAssemblyTargetObjectFile final : public TargetLoweringObjectFileELF { +class WebAssemblyTargetObjectFileELF final + : public TargetLoweringObjectFileELF { +public: + void Initialize(MCContext &Ctx, const TargetMachine &TM) override; +}; + +class WebAssemblyTargetObjectFile final : public TargetLoweringObjectFileWasm { public: void Initialize(MCContext &Ctx, const TargetMachine &TM) override; }; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp index 47aadf9..b3ce4bd 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.cpp @@ -36,7 +36,7 @@ unsigned WebAssemblyTTIImpl::getNumberOfRegisters(bool Vector) { return Result; } -unsigned WebAssemblyTTIImpl::getRegisterBitWidth(bool Vector) { +unsigned WebAssemblyTTIImpl::getRegisterBitWidth(bool Vector) const { if (Vector && getST()->hasSIMD128()) return 128; diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h index f658609..7b35fc9 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyTargetTransformInfo.h @@ -55,7 +55,7 @@ public: /// @{ unsigned getNumberOfRegisters(bool Vector); - unsigned getRegisterBitWidth(bool Vector); + unsigned getRegisterBitWidth(bool Vector) const; unsigned getArithmeticInstrCost( unsigned Opcode, Type *Ty, TTI::OperandValueKind Opd1Info = TTI::OK_AnyValue, diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp index a0049c1..e32772d 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.cpp @@ -15,6 +15,7 @@ #include "WebAssemblyUtilities.h" #include "WebAssemblyMachineFunctionInfo.h" #include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineLoopInfo.h" using namespace llvm; bool WebAssembly::isArgument(const MachineInstr &MI) { @@ -69,3 +70,28 @@ 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; + } +} + +MachineBasicBlock *llvm::LoopBottom(const MachineLoop *Loop) { + MachineBasicBlock *Bottom = Loop->getHeader(); + for (MachineBasicBlock *MBB : Loop->blocks()) + if (MBB->getNumber() > Bottom->getNumber()) + Bottom = MBB; + return Bottom; +} diff --git a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h index eb11440..595491f 100644 --- a/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h +++ b/contrib/llvm/lib/Target/WebAssembly/WebAssemblyUtilities.h @@ -18,7 +18,9 @@ namespace llvm { +class MachineBasicBlock; class MachineInstr; +class MachineLoop; class WebAssemblyFunctionInfo; namespace WebAssembly { @@ -27,8 +29,15 @@ 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 + +/// Return the "bottom" block of a loop. This differs from +/// MachineLoop::getBottomBlock in that it works even if the loop is +/// discontiguous. +MachineBasicBlock *LoopBottom(const MachineLoop *Loop); + } // end namespace llvm #endif diff --git a/contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt b/contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt index 8dd5e8a..35a6713 100644 --- a/contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt +++ b/contrib/llvm/lib/Target/WebAssembly/known_gcc_test_failures.txt @@ -1,5 +1,15 @@ # Tests which are known to fail from the GCC torture test suite. +# Syntax: Each line has a single test to be marked as a 'known failure' (or +# 'exclusion'. Known failures are expected to fail, and will cause an error if +# they pass. (Known failures that do not run at all will not cause an +# error). The format is +# <name> <attributes> # comment +# +# The attributes in this case represent the different arguments used to +# compiler: 'wasm-s' is for compiling to .s files, and 'wasm-o' for compiling +# to wasm object files (.o). + # Computed gotos are not supported (Cannot select BlockAddress/BRIND) 20040302-1.c 20071210-1.c @@ -23,9 +33,6 @@ built-in-setjmp.c pr60003.c # Error in the program / unsupported by Clang. -scal-to-vec1.c -scal-to-vec2.c -scal-to-vec3.c 20000822-1.c 20010209-1.c 20010605-1.c @@ -66,3 +73,18 @@ pr41935.c 920728-1.c pr28865.c widechar-2.c + +# crash: Running pass 'WebAssembly Explicit Locals' on function +20020107-1.c wasm-o +20030222-1.c wasm-o +20071220-1.c wasm-o +20071220-2.c wasm-o +990130-1.c wasm-o +pr38533.c wasm-o +pr41239.c wasm-o +pr43385.c wasm-o +pr43560.c wasm-o +pr45695.c wasm-o +pr49279.c wasm-o +pr49390.c wasm-o +pr52286.c wasm-o |