[llvm] r296190 - [WebAssembly] Basic support for Wasm object file encoding.

Dan Gohman via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 24 15:18:01 PST 2017


Author: djg
Date: Fri Feb 24 17:18:00 2017
New Revision: 296190

URL: http://llvm.org/viewvc/llvm-project?rev=296190&view=rev
Log:
[WebAssembly] Basic support for Wasm object file encoding.

With the "wasm32-unknown-unknown-wasm" triple, this allows writing out
simple wasm object files, and is another step in a larger series toward
migrating from ELF to general wasm object support. Note that this code
and the binary format itself is still experimental.

Added:
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
Modified:
    llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
    llvm/trunk/include/llvm/MC/MCExpr.h
    llvm/trunk/include/llvm/MC/MCSectionWasm.h
    llvm/trunk/include/llvm/MC/MCSymbolWasm.h
    llvm/trunk/include/llvm/MC/MCWasmObjectWriter.h
    llvm/trunk/include/llvm/MC/MCWasmStreamer.h
    llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
    llvm/trunk/lib/MC/MCExpr.cpp
    llvm/trunk/lib/MC/MCObjectFileInfo.cpp
    llvm/trunk/lib/MC/MCWasmStreamer.cpp
    llvm/trunk/lib/MC/WasmObjectWriter.cpp
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
    llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrCall.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.h
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
    llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h
    llvm/trunk/test/CodeGen/WebAssembly/call.ll
    llvm/trunk/test/CodeGen/WebAssembly/cfi.ll
    llvm/trunk/test/CodeGen/WebAssembly/comparisons_f32.ll
    llvm/trunk/test/CodeGen/WebAssembly/comparisons_f64.ll
    llvm/trunk/test/CodeGen/WebAssembly/comparisons_i32.ll
    llvm/trunk/test/CodeGen/WebAssembly/comparisons_i64.ll
    llvm/trunk/test/CodeGen/WebAssembly/copysign-casts.ll
    llvm/trunk/test/CodeGen/WebAssembly/dbgvalue.ll
    llvm/trunk/test/CodeGen/WebAssembly/dead-vreg.ll
    llvm/trunk/test/CodeGen/WebAssembly/divrem-constant.ll
    llvm/trunk/test/CodeGen/WebAssembly/f32.ll
    llvm/trunk/test/CodeGen/WebAssembly/f64.ll
    llvm/trunk/test/CodeGen/WebAssembly/fast-isel-noreg.ll
    llvm/trunk/test/CodeGen/WebAssembly/globl.ll
    llvm/trunk/test/CodeGen/WebAssembly/i128.ll
    llvm/trunk/test/CodeGen/WebAssembly/i32.ll
    llvm/trunk/test/CodeGen/WebAssembly/i64.ll
    llvm/trunk/test/CodeGen/WebAssembly/ident.ll
    llvm/trunk/test/CodeGen/WebAssembly/immediates.ll
    llvm/trunk/test/CodeGen/WebAssembly/implicit-def.ll
    llvm/trunk/test/CodeGen/WebAssembly/load.ll
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll
    llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll
    llvm/trunk/test/CodeGen/WebAssembly/non-executable-stack.ll
    llvm/trunk/test/CodeGen/WebAssembly/offset-folding.ll
    llvm/trunk/test/CodeGen/WebAssembly/store.ll
    llvm/trunk/test/CodeGen/WebAssembly/switch.ll
    llvm/trunk/test/CodeGen/WebAssembly/unreachable.ll

Modified: llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h (original)
+++ llvm/trunk/include/llvm/CodeGen/TargetLoweringObjectFileImpl.h Fri Feb 24 17:18:00 2017
@@ -172,6 +172,8 @@ public:
 };
 
 class TargetLoweringObjectFileWasm : public TargetLoweringObjectFile {
+  mutable unsigned NextUniqueID = 0;
+
 public:
   TargetLoweringObjectFileWasm() {}
 

Modified: llvm/trunk/include/llvm/MC/MCExpr.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCExpr.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCExpr.h (original)
+++ llvm/trunk/include/llvm/MC/MCExpr.h Fri Feb 24 17:18:00 2017
@@ -270,6 +270,7 @@ public:
     VK_Hexagon_IE_GOT,
 
     VK_WebAssembly_FUNCTION, // Function table index, rather than virtual addr
+    VK_WebAssembly_TYPEINDEX,// Type table index
 
     VK_AMDGPU_GOTPCREL32_LO, // symbol at gotpcrel32@lo
     VK_AMDGPU_GOTPCREL32_HI, // symbol at gotpcrel32@hi

Modified: llvm/trunk/include/llvm/MC/MCSectionWasm.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSectionWasm.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCSectionWasm.h (original)
+++ llvm/trunk/include/llvm/MC/MCSectionWasm.h Fri Feb 24 17:18:00 2017
@@ -40,12 +40,15 @@ class MCSectionWasm final : public MCSec
 
   const MCSymbolWasm *Group;
 
+  // The offset of the MC function section in the wasm code section.
+  uint64_t SectionOffset;
+
 private:
   friend class MCContext;
   MCSectionWasm(StringRef Section, unsigned type, unsigned flags, SectionKind K,
                 const MCSymbolWasm *group, unsigned UniqueID, MCSymbol *Begin)
       : MCSection(SV_Wasm, K, Begin), SectionName(Section), Type(type),
-        Flags(flags), UniqueID(UniqueID), Group(group) {
+        Flags(flags), UniqueID(UniqueID), Group(group), SectionOffset(0) {
   }
 
   void setSectionName(StringRef Name) { SectionName = Name; }
@@ -72,6 +75,9 @@ public:
   bool isUnique() const { return UniqueID != ~0U; }
   unsigned getUniqueID() const { return UniqueID; }
 
+  uint64_t getSectionOffset() const { return SectionOffset; }
+  void setSectionOffset(uint64_t Offset) { SectionOffset = Offset; }
+
   static bool classof(const MCSection *S) { return S->getVariant() == SV_Wasm; }
 };
 

Modified: llvm/trunk/include/llvm/MC/MCSymbolWasm.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCSymbolWasm.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCSymbolWasm.h (original)
+++ llvm/trunk/include/llvm/MC/MCSymbolWasm.h Fri Feb 24 17:18:00 2017
@@ -13,11 +13,41 @@
 
 namespace llvm {
 class MCSymbolWasm : public MCSymbol {
+private:
+  bool IsFunction = false;
+  std::string ModuleName;
+  SmallVector<unsigned, 1> Returns;
+  SmallVector<unsigned, 4> Params;
+
+  /// An expression describing how to calculate the size of a symbol. If a
+  /// symbol has no size this field will be NULL.
+  const MCExpr *SymbolSize = nullptr;
+
 public:
+  // Use a module name of "env" for now, for compatibility with existing tools.
+  // This is temporary, and may change, as the ABI is not yet stable.
   MCSymbolWasm(const StringMapEntry<bool> *Name, bool isTemporary)
-      : MCSymbol(SymbolKindWasm, Name, isTemporary) {}
-
+      : MCSymbol(SymbolKindWasm, Name, isTemporary),
+        ModuleName("env") {}
   static bool classof(const MCSymbol *S) { return S->isWasm(); }
+
+  const MCExpr *getSize() const { return SymbolSize; }
+  void setSize(const MCExpr *SS) { SymbolSize = SS; }
+
+  bool isFunction() const { return IsFunction; }
+  void setIsFunction(bool isFunc) { IsFunction = isFunc; }
+
+  const StringRef getModuleName() const { return ModuleName; }
+
+  const SmallVector<unsigned, 1> &getReturns() const { return Returns; }
+  void setReturns(SmallVectorImpl<unsigned> &&Rets) {
+    Returns = std::move(Rets);
+  }
+
+  const SmallVector<unsigned, 4> &getParams() const { return Params; }
+  void setParams(SmallVectorImpl<unsigned> &&Pars) {
+    Params = std::move(Pars);
+  }
 };
 }
 

Modified: llvm/trunk/include/llvm/MC/MCWasmObjectWriter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCWasmObjectWriter.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCWasmObjectWriter.h (original)
+++ llvm/trunk/include/llvm/MC/MCWasmObjectWriter.h Fri Feb 24 17:18:00 2017
@@ -22,22 +22,29 @@ class MCContext;
 class MCFixup;
 class MCFragment;
 class MCObjectWriter;
+class MCSectionWasm;
 class MCSymbol;
 class MCSymbolWasm;
 class MCValue;
 class raw_pwrite_stream;
 
+// Information about a single relocation.
 struct WasmRelocationEntry {
   uint64_t Offset;            // Where is the relocation.
   const MCSymbolWasm *Symbol; // The symbol to relocate with.
+  uint64_t Addend;            // A value to add to the symbol.
   unsigned Type;              // The type of the relocation.
+  MCSectionWasm *FixupSection;// The section the relocation is targeting.
 
   WasmRelocationEntry(uint64_t Offset, const MCSymbolWasm *Symbol,
-                      unsigned Type)
-      : Offset(Offset), Symbol(Symbol), Type(Type) {}
+                      uint64_t Addend, unsigned Type,
+                      MCSectionWasm *FixupSection)
+      : Offset(Offset), Symbol(Symbol), Addend(Addend), Type(Type),
+        FixupSection(FixupSection) {}
 
   void print(raw_ostream &Out) const {
-    Out << "Off=" << Offset << ", Sym=" << Symbol << ", Type=" << Type;
+    Out << "Off=" << Offset << ", Sym=" << Symbol << ", Addend=" << Addend
+        << ", Type=" << Type << ", FixupSection=" << FixupSection;
   }
   void dump() const { print(errs()); }
 };

Modified: llvm/trunk/include/llvm/MC/MCWasmStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/MC/MCWasmStreamer.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/include/llvm/MC/MCWasmStreamer.h (original)
+++ llvm/trunk/include/llvm/MC/MCWasmStreamer.h Fri Feb 24 17:18:00 2017
@@ -54,6 +54,8 @@ public:
   void EmitCOFFSymbolType(int Type) override;
   void EndCOFFSymbolDef() override;
 
+  void emitELFSize(MCSymbol *Symbol, const MCExpr *Value) override;
+
   void EmitLocalCommonSymbol(MCSymbol *Symbol, uint64_t Size,
                              unsigned ByteAlignment) override;
 

Modified: llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp (original)
+++ llvm/trunk/lib/CodeGen/TargetLoweringObjectFileImpl.cpp Fri Feb 24 17:18:00 2017
@@ -1162,18 +1162,73 @@ void TargetLoweringObjectFileCOFF::emitL
 //                                  Wasm
 //===----------------------------------------------------------------------===//
 
+static const Comdat *getWasmComdat(const GlobalValue *GV) {
+  const Comdat *C = GV->getComdat();
+  if (!C)
+    return nullptr;
+
+  if (C->getSelectionKind() != Comdat::Any)
+    report_fatal_error("Wasm COMDATs only support SelectionKind::Any, '" +
+                       C->getName() + "' cannot be lowered.");
+
+  return C;
+}
+
 MCSection *TargetLoweringObjectFileWasm::getExplicitSectionGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
   llvm_unreachable("getExplicitSectionGlobal not yet implemented");
   return nullptr;
 }
 
+static MCSectionWasm *
+selectWasmSectionForGlobal(MCContext &Ctx, const GlobalObject *GO,
+                           SectionKind Kind, Mangler &Mang,
+                           const TargetMachine &TM, bool EmitUniqueSection,
+                           unsigned Flags, unsigned *NextUniqueID) {
+  StringRef Group = "";
+  if (getWasmComdat(GO))
+    llvm_unreachable("comdat not yet supported for wasm");
+
+  bool UniqueSectionNames = TM.getUniqueSectionNames();
+  SmallString<128> Name = getSectionPrefixForGlobal(Kind);
+
+  if (const auto *F = dyn_cast<Function>(GO)) {
+    const auto &OptionalPrefix = F->getSectionPrefix();
+    if (OptionalPrefix)
+      Name += *OptionalPrefix;
+  }
+
+  if (EmitUniqueSection && UniqueSectionNames) {
+    Name.push_back('.');
+    TM.getNameWithPrefix(Name, GO, Mang, true);
+  }
+  unsigned UniqueID = MCContext::GenericSectionID;
+  if (EmitUniqueSection && !UniqueSectionNames) {
+    UniqueID = *NextUniqueID;
+    (*NextUniqueID)++;
+  }
+  return Ctx.getWasmSection(Name, /*Type=*/0, Flags,
+                            Group, UniqueID);
+}
+
 MCSection *TargetLoweringObjectFileWasm::SelectSectionForGlobal(
     const GlobalObject *GO, SectionKind Kind, const TargetMachine &TM) const {
+
+  if (Kind.isCommon())
+    report_fatal_error("mergable sections not supported yet on wasm");
+
+  // If we have -ffunction-section or -fdata-section then we should emit the
+  // global value to a uniqued section specifically for it.
+  bool EmitUniqueSection = false;
   if (Kind.isText())
-    return TextSection;
-  assert(!Kind.isMetadata() && "metadata sections not yet implemented");
-  return DataSection;
+    EmitUniqueSection = TM.getFunctionSections();
+  else
+    EmitUniqueSection = TM.getDataSections();
+  EmitUniqueSection |= GO->hasComdat();
+
+  return selectWasmSectionForGlobal(getContext(), GO, Kind, getMangler(), TM,
+                                    EmitUniqueSection, /*Flags=*/0,
+                                    &NextUniqueID);
 }
 
 bool TargetLoweringObjectFileWasm::shouldPutJumpTableInFunctionSection(

Modified: llvm/trunk/lib/MC/MCExpr.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCExpr.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCExpr.cpp (original)
+++ llvm/trunk/lib/MC/MCExpr.cpp Fri Feb 24 17:18:00 2017
@@ -286,6 +286,7 @@ StringRef MCSymbolRefExpr::getVariantKin
   case VK_Hexagon_IE: return "IE";
   case VK_Hexagon_IE_GOT: return "IEGOT";
   case VK_WebAssembly_FUNCTION: return "FUNCTION";
+  case VK_WebAssembly_TYPEINDEX: return "TYPEINDEX";
   case VK_AMDGPU_GOTPCREL32_LO: return "gotpcrel32 at lo";
   case VK_AMDGPU_GOTPCREL32_HI: return "gotpcrel32 at hi";
   case VK_AMDGPU_REL32_LO: return "rel32 at lo";

Modified: llvm/trunk/lib/MC/MCObjectFileInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCObjectFileInfo.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCObjectFileInfo.cpp (original)
+++ llvm/trunk/lib/MC/MCObjectFileInfo.cpp Fri Feb 24 17:18:00 2017
@@ -801,8 +801,8 @@ void MCObjectFileInfo::initCOFFMCObjectF
 
 void MCObjectFileInfo::initWasmMCObjectFileInfo(const Triple &T) {
   // TODO: Set the section types and flags.
-  TextSection = Ctx->getWasmSection("", 0, 0);
-  DataSection = Ctx->getWasmSection("", 0, 0);
+  TextSection = Ctx->getWasmSection(".text", 0, 0);
+  DataSection = Ctx->getWasmSection(".data", 0, 0);
 
   // TODO: Set the section types and flags.
   DwarfLineSection = Ctx->getWasmSection(".debug_line", 0, 0);

Modified: llvm/trunk/lib/MC/MCWasmStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/MCWasmStreamer.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/MC/MCWasmStreamer.cpp (original)
+++ llvm/trunk/lib/MC/MCWasmStreamer.cpp Fri Feb 24 17:18:00 2017
@@ -89,7 +89,29 @@ bool MCWasmStreamer::EmitSymbolAttribute
   // the symbol with the assembler.
   getAssembler().registerSymbol(*Symbol);
 
-  // TODO: Set the symbol binding, type, etc.
+  switch (Attribute) {
+  case MCSA_LazyReference:
+  case MCSA_Reference:
+  case MCSA_SymbolResolver:
+  case MCSA_PrivateExtern:
+  case MCSA_WeakDefinition:
+  case MCSA_WeakDefAutoPrivate:
+  case MCSA_Invalid:
+  case MCSA_IndirectSymbol:
+    return false;
+  case MCSA_Global:
+    Symbol->setExternal(true);
+    break;
+  case MCSA_ELF_TypeFunction:
+    Symbol->setIsFunction(true);
+    break;
+  case MCSA_ELF_TypeObject:
+    Symbol->setIsFunction(false);
+    break;
+  default:
+    // unrecognized directive
+    return false;
+  }
 
   return true;
 }
@@ -99,6 +121,10 @@ void MCWasmStreamer::EmitCommonSymbol(MC
   llvm_unreachable("Common symbols are not yet implemented for Wasm");
 }
 
+void MCWasmStreamer::emitELFSize(MCSymbol *Symbol, const MCExpr *Value) {
+  cast<MCSymbolWasm>(Symbol)->setSize(Value);
+}
+
 void MCWasmStreamer::EmitLocalCommonSymbol(MCSymbol *S, uint64_t Size,
                                            unsigned ByteAlignment) {
   llvm_unreachable("Local common symbols are not yet implemented for Wasm");
@@ -124,7 +150,17 @@ void MCWasmStreamer::EmitFileDirective(S
 }
 
 void MCWasmStreamer::EmitIdent(StringRef IdentString) {
-  llvm_unreachable("Ident sections not yet implemented for wasm");
+  MCSection *Comment = getAssembler().getContext().getWasmSection(
+      ".comment", 0, 0);
+  PushSection();
+  SwitchSection(Comment);
+  if (!SeenIdent) {
+    EmitIntValue(0, 1);
+    SeenIdent = true;
+  }
+  EmitBytes(IdentString);
+  EmitIntValue(0, 1);
+  PopSection();
 }
 
 void MCWasmStreamer::EmitInstToFragment(const MCInst &Inst,

Modified: llvm/trunk/lib/MC/WasmObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/MC/WasmObjectWriter.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/MC/WasmObjectWriter.cpp (original)
+++ llvm/trunk/lib/MC/WasmObjectWriter.cpp Fri Feb 24 17:18:00 2017
@@ -13,8 +13,6 @@
 
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/SmallPtrSet.h"
-#include "llvm/ADT/SmallString.h"
-#include "llvm/ADT/StringMap.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAsmInfo.h"
 #include "llvm/MC/MCAsmLayout.h"
@@ -28,9 +26,10 @@
 #include "llvm/MC/MCSymbolWasm.h"
 #include "llvm/MC/MCValue.h"
 #include "llvm/MC/MCWasmObjectWriter.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/Debug.h"
-#include "llvm/Support/Endian.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/LEB128.h"
 #include "llvm/Support/StringSaver.h"
 #include "llvm/Support/Wasm.h"
 #include <vector>
@@ -41,7 +40,25 @@ using namespace llvm;
 #define DEBUG_TYPE "reloc-info"
 
 namespace {
-typedef DenseMap<const MCSectionWasm *, uint32_t> SectionIndexMapTy;
+// For patching purposes, we need to remember where each section starts, both
+// for patching up the section size field, and for patching up references to
+// locations within the section.
+struct SectionBookkeeping {
+  // Where the size of the section is written.
+  uint64_t SizeOffset;
+  // Where the contents of the section starts (after the header).
+  uint64_t ContentsOffset;
+};
+
+// This record records information about a call_indirect which needs its
+// type index fixed up once we've computed type indices.
+struct TypeIndexFixup {
+  uint64_t Offset;
+  const MCSymbolWasm *Symbol;
+  const MCSectionWasm *FixupSection;
+  TypeIndexFixup(uint64_t O, const MCSymbolWasm *S, MCSectionWasm *F)
+    : Offset(O), Symbol(S), FixupSection(F) {}
+};
 
 class WasmObjectWriter : public MCObjectWriter {
   /// Helper struct for containing some precomputed information on symbols.
@@ -56,6 +73,18 @@ class WasmObjectWriter : public MCObject
   /// The target specific Wasm writer instance.
   std::unique_ptr<MCWasmObjectTargetWriter> TargetObjectWriter;
 
+  // Relocations for fixing up references in the code section.
+  std::vector<WasmRelocationEntry> CodeRelocations;
+
+  // Relocations for fixing up references in the data section.
+  std::vector<WasmRelocationEntry> DataRelocations;
+
+  // Fixups for call_indirect type indices.
+  std::vector<TypeIndexFixup> TypeIndexFixups;
+
+  // Index values to use for fixing up call_indirect type indices.
+  std::vector<uint32_t> TypeIndexFixupTypes;
+
   // TargetObjectWriter wrappers.
   bool is64Bit() const { return TargetObjectWriter->is64Bit(); }
   unsigned getRelocType(MCContext &Ctx, const MCValue &Target,
@@ -63,10 +92,15 @@ class WasmObjectWriter : public MCObject
     return TargetObjectWriter->getRelocType(Ctx, Target, Fixup, IsPCRel);
   }
 
+  void startSection(SectionBookkeeping &Section, unsigned SectionId,
+                    const char *Name = nullptr);
+  void endSection(SectionBookkeeping &Section);
+
 public:
   WasmObjectWriter(MCWasmObjectTargetWriter *MOTW, raw_pwrite_stream &OS)
       : MCObjectWriter(OS, /*IsLittleEndian=*/true), TargetObjectWriter(MOTW) {}
 
+private:
   void reset() override {
     MCObjectWriter::reset();
   }
@@ -89,6 +123,58 @@ public:
 
 WasmObjectWriter::~WasmObjectWriter() {}
 
+// Return the padding size to write a 32-bit value into a 5-byte ULEB128.
+static unsigned PaddingFor5ByteULEB128(uint32_t X) {
+  return X == 0 ? 4 : (4u - (31u - countLeadingZeros(X)) / 7u);
+}
+
+// Return the padding size to write a 32-bit value into a 5-byte SLEB128.
+static unsigned PaddingFor5ByteSLEB128(int32_t X) {
+  return 5 - getSLEB128Size(X);
+}
+
+// Write out a section header and a patchable section size field.
+void WasmObjectWriter::startSection(SectionBookkeeping &Section,
+                                    unsigned SectionId,
+                                    const char *Name) {
+  assert((Name != nullptr) == (SectionId == wasm::WASM_SEC_CUSTOM) &&
+         "Only custom sections can have names");
+
+  write8(SectionId);
+
+  Section.SizeOffset = getStream().tell();
+
+  // The section size. We don't know the size yet, so reserve enough space
+  // for any 32-bit value; we'll patch it later.
+  encodeULEB128(UINT32_MAX, getStream());
+
+  // The position where the section starts, for measuring its size.
+  Section.ContentsOffset = getStream().tell();
+
+  // Custom sections in wasm also have a string identifier.
+  if (SectionId == wasm::WASM_SEC_CUSTOM) {
+    encodeULEB128(strlen(Name), getStream());
+    writeBytes(Name);
+  }
+}
+
+// Now that the section is complete and we know how big it is, patch up the
+// section size field at the start of the section.
+void WasmObjectWriter::endSection(SectionBookkeeping &Section) {
+  uint64_t Size = getStream().tell() - Section.ContentsOffset;
+  if (uint32_t(Size) != Size)
+    report_fatal_error("section size does not fit in a uint32_t");
+
+  unsigned Padding = PaddingFor5ByteULEB128(Size);
+
+  // Write the final section size to the payload_len field, which follows
+  // the section id byte.
+  uint8_t Buffer[16];
+  unsigned SizeLen = encodeULEB128(Size, Buffer, Padding);
+  assert(SizeLen == 5);
+  getStream().pwrite((char *)Buffer, SizeLen, Section.SizeOffset);
+}
+
 // Emit the Wasm header.
 void WasmObjectWriter::writeHeader(const MCAssembler &Asm) {
   writeBytes(StringRef(wasm::WasmMagic, sizeof(wasm::WasmMagic)));
@@ -104,15 +190,823 @@ void WasmObjectWriter::recordRelocation(
                                         const MCFragment *Fragment,
                                         const MCFixup &Fixup, MCValue Target,
                                         bool &IsPCRel, uint64_t &FixedValue) {
-  // TODO: Implement
+  MCSectionWasm &FixupSection = cast<MCSectionWasm>(*Fragment->getParent());
+  uint64_t C = Target.getConstant();
+  uint64_t FixupOffset = Layout.getFragmentOffset(Fragment) + Fixup.getOffset();
+  MCContext &Ctx = Asm.getContext();
+
+  if (const MCSymbolRefExpr *RefB = Target.getSymB()) {
+    assert(RefB->getKind() == MCSymbolRefExpr::VK_None &&
+           "Should not have constructed this");
+
+    // Let A, B and C being the components of Target and R be the location of
+    // the fixup. If the fixup is not pcrel, we want to compute (A - B + C).
+    // If it is pcrel, we want to compute (A - B + C - R).
+
+    // In general, Wasm has no relocations for -B. It can only represent (A + C)
+    // or (A + C - R). If B = R + K and the relocation is not pcrel, we can
+    // replace B to implement it: (A - R - K + C)
+    if (IsPCRel) {
+      Ctx.reportError(
+          Fixup.getLoc(),
+          "No relocation available to represent this relative expression");
+      return;
+    }
+
+    const auto &SymB = cast<MCSymbolWasm>(RefB->getSymbol());
+
+    if (SymB.isUndefined()) {
+      Ctx.reportError(Fixup.getLoc(),
+                      Twine("symbol '") + SymB.getName() +
+                          "' can not be undefined in a subtraction expression");
+      return;
+    }
+
+    assert(!SymB.isAbsolute() && "Should have been folded");
+    const MCSection &SecB = SymB.getSection();
+    if (&SecB != &FixupSection) {
+      Ctx.reportError(Fixup.getLoc(),
+                      "Cannot represent a difference across sections");
+      return;
+    }
+
+    uint64_t SymBOffset = Layout.getSymbolOffset(SymB);
+    uint64_t K = SymBOffset - FixupOffset;
+    IsPCRel = true;
+    C -= K;
+  }
+
+  // We either rejected the fixup or folded B into C at this point.
+  const MCSymbolRefExpr *RefA = Target.getSymA();
+  const auto *SymA = RefA ? cast<MCSymbolWasm>(&RefA->getSymbol()) : nullptr;
+
+  bool ViaWeakRef = false;
+  if (SymA && SymA->isVariable()) {
+    const MCExpr *Expr = SymA->getVariableValue();
+    if (const auto *Inner = dyn_cast<MCSymbolRefExpr>(Expr)) {
+      if (Inner->getKind() == MCSymbolRefExpr::VK_WEAKREF) {
+        SymA = cast<MCSymbolWasm>(&Inner->getSymbol());
+        ViaWeakRef = true;
+      }
+    }
+  }
+
+  // Put any constant offset in an addend. Offsets can be negative, and
+  // LLVM expects wrapping, in contrast to wasm's immediates which can't
+  // be negative and don't wrap.
+  FixedValue = 0;
+
+  if (SymA) {
+    if (ViaWeakRef)
+      llvm_unreachable("weakref used in reloc not yet implemented");
+    else
+      SymA->setUsedInReloc();
+  }
+
+  if (RefA) {
+    if (RefA->getKind() == MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX) {
+      TypeIndexFixups.push_back(TypeIndexFixup(FixupOffset, SymA,
+                                               &FixupSection));
+      return;
+    }
+  }
+
+  unsigned Type = getRelocType(Ctx, Target, Fixup, IsPCRel);
+
+  WasmRelocationEntry Rec(FixupOffset, SymA, C, Type, &FixupSection);
+
+  if (FixupSection.hasInstructions())
+    CodeRelocations.push_back(Rec);
+  else
+    DataRelocations.push_back(Rec);
+}
+
+namespace {
+
+// 
+struct WasmFunctionType {
+  // Support empty and tombstone instances, needed by DenseMap.
+  enum { Plain, Empty, Tombstone } State;
+
+  // The return types of the function.
+  SmallVector<unsigned, 1> Returns;
+
+  // The parameter types of the function.
+  SmallVector<unsigned, 4> Params;
+
+  WasmFunctionType() : State(Plain) {}
+
+  bool operator==(const WasmFunctionType &Other) const {
+    return State == Other.State && Returns == Other.Returns &&
+           Params == Other.Params;
+  }
+};
+
+// Traits for using WasmFunctionType in a DenseMap.
+struct WasmFunctionTypeDenseMapInfo {
+  static WasmFunctionType getEmptyKey() {
+    WasmFunctionType FuncTy;
+    FuncTy.State = WasmFunctionType::Empty;
+    return FuncTy;
+  }
+  static WasmFunctionType getTombstoneKey() {
+    WasmFunctionType FuncTy;
+    FuncTy.State = WasmFunctionType::Tombstone;
+    return FuncTy;
+  }
+  static unsigned getHashValue(const WasmFunctionType &FuncTy) {
+    uintptr_t Value = FuncTy.State;
+    for (unsigned Ret : FuncTy.Returns)
+      Value += DenseMapInfo<unsigned>::getHashValue(Ret);
+    for (unsigned Param : FuncTy.Params)
+      Value += DenseMapInfo<unsigned>::getHashValue(Param);
+    return Value;
+  }
+  static bool isEqual(const WasmFunctionType &LHS,
+                      const WasmFunctionType &RHS) {
+    return LHS == RHS;
+  }
+};
+
+// A wasm import to be written into the import section.
+struct WasmImport {
+  StringRef ModuleName;
+  StringRef FieldName;
+  unsigned Kind;
+  uint32_t Type;
+};
+
+// A wasm function to be written into the function section.
+struct WasmFunction {
+  unsigned Type;
+  const MCSymbolWasm *Sym;
+};
+
+// A wasm export to be written into the export section.
+struct WasmExport {
+  StringRef FieldName;
+  unsigned Kind;
+  uint32_t Index;
+};
+
+// A wasm global to be written into the global section.
+struct WasmGlobal {
+  unsigned Type;
+  bool IsMutable;
+  uint32_t InitialValue;
+};
+
+}  // end anonymous namespace
+
+// Write X as an (unsigned) LEB value at offset Offset in Stream, padded
+// to allow patching.
+static void
+WritePatchableLEB(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
+  uint8_t Buffer[5];
+  unsigned Padding = PaddingFor5ByteULEB128(X);
+  unsigned SizeLen = encodeULEB128(X, Buffer, Padding);
+  assert(SizeLen == 5);
+  Stream.pwrite((char *)Buffer, SizeLen, Offset);
+}
+
+// Write X as an signed LEB value at offset Offset in Stream, padded
+// to allow patching.
+static void
+WritePatchableSLEB(raw_pwrite_stream &Stream, int32_t X, uint64_t Offset) {
+  uint8_t Buffer[5];
+  unsigned Padding = PaddingFor5ByteSLEB128(X);
+  unsigned SizeLen = encodeSLEB128(X, Buffer, Padding);
+  assert(SizeLen == 5);
+  Stream.pwrite((char *)Buffer, SizeLen, Offset);
+}
+
+// Write X as a plain integer value at offset Offset in Stream.
+static void WriteI32(raw_pwrite_stream &Stream, uint32_t X, uint64_t Offset) {
+  uint8_t Buffer[4];
+  support::endian::write32le(Buffer, X);
+  Stream.pwrite((char *)Buffer, sizeof(Buffer), Offset);
+}
+
+// Compute a value to write into the code at the location covered
+// by RelEntry. This value isn't used by the static linker, since
+// we have addends; it just serves to make the code more readable
+// and to make standalone wasm modules directly usable.
+static uint32_t ProvisionalValue(const WasmRelocationEntry &RelEntry) {
+  const MCSymbolWasm *Sym = RelEntry.Symbol;
+
+  // For undefined symbols, use a hopefully invalid value.
+  if (!Sym->isDefined(false))
+    return UINT32_MAX;
+
+  MCSectionWasm &Section =
+    cast<MCSectionWasm>(RelEntry.Symbol->getSection(false));
+  uint64_t Address = Section.getSectionOffset() + RelEntry.Addend;
+
+  // Ignore overflow. LLVM allows address arithmetic to silently wrap.
+  uint32_t Value = Address;
+
+  return Value;
+}
+
+// Apply the portions of the relocation records that we can handle ourselves
+// directly.
+static void ApplyRelocations(
+    ArrayRef<WasmRelocationEntry> Relocations,
+    raw_pwrite_stream &Stream,
+    DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices,
+    uint64_t ContentsOffset)
+{
+  for (const WasmRelocationEntry &RelEntry : Relocations) {
+    uint64_t Offset = ContentsOffset +
+                      RelEntry.FixupSection->getSectionOffset() +
+                      RelEntry.Offset;
+    switch (RelEntry.Type) {
+    case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB: {
+      uint32_t Index = SymbolIndices[RelEntry.Symbol];
+      assert(RelEntry.Addend == 0);
+
+      WritePatchableLEB(Stream, Index, Offset);
+      break;
+    }
+    case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB: {
+      uint32_t Index = SymbolIndices[RelEntry.Symbol];
+      assert(RelEntry.Addend == 0);
+
+      WritePatchableSLEB(Stream, Index, Offset);
+      break;
+    }
+    case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB: {
+      uint32_t Value = ProvisionalValue(RelEntry);
+
+      WritePatchableSLEB(Stream, Value, Offset);
+      break;
+    }
+    case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB: {
+      uint32_t Value = ProvisionalValue(RelEntry);
+
+      WritePatchableLEB(Stream, Value, Offset);
+      break;
+    }
+    case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32: {
+      uint32_t Index = SymbolIndices[RelEntry.Symbol];
+      assert(RelEntry.Addend == 0);
+
+      WriteI32(Stream, Index, Offset);
+      break;
+    }
+    case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32: {
+      uint32_t Value = ProvisionalValue(RelEntry);
+
+      WriteI32(Stream, Value, Offset);
+      break;
+    }
+    default:
+      break;
+    }
+  }
+}
+
+// Write out the portions of the relocation records that the linker will
+// need to handle.
+static void WriteRelocations(
+    ArrayRef<WasmRelocationEntry> Relocations,
+    raw_pwrite_stream &Stream,
+    DenseMap<const MCSymbolWasm *, uint32_t> &SymbolIndices)
+{
+  for (const WasmRelocationEntry RelEntry : Relocations) {
+    encodeULEB128(RelEntry.Type, Stream);
+
+    uint64_t Offset = RelEntry.Offset +
+                      RelEntry.FixupSection->getSectionOffset();
+    uint32_t Index = SymbolIndices[RelEntry.Symbol];
+    int64_t Addend = RelEntry.Addend;
+
+    switch (RelEntry.Type) {
+    case wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB:
+    case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+    case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
+      encodeULEB128(Offset, Stream);
+      encodeULEB128(Index, Stream);
+      assert(Addend == 0 && "addends not supported for functions");
+      break;
+    case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB:
+    case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
+    case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
+      encodeULEB128(Offset, Stream);
+      encodeULEB128(Index, Stream);
+      encodeSLEB128(Addend, Stream);
+      break;
+    default:
+      llvm_unreachable("unsupported relocation type");
+    }
+  }
 }
 
 void WasmObjectWriter::writeObject(MCAssembler &Asm,
                                    const MCAsmLayout &Layout) {
+  unsigned PtrType = is64Bit() ? wasm::WASM_TYPE_I64 : wasm::WASM_TYPE_I32;
+
+  // Collect information from the available symbols.
+  DenseMap<WasmFunctionType, unsigned, WasmFunctionTypeDenseMapInfo>
+      FunctionTypeIndices;
+  SmallVector<WasmFunctionType, 4> FunctionTypes;
+  SmallVector<WasmFunction, 4> Functions;
+  SmallVector<uint32_t, 4> TableElems;
+  SmallVector<WasmGlobal, 4> Globals;
+  SmallVector<WasmImport, 4> Imports;
+  SmallVector<WasmExport, 4> Exports;
+  DenseMap<const MCSymbolWasm *, uint32_t> SymbolIndices;
+  SmallPtrSet<const MCSymbolWasm *, 4> IsAddressTaken;
+  unsigned NumFuncImports = 0;
+  unsigned NumGlobalImports = 0;
+  SmallVector<char, 0> DataBytes;
+
+  // Populate the IsAddressTaken set.
+  for (WasmRelocationEntry RelEntry : CodeRelocations) {
+    switch (RelEntry.Type) {
+    case wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB:
+    case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB:
+      IsAddressTaken.insert(RelEntry.Symbol);
+      break;
+    default:
+      break;
+    }
+  }
+  for (WasmRelocationEntry RelEntry : DataRelocations) {
+    switch (RelEntry.Type) {
+    case wasm::R_WEBASSEMBLY_TABLE_INDEX_I32:
+    case wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32:
+      IsAddressTaken.insert(RelEntry.Symbol);
+      break;
+    default:
+      break;
+    }
+  }
+
+  // Populate the Imports set.
+  for (const MCSymbol &S : Asm.symbols()) {
+    const auto &WS = static_cast<const MCSymbolWasm &>(S);
+    unsigned Type;
+
+    if (WS.isFunction()) {
+      // Prepare the function's type, if we haven't seen it yet.
+      WasmFunctionType F;
+      F.Returns = WS.getReturns();
+      F.Params = WS.getParams();
+      auto Pair =
+          FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
+      if (Pair.second)
+        FunctionTypes.push_back(F);
+
+      Type = Pair.first->second;
+    } else {
+      Type = PtrType;
+    }
+
+    // If the symbol is not defined in this translation unit, import it.
+    if (!WS.isTemporary() && !WS.isDefined(/*SetUsed=*/false)) {
+      WasmImport Import;
+      Import.ModuleName = WS.getModuleName();
+      Import.FieldName = WS.getName();
+
+      if (WS.isFunction()) {
+        Import.Kind = wasm::WASM_EXTERNAL_FUNCTION;
+        Import.Type = Type;
+        SymbolIndices[&WS] = NumFuncImports;
+        ++NumFuncImports;
+      } else {
+        Import.Kind = wasm::WASM_EXTERNAL_GLOBAL;
+        Import.Type = Type;
+        SymbolIndices[&WS] = NumGlobalImports;
+        ++NumGlobalImports;
+      }
+
+      Imports.push_back(Import);
+    }
+  }
+
+  // Handle defined symbols.
+  for (const MCSymbol &S : Asm.symbols()) {
+    // Ignore unnamed temporary symbols, which aren't ever exported, imported,
+    // or used in relocations.
+    if (S.isTemporary() && S.getName().empty())
+      continue;
+    const auto &WS = static_cast<const MCSymbolWasm &>(S);
+    unsigned Index;
+    if (WS.isFunction()) {
+      // Prepare the function's type, if we haven't seen it yet.
+      WasmFunctionType F;
+      F.Returns = WS.getReturns();
+      F.Params = WS.getParams();
+      auto Pair =
+          FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
+      if (Pair.second)
+        FunctionTypes.push_back(F);
+
+      unsigned Type = Pair.first->second;
+
+      if (WS.isDefined(/*SetUsed=*/false)) {
+        // A definition. Take the next available index.
+        Index = NumFuncImports + Functions.size();
+
+        // Prepare the function.
+        WasmFunction Func;
+        Func.Type = Type;
+        Func.Sym = &WS;
+        SymbolIndices[&WS] = Index;
+        Functions.push_back(Func);
+      } else {
+        // An import; the index was assigned above.
+        Index = SymbolIndices.find(&WS)->second;
+      }
+
+      // If needed, prepare the function to be called indirectly.
+      if (IsAddressTaken.count(&WS))
+        TableElems.push_back(Index);
+    } else {
+      // For now, ignore temporary non-function symbols.
+      if (S.isTemporary())
+        continue;
+
+      if (WS.getOffset() != 0)
+        report_fatal_error("data sections must contain one variable each");
+      if (!WS.getSize())
+        report_fatal_error("data symbols must have a size set with .size");
+
+      int64_t Size = 0;
+      if (!WS.getSize()->evaluateAsAbsolute(Size, Layout))
+        report_fatal_error(".size expression must be evaluatable");
+
+      if (WS.isDefined(false)) {
+        MCSectionWasm &DataSection =
+            static_cast<MCSectionWasm &>(WS.getSection());
+
+        if (uint64_t(Size) != Layout.getSectionFileSize(&DataSection))
+          report_fatal_error("data sections must contain at most one variable");
+
+        DataBytes.resize(alignTo(DataBytes.size(), DataSection.getAlignment()));
+
+        DataSection.setSectionOffset(DataBytes.size());
+
+        for (MCSection::iterator I = DataSection.begin(), E = DataSection.end();
+             I != E; ++I) {
+          const MCFragment &Frag = *I;
+          if (Frag.hasInstructions())
+            report_fatal_error("only data supported in data sections");
+
+          if (const MCAlignFragment *Align = dyn_cast<MCAlignFragment>(&Frag)) {
+            if (Align->getValueSize() != 1)
+              report_fatal_error("only byte values supported for alignment");
+            // If nops are requested, use zeros, as this is the data section.
+            uint8_t Value = Align->hasEmitNops() ? 0 : Align->getValue();
+            uint64_t Size = std::min<uint64_t>(alignTo(DataBytes.size(),
+                                                       Align->getAlignment()),
+                                               DataBytes.size() +
+                                                   Align->getMaxBytesToEmit());
+            DataBytes.resize(Size, Value);
+          } else if (const MCFillFragment *Fill =
+                                              dyn_cast<MCFillFragment>(&Frag)) {
+            DataBytes.insert(DataBytes.end(), Size, Fill->getValue());
+          } else {
+            const MCDataFragment &DataFrag = cast<MCDataFragment>(Frag);
+            const SmallVectorImpl<char> &Contents = DataFrag.getContents();
+
+            DataBytes.insert(DataBytes.end(), Contents.begin(), Contents.end());
+          }
+        }
+
+        // For each external global, prepare a corresponding wasm global
+        // holding its address.
+        if (WS.isExternal()) {
+          Index = NumGlobalImports + Globals.size();
+
+          WasmGlobal Global;
+          Global.Type = PtrType;
+          Global.IsMutable = false;
+          Global.InitialValue = DataSection.getSectionOffset();
+          SymbolIndices[&WS] = Index;
+          Globals.push_back(Global);
+        }
+      }
+    }
+
+    // If the symbol is visible outside this translation unit, export it.
+    if (WS.isExternal()) {
+      assert(WS.isDefined(false));
+      WasmExport Export;
+      Export.FieldName = WS.getName();
+      Export.Index = Index;
+
+      if (WS.isFunction())
+        Export.Kind = wasm::WASM_EXTERNAL_FUNCTION;
+      else
+        Export.Kind = wasm::WASM_EXTERNAL_GLOBAL;
+
+      Exports.push_back(Export);
+    }
+  }
+
+  // Add types for indirect function calls.
+  for (const TypeIndexFixup &Fixup : TypeIndexFixups) {
+    WasmFunctionType F;
+    F.Returns = Fixup.Symbol->getReturns();
+    F.Params = Fixup.Symbol->getParams();
+    auto Pair =
+        FunctionTypeIndices.insert(std::make_pair(F, FunctionTypes.size()));
+    if (Pair.second)
+      FunctionTypes.push_back(F);
+
+    TypeIndexFixupTypes.push_back(Pair.first->second);
+  }
+
   // Write out the Wasm header.
   writeHeader(Asm);
 
-  // TODO: Write the contents.
+  SectionBookkeeping Section;
+
+  // === Type Section =========================================================
+  if (!FunctionTypes.empty()) {
+    startSection(Section, wasm::WASM_SEC_TYPE);
+
+    encodeULEB128(FunctionTypes.size(), getStream());
+
+    for (WasmFunctionType &FuncTy : FunctionTypes) {
+      write8(wasm::WASM_TYPE_FUNC);
+      encodeULEB128(FuncTy.Params.size(), getStream());
+      for (unsigned Ty : FuncTy.Params)
+        write8(Ty);
+      encodeULEB128(FuncTy.Returns.size(), getStream());
+      for (unsigned Ty : FuncTy.Returns)
+        write8(Ty);
+    }
+
+    endSection(Section);
+  }
+
+  // === Import Section ========================================================
+  if (!Imports.empty()) {
+    startSection(Section, wasm::WASM_SEC_IMPORT);
+
+    encodeULEB128(Imports.size(), getStream());
+    for (const WasmImport &Import : Imports) {
+      StringRef ModuleName = Import.ModuleName;
+      encodeULEB128(ModuleName.size(), getStream());
+      writeBytes(ModuleName);
+
+      StringRef FieldName = Import.FieldName;
+      encodeULEB128(FieldName.size(), getStream());
+      writeBytes(FieldName);
+
+      write8(Import.Kind);
+
+      switch (Import.Kind) {
+      case wasm::WASM_EXTERNAL_FUNCTION:
+        encodeULEB128(Import.Type, getStream());
+        break;
+      case wasm::WASM_EXTERNAL_GLOBAL:
+        write8(Import.Type);
+        write8(0); // mutability
+        break;
+      default:
+        llvm_unreachable("unsupported import kind");
+      }
+    }
+
+    endSection(Section);
+  }
+
+  // === Function Section ======================================================
+  if (!Functions.empty()) {
+    startSection(Section, wasm::WASM_SEC_FUNCTION);
+
+    encodeULEB128(Functions.size(), getStream());
+    for (const WasmFunction &Func : Functions)
+      encodeULEB128(Func.Type, getStream());
+
+    endSection(Section);
+  }
+
+  // === Table Section =========================================================
+  // For now, always emit the table section, since indirect calls are not
+  // valid without it. In the future, we could perhaps be more clever and omit
+  // it if there are no indirect calls.
+  startSection(Section, wasm::WASM_SEC_TABLE);
+
+  // The number of tables, fixed to 1 for now.
+  encodeULEB128(1, getStream());
+
+  write8(wasm::WASM_TYPE_ANYFUNC);
+
+  encodeULEB128(0, getStream());                 // flags
+  encodeULEB128(TableElems.size(), getStream()); // initial
+
+  endSection(Section);
+
+  // === Memory Section ========================================================
+  // For now, always emit the memory section, since loads and stores are not
+  // valid without it. In the future, we could perhaps be more clever and omit
+  // it if there are no loads or stores.
+  startSection(Section, wasm::WASM_SEC_MEMORY);
+
+  encodeULEB128(1, getStream()); // number of memory spaces
+
+  encodeULEB128(0, getStream()); // flags
+  encodeULEB128(DataBytes.size(), getStream()); // initial
+
+  endSection(Section);
+
+  // === Global Section ========================================================
+  if (!Globals.empty()) {
+    startSection(Section, wasm::WASM_SEC_GLOBAL);
+
+    encodeULEB128(Globals.size(), getStream());
+    for (const WasmGlobal &Global : Globals) {
+      write8(Global.Type);
+      write8(Global.IsMutable);
+
+      write8(wasm::WASM_OPCODE_I32_CONST);
+      encodeSLEB128(Global.InitialValue, getStream()); // offset
+      write8(wasm::WASM_OPCODE_END);
+    }
+
+    endSection(Section);
+  }
+
+  // === Export Section ========================================================
+  if (!Exports.empty()) {
+    startSection(Section, wasm::WASM_SEC_EXPORT);
+
+    encodeULEB128(Exports.size(), getStream());
+    for (const WasmExport &Export : Exports) {
+      encodeULEB128(Export.FieldName.size(), getStream());
+      writeBytes(Export.FieldName);
+
+      write8(Export.Kind);
+
+      encodeULEB128(Export.Index, getStream());
+    }
+
+    endSection(Section);
+  }
+
+#if 0 // TODO: Start Section
+  if (HaveStartFunction) {
+    // === Start Section =========================================================
+    startSection(Section, wasm::WASM_SEC_START);
+
+    encodeSLEB128(StartFunction, getStream());
+
+    endSection(Section);
+  }
+#endif
+
+  // === Elem Section ==========================================================
+  if (!TableElems.empty()) {
+    startSection(Section, wasm::WASM_SEC_ELEM);
+
+    encodeULEB128(1, getStream()); // number of "segments"
+    encodeULEB128(0, getStream()); // the table index
+
+    // init expr for starting offset
+    write8(wasm::WASM_OPCODE_I32_CONST);
+    encodeSLEB128(0, getStream());
+    write8(wasm::WASM_OPCODE_END);
+
+    encodeULEB128(TableElems.size(), getStream());
+    for (uint32_t Elem : TableElems)
+      encodeULEB128(Elem, getStream());
+
+    endSection(Section);
+  }
+
+  // === Code Section ==========================================================
+  if (!Functions.empty()) {
+    startSection(Section, wasm::WASM_SEC_CODE);
+
+    encodeULEB128(Functions.size(), getStream());
+
+    for (const WasmFunction &Func : Functions) {
+      MCSectionWasm &FuncSection =
+          static_cast<MCSectionWasm &>(Func.Sym->getSection());
+
+      if (Func.Sym->isVariable())
+        report_fatal_error("weak symbols not supported yet");
+
+      if (Func.Sym->getOffset() != 0)
+        report_fatal_error("function sections must contain one function each");
+
+      if (!Func.Sym->getSize())
+        report_fatal_error("function symbols must have a size set with .size");
+
+      int64_t Size = 0;
+      if (!Func.Sym->getSize()->evaluateAsAbsolute(Size, Layout))
+        report_fatal_error(".size expression must be evaluatable");
+
+      encodeULEB128(Size, getStream());
+
+      FuncSection.setSectionOffset(getStream().tell() -
+                                   Section.ContentsOffset);
+
+      Asm.writeSectionData(&FuncSection, Layout);
+    }
+
+    // Apply the type index fixups for call_indirect etc. instructions.
+    for (size_t i = 0, e = TypeIndexFixups.size(); i < e; ++i) {
+      uint32_t Type = TypeIndexFixupTypes[i];
+      unsigned Padding = PaddingFor5ByteULEB128(Type);
+
+      const TypeIndexFixup &Fixup = TypeIndexFixups[i];
+      uint64_t Offset = Fixup.Offset +
+                        Fixup.FixupSection->getSectionOffset();
+
+      uint8_t Buffer[16];
+      unsigned SizeLen = encodeULEB128(Type, Buffer, Padding);
+      assert(SizeLen == 5);
+      getStream().pwrite((char *)Buffer, SizeLen,
+                         Section.ContentsOffset + Offset);
+    }
+
+    // Apply fixups.
+    ApplyRelocations(CodeRelocations, getStream(), SymbolIndices,
+                     Section.ContentsOffset);
+
+    endSection(Section);
+  }
+
+  // === Data Section ==========================================================
+  if (!DataBytes.empty()) {
+    startSection(Section, wasm::WASM_SEC_DATA);
+
+    encodeULEB128(1, getStream()); // count
+    encodeULEB128(0, getStream()); // memory index
+    write8(wasm::WASM_OPCODE_I32_CONST);
+    encodeSLEB128(0, getStream()); // offset
+    write8(wasm::WASM_OPCODE_END);
+    encodeULEB128(DataBytes.size(), getStream()); // size
+    writeBytes(DataBytes); // data
+
+    // Apply fixups.
+    ApplyRelocations(DataRelocations, getStream(), SymbolIndices,
+                     Section.ContentsOffset);
+
+    endSection(Section);
+  }
+
+  // === Name Section ==========================================================
+  if (NumFuncImports != 0 || !Functions.empty()) {
+    startSection(Section, wasm::WASM_SEC_CUSTOM, "name");
+
+    encodeULEB128(NumFuncImports + Functions.size(), getStream());
+    for (const WasmImport &Import : Imports) {
+      if (Import.Kind == wasm::WASM_EXTERNAL_FUNCTION) {
+        encodeULEB128(Import.FieldName.size(), getStream());
+        writeBytes(Import.FieldName);
+        encodeULEB128(0, getStream()); // local count, meaningless for imports
+      }
+    }
+    for (const WasmFunction &Func : Functions) {
+      encodeULEB128(Func.Sym->getName().size(), getStream());
+      writeBytes(Func.Sym->getName());
+
+      // TODO: Local names.
+      encodeULEB128(0, getStream()); // local count
+    }
+
+    endSection(Section);
+  }
+
+  // See: https://github.com/WebAssembly/tool-conventions/blob/master/Linking.md
+  // for descriptions of the reloc sections.
+
+  // === Code Reloc Section ====================================================
+  if (!CodeRelocations.empty()) {
+    startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.CODE");
+
+    write8(wasm::WASM_SEC_CODE);
+
+    encodeULEB128(CodeRelocations.size(), getStream());
+
+    WriteRelocations(CodeRelocations, getStream(), SymbolIndices);
+
+    endSection(Section);
+  }
+
+  // === Data Reloc Section ====================================================
+  if (!DataRelocations.empty()) {
+    startSection(Section, wasm::WASM_SEC_CUSTOM, "reloc.DATA");
+
+    write8(wasm::WASM_SEC_DATA);
+
+    encodeULEB128(DataRelocations.size(), getStream());
+
+    WriteRelocations(DataRelocations, getStream(), SymbolIndices);
+
+    endSection(Section);
+  }
+
+  // TODO: Translate the .comment section to the output.
+
+  // TODO: Translate debug sections to the output.
 }
 
 MCObjectWriter *llvm::createWasmObjectWriter(MCWasmObjectTargetWriter *MOTW,

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyAsmBackend.cpp Fri Feb 24 17:18:00 2017
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "MCTargetDesc/WebAssemblyFixupKinds.h"
 #include "llvm/MC/MCAsmBackend.h"
 #include "llvm/MC/MCAssembler.h"
 #include "llvm/MC/MCDirectives.h"
@@ -70,6 +71,12 @@ public:
       : MCAsmBackend(), Is64Bit(Is64Bit) {}
   ~WebAssemblyAsmBackend() override {}
 
+  unsigned getNumFixupKinds() const override {
+    return WebAssembly::NumTargetFixupKinds;
+  }
+
+  const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override;
+
   void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
                   uint64_t Value, bool IsPCRel) const override;
 
@@ -82,12 +89,6 @@ public:
     return false;
   }
 
-  unsigned getNumFixupKinds() const override {
-    // We currently just use the generic fixups in MCFixup.h and don't have any
-    // target-specific fixups.
-    return 0;
-  }
-
   bool mayNeedRelaxation(const MCInst &Inst) const override { return false; }
 
   void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI,
@@ -131,6 +132,26 @@ WebAssemblyAsmBackendELF::createObjectWr
   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)

Added: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h?rev=296190&view=auto
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h (added)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyFixupKinds.h Fri Feb 24 17:18:00 2017
@@ -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

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCCodeEmitter.cpp Fri Feb 24 17:18:00 2017
@@ -13,6 +13,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "MCTargetDesc/WebAssemblyFixupKinds.h"
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/Statistic.h"
 #include "llvm/MC/MCCodeEmitter.h"
@@ -48,9 +49,7 @@ class WebAssemblyMCCodeEmitter final : p
 
 public:
   WebAssemblyMCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx)
-      : MCII(mcii), Ctx(ctx) {
-    (void)Ctx;
-  }
+      : MCII(mcii), Ctx(ctx) {}
 };
 } // end anonymous namespace
 
@@ -68,6 +67,13 @@ void WebAssemblyMCCodeEmitter::encodeIns
   assert(Binary < UINT8_MAX && "Multi-byte opcodes not supported yet");
   OS << uint8_t(Binary);
 
+  // For br_table instructions, encode the size of the table. In the MCInst,
+  // there's an index operand, one operand for each table entry, and the
+  // default operand.
+  if (MI.getOpcode() == WebAssembly::BR_TABLE_I32 ||
+      MI.getOpcode() == WebAssembly::BR_TABLE_I64)
+    encodeULEB128(MI.getNumOperands() - 2, OS);
+
   const MCInstrDesc &Desc = MCII.get(MI.getOpcode());
   for (unsigned i = 0, e = MI.getNumOperands(); i < e; ++i) {
     const MCOperand &MO = MI.getOperand(i);
@@ -82,6 +88,12 @@ void WebAssemblyMCCodeEmitter::encodeIns
           encodeSLEB128(int32_t(MO.getImm()), OS);
         } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
           encodeSLEB128(int64_t(MO.getImm()), OS);
+        } else if (Info.OperandType == WebAssembly::OPERAND_GLOBAL) {
+          Fixups.push_back(MCFixup::create(
+              OS.tell() - Start, MCConstantExpr::create(MO.getImm(), Ctx),
+              MCFixupKind(WebAssembly::fixup_code_global_index), MI.getLoc()));
+          ++MCNumFixups;
+          encodeULEB128(uint64_t(MO.getImm()), OS);
         } else {
           encodeULEB128(uint64_t(MO.getImm()), OS);
         }
@@ -107,14 +119,28 @@ void WebAssemblyMCCodeEmitter::encodeIns
         support::endian::Writer<support::little>(OS).write<double>(d);
       }
     } else if (MO.isExpr()) {
+      const MCOperandInfo &Info = Desc.OpInfo[i];
+      llvm::MCFixupKind FixupKind;
+      size_t PaddedSize;
+      if (Info.OperandType == WebAssembly::OPERAND_I32IMM) {
+        FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i32);
+        PaddedSize = 5;
+      } else if (Info.OperandType == WebAssembly::OPERAND_I64IMM) {
+        FixupKind = MCFixupKind(WebAssembly::fixup_code_sleb128_i64);
+        PaddedSize = 10;
+      } else if (Info.OperandType == WebAssembly::OPERAND_FUNCTION32 ||
+                 Info.OperandType == WebAssembly::OPERAND_OFFSET32 ||
+                 Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
+        FixupKind = MCFixupKind(WebAssembly::fixup_code_uleb128_i32);
+        PaddedSize = 5;
+      } else {
+        llvm_unreachable("unexpected symbolic operand kind");
+      }
       Fixups.push_back(MCFixup::create(
           OS.tell() - Start, MO.getExpr(),
-          STI.getTargetTriple().isArch64Bit() ? FK_Data_8 : FK_Data_4,
-          MI.getLoc()));
+          FixupKind, MI.getLoc()));
       ++MCNumFixups;
-      encodeULEB128(STI.getTargetTriple().isArch64Bit() ? UINT64_MAX
-                                                        : uint64_t(UINT32_MAX),
-                    OS);
+      encodeULEB128(0, OS, PaddedSize - 1);
     } else {
       llvm_unreachable("unexpected operand kind");
     }

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyMCTargetDesc.h Fri Feb 24 17:18:00 2017
@@ -68,7 +68,9 @@ enum OperandType {
   /// p2align immediate for load and store address alignment.
   OPERAND_P2ALIGN,
   /// signature immediate for block/loop.
-  OPERAND_SIGNATURE
+  OPERAND_SIGNATURE,
+  /// type signature immediate for call_indirect.
+  OPERAND_TYPEINDEX,
 };
 } // end namespace WebAssembly
 

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.cpp Fri Feb 24 17:18:00 2017
@@ -22,8 +22,10 @@
 #include "llvm/MC/MCSubtargetInfo.h"
 #include "llvm/MC/MCSymbolELF.h"
 #include "llvm/MC/MCSymbolWasm.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/FormattedStream.h"
+#include "llvm/Support/Wasm.h"
 using namespace llvm;
 
 WebAssemblyTargetStreamer::WebAssemblyTargetStreamer(MCStreamer &S)
@@ -51,14 +53,28 @@ static void PrintTypes(formatted_raw_ost
   OS << '\n';
 }
 
-void WebAssemblyTargetAsmStreamer::emitParam(ArrayRef<MVT> Types) {
-  OS << "\t.param  \t";
-  PrintTypes(OS, Types);
+void WebAssemblyTargetAsmStreamer::emitParam(MCSymbol *Symbol,
+                                             ArrayRef<MVT> Types) {
+  if (!Types.empty()) {
+    OS << "\t.param  \t";
+
+    // FIXME: Currently this applies to the "current" function; it may
+    // be cleaner to specify an explicit symbol as part of the directive.
+
+    PrintTypes(OS, Types);
+  }
 }
 
-void WebAssemblyTargetAsmStreamer::emitResult(ArrayRef<MVT> Types) {
-  OS << "\t.result \t";
-  PrintTypes(OS, Types);
+void WebAssemblyTargetAsmStreamer::emitResult(MCSymbol *Symbol,
+                                              ArrayRef<MVT> Types) {
+  if (!Types.empty()) {
+    OS << "\t.result \t";
+
+    // FIXME: Currently this applies to the "current" function; it may
+    // be cleaner to specify an explicit symbol as part of the directive.
+
+    PrintTypes(OS, Types);
+  }
 }
 
 void WebAssemblyTargetAsmStreamer::emitLocal(ArrayRef<MVT> Types) {
@@ -92,11 +108,13 @@ void WebAssemblyTargetAsmStreamer::emitI
   OS << "\t.indidx  \t" << *Value << '\n';
 }
 
-void WebAssemblyTargetELFStreamer::emitParam(ArrayRef<MVT> Types) {
+void WebAssemblyTargetELFStreamer::emitParam(MCSymbol *Symbol,
+                                             ArrayRef<MVT> Types) {
   // Nothing to emit; params are declared as part of the function signature.
 }
 
-void WebAssemblyTargetELFStreamer::emitResult(ArrayRef<MVT> Types) {
+void WebAssemblyTargetELFStreamer::emitResult(MCSymbol *Symbol,
+                                              ArrayRef<MVT> Types) {
   // Nothing to emit; results are declared as part of the function signature.
 }
 
@@ -123,22 +141,52 @@ void WebAssemblyTargetELFStreamer::emitI
 void WebAssemblyTargetELFStreamer::emitGlobalImport(StringRef name) {
 }
 
-void WebAssemblyTargetWasmStreamer::emitParam(ArrayRef<MVT> Types) {
-  // Nothing to emit; params are declared as part of the function signature.
+static unsigned MVT2WasmType(MVT Ty) {
+  switch (Ty.SimpleTy) {
+  case MVT::i32: return wasm::WASM_TYPE_I32;
+  case MVT::i64: return wasm::WASM_TYPE_I64;
+  case MVT::f32: return wasm::WASM_TYPE_F32;
+  case MVT::f64: return wasm::WASM_TYPE_F64;
+  default: llvm_unreachable("unsupported type");
+  }
 }
 
-void WebAssemblyTargetWasmStreamer::emitResult(ArrayRef<MVT> Types) {
-  // Nothing to emit; results are declared as part of the function signature.
+void WebAssemblyTargetWasmStreamer::emitParam(MCSymbol *Symbol,
+                                              ArrayRef<MVT> Types) {
+  SmallVector<unsigned, 4> Params;
+  for (MVT Ty : Types)
+    Params.push_back(MVT2WasmType(Ty));
+
+  cast<MCSymbolWasm>(Symbol)->setParams(std::move(Params));
+}
+
+void WebAssemblyTargetWasmStreamer::emitResult(MCSymbol *Symbol,
+                                               ArrayRef<MVT> Types) {
+  SmallVector<unsigned, 4> Returns;
+  for (MVT Ty : Types)
+    Returns.push_back(MVT2WasmType(Ty));
+
+  cast<MCSymbolWasm>(Symbol)->setReturns(std::move(Returns));
 }
 
 void WebAssemblyTargetWasmStreamer::emitLocal(ArrayRef<MVT> Types) {
-  Streamer.EmitULEB128IntValue(Types.size());
-  for (MVT Type : Types)
-    Streamer.EmitIntValue(int64_t(WebAssembly::toValType(Type)), 1);
+  SmallVector<std::pair<MVT, uint32_t>, 4> Grouped;
+  for (MVT Type : Types) {
+    if (Grouped.empty() || Grouped.back().first != Type)
+      Grouped.push_back(std::make_pair(Type, 1));
+    else
+      ++Grouped.back().second;
+  }
+
+  Streamer.EmitULEB128IntValue(Grouped.size());
+  for (auto Pair : Grouped) {
+    Streamer.EmitULEB128IntValue(Pair.second);
+    Streamer.EmitULEB128IntValue(uint64_t(WebAssembly::toValType(Pair.first)));
+  }
 }
 
 void WebAssemblyTargetWasmStreamer::emitEndFunc() {
-  Streamer.EmitIntValue(WebAssembly::End, 1);
+  llvm_unreachable(".end_func is not needed for direct wasm output");
 }
 
 void WebAssemblyTargetWasmStreamer::emitIndIdx(const MCExpr *Value) {

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyTargetStreamer.h Fri Feb 24 17:18:00 2017
@@ -31,9 +31,9 @@ public:
   explicit WebAssemblyTargetStreamer(MCStreamer &S);
 
   /// .param
-  virtual void emitParam(ArrayRef<MVT> Types) = 0;
+  virtual void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) = 0;
   /// .result
-  virtual void emitResult(ArrayRef<MVT> Types) = 0;
+  virtual void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) = 0;
   /// .local
   virtual void emitLocal(ArrayRef<MVT> Types) = 0;
   /// .endfunc
@@ -57,8 +57,8 @@ class WebAssemblyTargetAsmStreamer final
 public:
   WebAssemblyTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
 
-  void emitParam(ArrayRef<MVT> Types) override;
-  void emitResult(ArrayRef<MVT> Types) override;
+  void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
+  void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
   void emitLocal(ArrayRef<MVT> Types) override;
   void emitEndFunc() override;
   void emitIndirectFunctionType(StringRef name,
@@ -73,8 +73,8 @@ class WebAssemblyTargetELFStreamer final
 public:
   explicit WebAssemblyTargetELFStreamer(MCStreamer &S);
 
-  void emitParam(ArrayRef<MVT> Types) override;
-  void emitResult(ArrayRef<MVT> Types) override;
+  void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
+  void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
   void emitLocal(ArrayRef<MVT> Types) override;
   void emitEndFunc() override;
   void emitIndirectFunctionType(StringRef name,
@@ -89,8 +89,8 @@ class WebAssemblyTargetWasmStreamer fina
 public:
   explicit WebAssemblyTargetWasmStreamer(MCStreamer &S);
 
-  void emitParam(ArrayRef<MVT> Types) override;
-  void emitResult(ArrayRef<MVT> Types) override;
+  void emitParam(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
+  void emitResult(MCSymbol *Symbol, ArrayRef<MVT> Types) override;
   void emitLocal(ArrayRef<MVT> Types) override;
   void emitEndFunc() override;
   void emitIndirectFunctionType(StringRef name,

Modified: llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/MCTargetDesc/WebAssemblyWasmObjectWriter.cpp Fri Feb 24 17:18:00 2017
@@ -14,9 +14,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
+#include "MCTargetDesc/WebAssemblyFixupKinds.h"
 #include "llvm/MC/MCFixup.h"
+#include "llvm/MC/MCSymbolWasm.h"
 #include "llvm/MC/MCWasmObjectWriter.h"
+#include "llvm/Support/Casting.h"
 #include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Wasm.h"
 using namespace llvm;
 
 namespace {
@@ -33,12 +37,52 @@ private:
 WebAssemblyWasmObjectWriter::WebAssemblyWasmObjectWriter(bool Is64Bit)
     : MCWasmObjectTargetWriter(Is64Bit) {}
 
+// Test whether the given expression computes a function address.
+static bool IsFunctionExpr(const MCExpr *Expr) {
+  if (const MCSymbolRefExpr *SyExp =
+          dyn_cast<MCSymbolRefExpr>(Expr))
+    return cast<MCSymbolWasm>(SyExp->getSymbol()).isFunction();
+
+  if (const MCBinaryExpr *BinOp =
+          dyn_cast<MCBinaryExpr>(Expr))
+    return IsFunctionExpr(BinOp->getLHS()) != IsFunctionExpr(BinOp->getRHS());
+
+  if (const MCUnaryExpr *UnOp =
+          dyn_cast<MCUnaryExpr>(Expr))
+    return IsFunctionExpr(UnOp->getSubExpr());
+
+  return false;
+}
+
 unsigned WebAssemblyWasmObjectWriter::getRelocType(MCContext &Ctx,
                                                    const MCValue &Target,
                                                    const MCFixup &Fixup,
                                                    bool IsPCRel) const {
-  llvm_unreachable("Relocations not yet implemented");
-  return 0;
+  // WebAssembly functions are not allocated in the data address space. To
+  // resolve a pointer to a function, we must use a special relocation type.
+  bool IsFunction = IsFunctionExpr(Fixup.getValue());
+
+  assert(!IsPCRel);
+  switch (unsigned(Fixup.getKind())) {
+  case WebAssembly::fixup_code_sleb128_i32:
+    if (IsFunction)
+      return wasm::R_WEBASSEMBLY_TABLE_INDEX_SLEB;
+    return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_SLEB;
+  case WebAssembly::fixup_code_sleb128_i64:
+    llvm_unreachable("fixup_sleb128_i64 not implemented yet");
+  case WebAssembly::fixup_code_uleb128_i32:
+    if (IsFunction)
+      return wasm::R_WEBASSEMBLY_FUNCTION_INDEX_LEB;
+    return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_LEB;
+  case FK_Data_4:
+    if (IsFunction)
+      return wasm::R_WEBASSEMBLY_TABLE_INDEX_I32;
+    return wasm::R_WEBASSEMBLY_GLOBAL_ADDR_I32;
+  case FK_Data_8:
+    llvm_unreachable("FK_Data_8 not implemented yet");
+  default:
+    llvm_unreachable("unimplemented fixup kind");
+  }
 }
 
 MCObjectWriter *llvm::createWebAssemblyWasmObjectWriter(raw_pwrite_stream &OS,

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.cpp Fri Feb 24 17:18:00 2017
@@ -14,6 +14,7 @@
 ///
 //===----------------------------------------------------------------------===//
 
+#include "WebAssemblyAsmPrinter.h"
 #include "InstPrinter/WebAssemblyInstPrinter.h"
 #include "MCTargetDesc/WebAssemblyMCTargetDesc.h"
 #include "MCTargetDesc/WebAssemblyTargetStreamer.h"
@@ -21,13 +22,13 @@
 #include "WebAssemblyMCInstLower.h"
 #include "WebAssemblyMachineFunctionInfo.h"
 #include "WebAssemblyRegisterInfo.h"
-#include "WebAssemblySubtarget.h"
 #include "llvm/ADT/StringExtras.h"
 #include "llvm/CodeGen/Analysis.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineConstantPool.h"
 #include "llvm/CodeGen/MachineInstr.h"
 #include "llvm/IR/DataLayout.h"
+#include "llvm/IR/GlobalVariable.h"
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCStreamer.h"
 #include "llvm/MC/MCSymbol.h"
@@ -38,56 +39,6 @@ using namespace llvm;
 
 #define DEBUG_TYPE "asm-printer"
 
-namespace {
-
-class WebAssemblyAsmPrinter final : public AsmPrinter {
-  const MachineRegisterInfo *MRI;
-  WebAssemblyFunctionInfo *MFI;
-
-public:
-  WebAssemblyAsmPrinter(TargetMachine &TM, std::unique_ptr<MCStreamer> Streamer)
-      : AsmPrinter(TM, std::move(Streamer)), MRI(nullptr), MFI(nullptr) {}
-
-private:
-  StringRef getPassName() const override {
-    return "WebAssembly Assembly Printer";
-  }
-
-  //===------------------------------------------------------------------===//
-  // MachineFunctionPass Implementation.
-  //===------------------------------------------------------------------===//
-
-  bool runOnMachineFunction(MachineFunction &MF) override {
-    MRI = &MF.getRegInfo();
-    MFI = MF.getInfo<WebAssemblyFunctionInfo>();
-    return AsmPrinter::runOnMachineFunction(MF);
-  }
-
-  //===------------------------------------------------------------------===//
-  // AsmPrinter Implementation.
-  //===------------------------------------------------------------------===//
-
-  void EmitEndOfAsmFile(Module &M) override;
-  void EmitJumpTableInfo() override;
-  void EmitConstantPool() override;
-  void EmitFunctionBodyStart() override;
-  void EmitFunctionBodyEnd() override;
-  void EmitInstruction(const MachineInstr *MI) override;
-  const MCExpr *lowerConstant(const Constant *CV) override;
-  bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
-                       unsigned AsmVariant, const char *ExtraCode,
-                       raw_ostream &OS) override;
-  bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
-                             unsigned AsmVariant, const char *ExtraCode,
-                             raw_ostream &OS) override;
-
-  MVT getRegType(unsigned RegNo) const;
-  std::string regToString(const MachineOperand &MO);
-  WebAssemblyTargetStreamer *getTargetStreamer();
-};
-
-} // end anonymous namespace
-
 //===----------------------------------------------------------------------===//
 // Helpers.
 //===----------------------------------------------------------------------===//
@@ -135,7 +86,10 @@ void WebAssemblyAsmPrinter::EmitEndOfAsm
   }
   for (const auto &G : M.globals()) {
     if (!G.hasInitializer() && G.hasExternalLinkage()) {
+      uint16_t Size = M.getDataLayout().getTypeAllocSize(G.getValueType());
       getTargetStreamer()->emitGlobalImport(G.getGlobalIdentifier());
+      OutStreamer->emitELFSize(getSymbol(&G),
+                               MCConstantExpr::create(Size, OutContext));
     }
   }
 }
@@ -150,8 +104,7 @@ void WebAssemblyAsmPrinter::EmitJumpTabl
 }
 
 void WebAssemblyAsmPrinter::EmitFunctionBodyStart() {
-  if (!MFI->getParams().empty())
-    getTargetStreamer()->emitParam(MFI->getParams());
+  getTargetStreamer()->emitParam(CurrentFnSym, MFI->getParams());
 
   SmallVector<MVT, 4> ResultVTs;
   const Function &F(*MF->getFunction());
@@ -169,23 +122,26 @@ void WebAssemblyAsmPrinter::EmitFunction
   // If the return type needs to be legalized it will get converted into
   // passing a pointer.
   if (ResultVTs.size() == 1)
-    getTargetStreamer()->emitResult(ResultVTs);
-
-  // FIXME: When ExplicitLocals is enabled by default, we won't need
-  // to define the locals here (and MFI can go back to being pointer-to-const).
-  for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
-    unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
-    unsigned WAReg = MFI->getWAReg(VReg);
-    // Don't declare unused registers.
-    if (WAReg == WebAssemblyFunctionInfo::UnusedReg)
-      continue;
-    // Don't redeclare parameters.
-    if (WAReg < MFI->getParams().size())
-      continue;
-    // Don't declare stackified registers.
-    if (int(WAReg) < 0)
-      continue;
-    MFI->addLocal(getRegType(VReg));
+    getTargetStreamer()->emitResult(CurrentFnSym, ResultVTs);
+  else
+    getTargetStreamer()->emitResult(CurrentFnSym, ArrayRef<MVT>());
+
+  if (TM.getTargetTriple().isOSBinFormatELF()) {
+    assert(MFI->getLocals().empty());
+    for (unsigned Idx = 0, IdxE = MRI->getNumVirtRegs(); Idx != IdxE; ++Idx) {
+      unsigned VReg = TargetRegisterInfo::index2VirtReg(Idx);
+      unsigned WAReg = MFI->getWAReg(VReg);
+      // Don't declare unused registers.
+      if (WAReg == WebAssemblyFunctionInfo::UnusedReg)
+        continue;
+      // Don't redeclare parameters.
+      if (WAReg < MFI->getParams().size())
+        continue;
+      // Don't declare stackified registers.
+      if (int(WAReg) < 0)
+        continue;
+      MFI->addLocal(getRegType(VReg));
+    }
   }
 
   getTargetStreamer()->emitLocal(MFI->getLocals());
@@ -194,7 +150,8 @@ void WebAssemblyAsmPrinter::EmitFunction
 }
 
 void WebAssemblyAsmPrinter::EmitFunctionBodyEnd() {
-  getTargetStreamer()->emitEndFunc();
+  if (TM.getTargetTriple().isOSBinFormatELF())
+    getTargetStreamer()->emitEndFunc();
 }
 
 void WebAssemblyAsmPrinter::EmitInstruction(const MachineInstr *MI) {

Added: llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h?rev=296190&view=auto
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h (added)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyAsmPrinter.h Fri Feb 24 17:18:00 2017
@@ -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

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyCFGStackify.cpp Fri Feb 24 17:18:00 2017
@@ -488,6 +488,15 @@ static void FixEndsAtEndOfFunction(
   }
 }
 
+// WebAssembly functions end with an end instruction, as if the function body
+// were a block.
+static void AppendEndToFunction(
+    MachineFunction &MF,
+    const WebAssemblyInstrInfo &TII) {
+  BuildMI(MF.back(), MF.back().end(), DebugLoc(),
+          TII.get(WebAssembly::END_FUNCTION));
+}
+
 /// Insert LOOP and BLOCK markers at appropriate places.
 static void PlaceMarkers(MachineFunction &MF, const MachineLoopInfo &MLI,
                          const WebAssemblyInstrInfo &TII,
@@ -555,6 +564,11 @@ static void PlaceMarkers(MachineFunction
   // 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) {

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyCallIndirectFixup.cpp Fri Feb 24 17:18:00 2017
@@ -97,15 +97,28 @@ bool WebAssemblyCallIndirectFixup::runOn
         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);
+        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()));
 
-        MI.addOperand(MF, MO);
+        // 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;

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyExplicitLocals.cpp Fri Feb 24 17:18:00 2017
@@ -60,7 +60,25 @@ FunctionPass *llvm::createWebAssemblyExp
 /// if it doesn't yet have one.
 static unsigned getLocalId(DenseMap<unsigned, unsigned> &Reg2Local,
                            unsigned &CurLocal, unsigned Reg) {
-  return Reg2Local.insert(std::make_pair(Reg, CurLocal++)).first->second;
+  auto P = Reg2Local.insert(std::make_pair(Reg, CurLocal));
+  if (P.second)
+    ++CurLocal;
+  return P.first->second;
+}
+
+/// Get the appropriate drop opcode for the given register class.
+static unsigned getDropOpcode(const TargetRegisterClass *RC) {
+  if (RC == &WebAssembly::I32RegClass)
+    return WebAssembly::DROP_I32;
+  if (RC == &WebAssembly::I64RegClass)
+    return WebAssembly::DROP_I64;
+  if (RC == &WebAssembly::F32RegClass)
+    return WebAssembly::DROP_F32;
+  if (RC == &WebAssembly::F64RegClass)
+    return WebAssembly::DROP_F64;
+  if (RC == &WebAssembly::V128RegClass)
+    return WebAssembly::DROP_V128;
+  llvm_unreachable("Unexpected register class");
 }
 
 /// Get the appropriate get_local opcode for the given register class.
@@ -176,6 +194,12 @@ bool WebAssemblyExplicitLocals::runOnMac
   // Start assigning local numbers after the last parameter.
   unsigned CurLocal = MFI.getParams().size();
 
+  // Precompute the set of registers that are unused, so that we can insert
+  // drops to their defs.
+  BitVector UseEmpty(MRI.getNumVirtRegs());
+  for (unsigned i = 0, e = MRI.getNumVirtRegs(); i < e; ++i)
+    UseEmpty[i] = MRI.use_empty(TargetRegisterInfo::index2VirtReg(i));
+
   // Visit each instruction in the function.
   for (MachineBasicBlock &MBB : MF) {
     for (MachineBasicBlock::iterator I = MBB.begin(), E = MBB.end(); I != E;) {
@@ -224,15 +248,26 @@ bool WebAssemblyExplicitLocals::runOnMac
       assert(MI.getDesc().getNumDefs() <= 1);
       if (MI.getDesc().getNumDefs() == 1) {
         unsigned OldReg = MI.getOperand(0).getReg();
-        if (!MFI.isVRegStackified(OldReg) && !MRI.use_empty(OldReg)) {
-          unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
+        if (!MFI.isVRegStackified(OldReg)) {
           const TargetRegisterClass *RC = MRI.getRegClass(OldReg);
           unsigned NewReg = MRI.createVirtualRegister(RC);
           auto InsertPt = std::next(MachineBasicBlock::iterator(&MI));
-          unsigned Opc = getSetLocalOpcode(RC);
-          BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
-              .addImm(LocalId)
-              .addReg(NewReg);
+          if (MI.getOpcode() == WebAssembly::IMPLICIT_DEF) {
+            MI.eraseFromParent();
+            Changed = true;
+            continue;
+          }
+          if (UseEmpty[TargetRegisterInfo::virtReg2Index(OldReg)]) {
+            unsigned Opc = getDropOpcode(RC);
+            BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
+                .addReg(NewReg);
+          } else {
+            unsigned LocalId = getLocalId(Reg2Local, CurLocal, OldReg);
+            unsigned Opc = getSetLocalOpcode(RC);
+            BuildMI(MBB, InsertPt, MI.getDebugLoc(), TII->get(Opc))
+                .addImm(LocalId)
+                .addReg(NewReg);
+          }
           MI.getOperand(0).setReg(NewReg);
           MFI.stackifyVReg(NewReg);
           Changed = true;
@@ -278,13 +313,16 @@ bool WebAssemblyExplicitLocals::runOnMac
   }
 
   // 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;
   }
 

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyFrameLowering.cpp Fri Feb 24 17:18:00 2017
@@ -24,6 +24,7 @@
 #include "WebAssemblyMachineFunctionInfo.h"
 #include "WebAssemblySubtarget.h"
 #include "WebAssemblyTargetMachine.h"
+#include "WebAssemblyUtilities.h"
 #include "llvm/CodeGen/MachineFrameInfo.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/CodeGen/MachineInstrBuilder.h"
@@ -151,6 +152,8 @@ void WebAssemblyFrameLowering::emitProlo
   auto &MRI = MF.getRegInfo();
 
   auto InsertPt = MBB.begin();
+  while (InsertPt != MBB.end() && WebAssembly::isArgument(*InsertPt))
+    ++InsertPt;
   DebugLoc DL;
 
   const TargetRegisterClass *PtrRC =

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrCall.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrCall.td?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrCall.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrCall.td Fri Feb 24 17:18:00 2017
@@ -30,13 +30,15 @@ multiclass CALL<WebAssemblyRegClass vt,
                    [(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, strin
                                (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, strin
   } // 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

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrControl.td Fri Feb 24 17:18:00 2017
@@ -64,9 +64,12 @@ let Uses = [VALUE_STACK], Defs = [VALUE_
 def BLOCK     : I<(outs), (ins Signature:$sig), [], "block   \t$sig", 0x02>;
 def LOOP      : I<(outs), (ins Signature:$sig), [], "loop    \t$sig", 0x03>;
 
-// END_BLOCK and END_LOOP are represented with the same opcode in wasm.
+// END_BLOCK, END_LOOP, and END_FUNCTION are represented with the same opcode
+// in wasm.
 def END_BLOCK : I<(outs), (ins), [], "end_block", 0x0b>;
 def END_LOOP  : I<(outs), (ins), [], "end_loop", 0x0b>;
+let isTerminator = 1, isBarrier = 1 in
+def END_FUNCTION : I<(outs), (ins), [], "end_function", 0x0b>;
 } // Uses = [VALUE_STACK], Defs = [VALUE_STACK]
 
 multiclass RETURN<WebAssemblyRegClass vt> {

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyInstrInfo.td Fri Feb 24 17:18:00 2017
@@ -107,6 +107,9 @@ def Signature : Operand<i32> {
 }
 } // OperandType = "OPERAND_SIGNATURE"
 
+let OperandType = "OPERAND_TYPEINDEX" in
+def TypeIndex : Operand<i32>;
+
 } // OperandNamespace = "WebAssembly"
 
 //===----------------------------------------------------------------------===//

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.cpp Fri Feb 24 17:18:00 2017
@@ -14,7 +14,10 @@
 //===----------------------------------------------------------------------===//
 
 #include "WebAssemblyMCInstLower.h"
+#include "WebAssemblyAsmPrinter.h"
 #include "WebAssemblyMachineFunctionInfo.h"
+#include "WebAssemblyRuntimeLibcallSignatures.h"
+#include "WebAssemblyUtilities.h"
 #include "llvm/CodeGen/AsmPrinter.h"
 #include "llvm/CodeGen/MachineFunction.h"
 #include "llvm/IR/Constants.h"
@@ -22,18 +25,85 @@
 #include "llvm/MC/MCContext.h"
 #include "llvm/MC/MCExpr.h"
 #include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/MC/MCSymbolWasm.h"
 #include "llvm/Support/ErrorHandling.h"
 #include "llvm/Support/raw_ostream.h"
 using namespace llvm;
 
 MCSymbol *
 WebAssemblyMCInstLower::GetGlobalAddressSymbol(const MachineOperand &MO) const {
-  return Printer.getSymbol(MO.getGlobal());
+  const GlobalValue *Global = MO.getGlobal();
+  MCSymbol *Sym = Printer.getSymbol(Global);
+  if (isa<MCSymbolELF>(Sym))
+    return Sym;
+
+  MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
+
+  if (const auto *FuncTy = dyn_cast<FunctionType>(Global->getValueType())) {
+    const MachineFunction &MF = *MO.getParent()->getParent()->getParent();
+    const TargetMachine &TM = MF.getTarget();
+    const Function &CurrentFunc = *MF.getFunction();
+
+    SmallVector<unsigned, 4> Returns;
+    SmallVector<unsigned, 4> Params;
+
+    WebAssembly::ValType iPTR =
+        MF.getSubtarget<WebAssemblySubtarget>().hasAddr64() ?
+        WebAssembly::ValType::I64 :
+        WebAssembly::ValType::I32;
+
+    SmallVector<MVT, 4> ResultMVTs;
+    ComputeLegalValueVTs(CurrentFunc, TM, FuncTy->getReturnType(), ResultMVTs);
+    // WebAssembly can't currently handle returning tuples.
+    if (ResultMVTs.size() <= 1)
+      for (MVT ResultMVT : ResultMVTs)
+        Returns.push_back(unsigned(WebAssembly::toValType(ResultMVT)));
+    else
+      Params.push_back(unsigned(iPTR));
+
+    for (Type *Ty : FuncTy->params()) {
+      SmallVector<MVT, 4> ParamMVTs;
+      ComputeLegalValueVTs(CurrentFunc, TM, Ty, ParamMVTs);
+      for (MVT ParamMVT : ParamMVTs)
+        Params.push_back(unsigned(WebAssembly::toValType(ParamMVT)));
+    }
+
+    if (FuncTy->isVarArg())
+      Params.push_back(unsigned(iPTR));
+
+    WasmSym->setReturns(std::move(Returns));
+    WasmSym->setParams(std::move(Params));
+    WasmSym->setIsFunction(true);
+  }
+
+  return WasmSym;
 }
 
 MCSymbol *WebAssemblyMCInstLower::GetExternalSymbolSymbol(
     const MachineOperand &MO) const {
-  return Printer.GetExternalSymbolSymbol(MO.getSymbolName());
+  const char *Name = MO.getSymbolName();
+  MCSymbol *Sym = Printer.GetExternalSymbolSymbol(Name);
+  if (isa<MCSymbolELF>(Sym))
+    return Sym;
+
+  MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
+  const WebAssemblySubtarget &Subtarget = Printer.getSubtarget();
+
+  // __stack_pointer is a global variable; all other external symbols used by
+  // CodeGen are functions.
+  if (strcmp(Name, "__stack_pointer") == 0)
+    return WasmSym;
+
+  SmallVector<unsigned, 4> Returns;
+  SmallVector<unsigned, 4> Params;
+  GetSignature(Subtarget, Name, Returns, Params);
+
+  WasmSym->setReturns(std::move(Returns));
+  WasmSym->setParams(std::move(Params));
+  WasmSym->setIsFunction(true);
+
+  return WasmSym;
 }
 
 MCOperand WebAssemblyMCInstLower::LowerSymbolOperand(MCSymbol *Sym,
@@ -42,6 +112,9 @@ MCOperand WebAssemblyMCInstLower::LowerS
   MCSymbolRefExpr::VariantKind VK =
       IsFunc ? MCSymbolRefExpr::VK_WebAssembly_FUNCTION
              : MCSymbolRefExpr::VK_None;
+  if (!isa<MCSymbolELF>(Sym))
+    cast<MCSymbolWasm>(Sym)->setIsFunction(IsFunc);
+
   const MCExpr *Expr = MCSymbolRefExpr::create(Sym, VK, Ctx);
 
   if (Offset != 0) {
@@ -54,10 +127,24 @@ MCOperand WebAssemblyMCInstLower::LowerS
   return MCOperand::createExpr(Expr);
 }
 
+// Return the WebAssembly type associated with the given register class.
+static unsigned getType(const TargetRegisterClass *RC) {
+  if (RC == &WebAssembly::I32RegClass)
+    return unsigned(WebAssembly::ExprType::I32);
+  if (RC == &WebAssembly::I64RegClass)
+    return unsigned(WebAssembly::ExprType::I64);
+  if (RC == &WebAssembly::F32RegClass)
+    return unsigned(WebAssembly::ExprType::F32);
+  if (RC == &WebAssembly::F64RegClass)
+    return unsigned(WebAssembly::ExprType::F64);
+  llvm_unreachable("Unexpected register class");
+}
+
 void WebAssemblyMCInstLower::Lower(const MachineInstr *MI,
                                    MCInst &OutMI) const {
   OutMI.setOpcode(MI->getOpcode());
 
+  const MCInstrDesc &Desc = MI->getDesc();
   for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
     const MachineOperand &MO = MI->getOperand(i);
 
@@ -80,6 +167,41 @@ void WebAssemblyMCInstLower::Lower(const
       break;
     }
     case MachineOperand::MO_Immediate:
+      if (i < Desc.NumOperands) {
+        const MCOperandInfo &Info = Desc.OpInfo[i];
+        if (Info.OperandType == WebAssembly::OPERAND_TYPEINDEX) {
+          MCSymbol *Sym = Printer.createTempSymbol("typeindex");
+          if (!isa<MCSymbolELF>(Sym)) {
+            SmallVector<unsigned, 4> Returns;
+            SmallVector<unsigned, 4> Params;
+
+            const MachineRegisterInfo &MRI =
+                MI->getParent()->getParent()->getRegInfo();
+            for (const MachineOperand &MO : MI->defs())
+              Returns.push_back(getType(MRI.getRegClass(MO.getReg())));
+            for (const MachineOperand &MO : MI->explicit_uses())
+              if (MO.isReg())
+                Params.push_back(getType(MRI.getRegClass(MO.getReg())));
+
+            // call_indirect instructions have a callee operand at the end which
+            // doesn't count as a param.
+            if (WebAssembly::isCallIndirect(*MI))
+              Params.pop_back();
+
+            MCSymbolWasm *WasmSym = cast<MCSymbolWasm>(Sym);
+            WasmSym->setReturns(std::move(Returns));
+            WasmSym->setParams(std::move(Params));
+            WasmSym->setIsFunction(true);
+
+            const MCExpr *Expr =
+                MCSymbolRefExpr::create(WasmSym,
+                                        MCSymbolRefExpr::VK_WebAssembly_TYPEINDEX,
+                                        Ctx);
+            MCOp = MCOperand::createExpr(Expr);
+            break;
+          }
+        }
+      }
       MCOp = MCOperand::createImm(MO.getImm());
       break;
     case MachineOperand::MO_FPImmediate: {

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMCInstLower.h Fri Feb 24 17:18:00 2017
@@ -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 WebAssembl
                                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;
 };

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyMachineFunctionInfo.h Fri Feb 24 17:18:00 2017
@@ -60,6 +60,8 @@ class WebAssemblyFunctionInfo final : pu
   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; }
 

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyPeephole.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyPeephole.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyPeephole.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyPeephole.cpp Fri Feb 24 17:18:00 2017
@@ -80,8 +80,18 @@ static bool MaybeRewriteToFallthrough(Ma
     return false;
   if (&MBB != &MF.back())
     return false;
-  if (&MI != &MBB.back())
-    return false;
+  if (MF.getSubtarget<WebAssemblySubtarget>()
+        .getTargetTriple().isOSBinFormatELF()) {
+    if (&MI != &MBB.back())
+      return false;
+  } else {
+    MachineBasicBlock::iterator End = MBB.end();
+    --End;
+    assert(End->getOpcode() == WebAssembly::END_FUNCTION);
+    --End;
+    if (&MI != &*End)
+      return false;
+  }
 
   if (FallthroughOpc != WebAssembly::FALLTHROUGH_RETURN_VOID) {
     // If the operand isn't stackified, insert a COPY to read the operand and

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyTargetMachine.cpp Fri Feb 24 17:18:00 2017
@@ -85,6 +85,14 @@ WebAssemblyTargetMachine::WebAssemblyTar
   // 'unreachable' instructions which is meant for that case.
   this->Options.TrapUnreachable = true;
 
+  // WebAssembly treats each function as an independent unit. Force
+  // -ffunction-sections, effectively, so that we can emit them independently.
+  if (!TT.isOSBinFormatELF()) {
+    this->Options.FunctionSections = true;
+    this->Options.DataSections = true;
+    this->Options.UniqueSectionNames = true;
+  }
+
   initAsmInfo();
 
   // Note that we don't use setRequiresStructuredCFG(true). It disables
@@ -264,12 +272,14 @@ void WebAssemblyPassConfig::addPreEmitPa
     addPass(createWebAssemblyRegColoring());
   }
 
+  // Eliminate multiple-entry loops. Do this before inserting explicit get_local
+  // and set_local operators because we create a new variable that we want
+  // converted into a local.
+  addPass(createWebAssemblyFixIrreducibleControlFlow());
+
   // Insert explicit get_local and set_local operators.
   addPass(createWebAssemblyExplicitLocals());
 
-  // Eliminate multiple-entry loops.
-  addPass(createWebAssemblyFixIrreducibleControlFlow());
-
   // Put the CFG in structured form; insert BLOCK and LOOP markers.
   addPass(createWebAssemblyCFGStackify());
 

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.cpp Fri Feb 24 17:18:00 2017
@@ -69,3 +69,20 @@ bool WebAssembly::isChild(const MachineI
   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;
+  }
+}

Modified: llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h (original)
+++ llvm/trunk/lib/Target/WebAssembly/WebAssemblyUtilities.h Fri Feb 24 17:18:00 2017
@@ -27,6 +27,7 @@ bool isArgument(const MachineInstr &MI);
 bool isCopy(const MachineInstr &MI);
 bool isTee(const MachineInstr &MI);
 bool isChild(const MachineInstr &MI, const WebAssemblyFunctionInfo &MFI);
+bool isCallIndirect(const MachineInstr &MI);
 
 } // end namespace WebAssembly
 } // end namespace llvm

Modified: llvm/trunk/test/CodeGen/WebAssembly/call.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/call.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/call.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/call.ll Fri Feb 24 17:18:00 2017
@@ -4,7 +4,7 @@
 ; Test that basic call operations assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare i32 @i32_nullary()
 declare i32 @i32_unary(i32)
@@ -61,7 +61,8 @@ define void @call_void_nullary() {
 ; CHECK-LABEL: call_i32_unary:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: {{^}} i32.call $push[[NUM:[0-9]+]]=, i32_unary at FUNCTION, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: {{^}} i32.call $push[[NUM:[0-9]+]]=, i32_unary at FUNCTION, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @call_i32_unary(i32 %a) {
   %r = call i32 @i32_unary(i32 %a)
@@ -71,7 +72,9 @@ define i32 @call_i32_unary(i32 %a) {
 ; CHECK-LABEL: call_i32_binary:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: {{^}} i32.call $push[[NUM:[0-9]+]]=, i32_binary at FUNCTION, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: {{^}} i32.call $push[[NUM:[0-9]+]]=, i32_binary at FUNCTION, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @call_i32_binary(i32 %a, i32 %b) {
   %r = call i32 @i32_binary(i32 %a, i32 %b)
@@ -80,7 +83,8 @@ define i32 @call_i32_binary(i32 %a, i32
 
 ; CHECK-LABEL: call_indirect_void:
 ; CHECK-NEXT: .param i32{{$}}
-; CHECK-NEXT: {{^}} call_indirect $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: {{^}} call_indirect $pop[[L0]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @call_indirect_void(void ()* %callee) {
   call void %callee()
@@ -90,7 +94,8 @@ define void @call_indirect_void(void ()*
 ; CHECK-LABEL: call_indirect_i32:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: {{^}} i32.call_indirect $push[[NUM:[0-9]+]]=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: {{^}} i32.call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @call_indirect_i32(i32 ()* %callee) {
   %t = call i32 %callee()
@@ -99,7 +104,9 @@ define i32 @call_indirect_i32(i32 ()* %c
 
 ; CHECK-LABEL: call_indirect_arg:
 ; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: {{^}} call_indirect $1, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: {{^}} call_indirect $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @call_indirect_arg(void (i32)* %callee, i32 %arg) {
   call void %callee(i32 %arg)
@@ -108,7 +115,11 @@ define void @call_indirect_arg(void (i32
 
 ; CHECK-LABEL: call_indirect_arg_2:
 ; CHECK-NEXT: .param i32, i32, i32{{$}}
-; CHECK-NEXT: {{^}} i32.call_indirect $drop=, $1, $2, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 2{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: {{^}} i32.call_indirect $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]], $pop[[L2]]{{$}}
+; CHECK-NEXT: drop $pop[[NUM]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @call_indirect_arg_2(i32 (i32, i32)* %callee, i32 %arg, i32 %arg2) {
   call i32 %callee(i32 %arg, i32 %arg2)

Modified: llvm/trunk/test/CodeGen/WebAssembly/cfi.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/cfi.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/cfi.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/cfi.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Tests that we correctly assign indexes for control flow integrity.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 @0 = private unnamed_addr constant [2 x void (...)*] [void (...)* bitcast (void ()* @f to void (...)*), void (...)* bitcast (void ()* @g to void (...)*)], align 16
 

Modified: llvm/trunk/test/CodeGen/WebAssembly/comparisons_f32.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/comparisons_f32.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/comparisons_f32.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/comparisons_f32.ll Fri Feb 24 17:18:00 2017
@@ -4,13 +4,17 @@
 ; expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-LABEL: ord_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.eq $push[[NUM0:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f32.eq $push[[NUM1:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.eq $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.eq $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
 ; CHECK-NEXT: i32.and $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM2]]{{$}}
 define i32 @ord_f32(float %x, float %y) {
@@ -22,8 +26,12 @@ define i32 @ord_f32(float %x, float %y)
 ; CHECK-LABEL: uno_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM0:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM2]]{{$}}
 define i32 @uno_f32(float %x, float %y) {
@@ -35,7 +43,9 @@ define i32 @uno_f32(float %x, float %y)
 ; CHECK-LABEL: oeq_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.eq $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @oeq_f32(float %x, float %y) {
   %a = fcmp oeq float %x, %y
@@ -44,7 +54,7 @@ define i32 @oeq_f32(float %x, float %y)
 }
 
 ; CHECK-LABEL: une_f32:
-; CHECK: f32.ne $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f32.ne $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @une_f32(float %x, float %y) {
   %a = fcmp une float %x, %y
@@ -53,7 +63,7 @@ define i32 @une_f32(float %x, float %y)
 }
 
 ; CHECK-LABEL: olt_f32:
-; CHECK: f32.lt $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f32.lt $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @olt_f32(float %x, float %y) {
   %a = fcmp olt float %x, %y
@@ -62,7 +72,7 @@ define i32 @olt_f32(float %x, float %y)
 }
 
 ; CHECK-LABEL: ole_f32:
-; CHECK: f32.le $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f32.le $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ole_f32(float %x, float %y) {
   %a = fcmp ole float %x, %y
@@ -71,7 +81,7 @@ define i32 @ole_f32(float %x, float %y)
 }
 
 ; CHECK-LABEL: ogt_f32:
-; CHECK: f32.gt $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f32.gt $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ogt_f32(float %x, float %y) {
   %a = fcmp ogt float %x, %y
@@ -80,7 +90,7 @@ define i32 @ogt_f32(float %x, float %y)
 }
 
 ; CHECK-LABEL: oge_f32:
-; CHECK: f32.ge $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f32.ge $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @oge_f32(float %x, float %y) {
   %a = fcmp oge float %x, %y
@@ -93,9 +103,15 @@ define i32 @oge_f32(float %x, float %y)
 ; CHECK-LABEL: ueq_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.eq $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.eq $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
@@ -108,9 +124,15 @@ define i32 @ueq_f32(float %x, float %y)
 ; CHECK-LABEL: one_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f32.eq $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f32.eq $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.eq $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.eq $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.and $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.and $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]
@@ -123,9 +145,15 @@ define i32 @one_f32(float %x, float %y)
 ; CHECK-LABEL: ult_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.lt $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.lt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
@@ -138,9 +166,15 @@ define i32 @ult_f32(float %x, float %y)
 ; CHECK-LABEL: ule_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.le $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.le $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
@@ -153,9 +187,15 @@ define i32 @ule_f32(float %x, float %y)
 ; CHECK-LABEL: ugt_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.gt $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.gt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
@@ -168,9 +208,15 @@ define i32 @ugt_f32(float %x, float %y)
 ; CHECK-LABEL: uge_f32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f32.ge $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.ge $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}

Modified: llvm/trunk/test/CodeGen/WebAssembly/comparisons_f64.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/comparisons_f64.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/comparisons_f64.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/comparisons_f64.ll Fri Feb 24 17:18:00 2017
@@ -4,13 +4,17 @@
 ; expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-LABEL: ord_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.eq $push[[NUM0:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f64.eq $push[[NUM1:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.eq $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.eq $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
 ; CHECK-NEXT: i32.and $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM2]]{{$}}
 define i32 @ord_f64(double %x, double %y) {
@@ -22,8 +26,12 @@ define i32 @ord_f64(double %x, double %y
 ; CHECK-LABEL: uno_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM0:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM2:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM2]]{{$}}
 define i32 @uno_f64(double %x, double %y) {
@@ -35,7 +43,9 @@ define i32 @uno_f64(double %x, double %y
 ; CHECK-LABEL: oeq_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.eq $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @oeq_f64(double %x, double %y) {
   %a = fcmp oeq double %x, %y
@@ -44,7 +54,7 @@ define i32 @oeq_f64(double %x, double %y
 }
 
 ; CHECK-LABEL: une_f64:
-; CHECK: f64.ne $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f64.ne $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @une_f64(double %x, double %y) {
   %a = fcmp une double %x, %y
@@ -53,7 +63,7 @@ define i32 @une_f64(double %x, double %y
 }
 
 ; CHECK-LABEL: olt_f64:
-; CHECK: f64.lt $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f64.lt $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @olt_f64(double %x, double %y) {
   %a = fcmp olt double %x, %y
@@ -62,7 +72,7 @@ define i32 @olt_f64(double %x, double %y
 }
 
 ; CHECK-LABEL: ole_f64:
-; CHECK: f64.le $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f64.le $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ole_f64(double %x, double %y) {
   %a = fcmp ole double %x, %y
@@ -71,7 +81,7 @@ define i32 @ole_f64(double %x, double %y
 }
 
 ; CHECK-LABEL: ogt_f64:
-; CHECK: f64.gt $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f64.gt $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ogt_f64(double %x, double %y) {
   %a = fcmp ogt double %x, %y
@@ -80,7 +90,7 @@ define i32 @ogt_f64(double %x, double %y
 }
 
 ; CHECK-LABEL: oge_f64:
-; CHECK: f64.ge $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: f64.ge $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @oge_f64(double %x, double %y) {
   %a = fcmp oge double %x, %y
@@ -93,9 +103,15 @@ define i32 @oge_f64(double %x, double %y
 ; CHECK-LABEL: ueq_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.eq $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.eq $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
@@ -108,9 +124,15 @@ define i32 @ueq_f64(double %x, double %y
 ; CHECK-LABEL: one_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f64.eq $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f64.eq $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.eq $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.eq $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.and $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.and $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]
@@ -123,9 +145,15 @@ define i32 @one_f64(double %x, double %y
 ; CHECK-LABEL: ult_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.lt $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.lt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
@@ -138,9 +166,15 @@ define i32 @ult_f64(double %x, double %y
 ; CHECK-LABEL: ule_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.le $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.le $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
@@ -153,9 +187,15 @@ define i32 @ule_f64(double %x, double %y
 ; CHECK-LABEL: ugt_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.gt $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.gt $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}
@@ -168,9 +208,15 @@ define i32 @ugt_f64(double %x, double %y
 ; CHECK-LABEL: uge_f64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: f64.ge $push[[NUM0:[0-9]+]]=, $0, $1{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $0, $0{{$}}
-; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $1, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.ge $push[[NUM0:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: get_local $push[[L2:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L3:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM1:[0-9]+]]=, $pop[[L2]], $pop[[L3]]{{$}}
+; CHECK-NEXT: get_local $push[[L4:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: get_local $push[[L5:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.ne $push[[NUM2:[0-9]+]]=, $pop[[L4]], $pop[[L5]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM3:[0-9]+]]=, $pop[[NUM1]], $pop[[NUM2]]{{$}}
 ; CHECK-NEXT: i32.or $push[[NUM4:[0-9]+]]=, $pop[[NUM0]], $pop[[NUM3]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM4]]{{$}}

Modified: llvm/trunk/test/CodeGen/WebAssembly/comparisons_i32.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/comparisons_i32.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/comparisons_i32.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/comparisons_i32.ll Fri Feb 24 17:18:00 2017
@@ -4,12 +4,14 @@
 ; Test that basic 32-bit integer comparison operations assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-LABEL: eq_i32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.eq $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @eq_i32(i32 %x, i32 %y) {
   %a = icmp eq i32 %x, %y
@@ -18,7 +20,7 @@ define i32 @eq_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: ne_i32:
-; CHECK: i32.ne $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.ne $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ne_i32(i32 %x, i32 %y) {
   %a = icmp ne i32 %x, %y
@@ -27,7 +29,7 @@ define i32 @ne_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: slt_i32:
-; CHECK: i32.lt_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.lt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @slt_i32(i32 %x, i32 %y) {
   %a = icmp slt i32 %x, %y
@@ -36,7 +38,7 @@ define i32 @slt_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: sle_i32:
-; CHECK: i32.le_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.le_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @sle_i32(i32 %x, i32 %y) {
   %a = icmp sle i32 %x, %y
@@ -45,7 +47,7 @@ define i32 @sle_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: ult_i32:
-; CHECK: i32.lt_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.lt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ult_i32(i32 %x, i32 %y) {
   %a = icmp ult i32 %x, %y
@@ -54,7 +56,7 @@ define i32 @ult_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: ule_i32:
-; CHECK: i32.le_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.le_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ule_i32(i32 %x, i32 %y) {
   %a = icmp ule i32 %x, %y
@@ -63,7 +65,7 @@ define i32 @ule_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: sgt_i32:
-; CHECK: i32.gt_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.gt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @sgt_i32(i32 %x, i32 %y) {
   %a = icmp sgt i32 %x, %y
@@ -72,7 +74,7 @@ define i32 @sgt_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: sge_i32:
-; CHECK: i32.ge_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.ge_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @sge_i32(i32 %x, i32 %y) {
   %a = icmp sge i32 %x, %y
@@ -81,7 +83,7 @@ define i32 @sge_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: ugt_i32:
-; CHECK: i32.gt_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.gt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ugt_i32(i32 %x, i32 %y) {
   %a = icmp ugt i32 %x, %y
@@ -90,7 +92,7 @@ define i32 @ugt_i32(i32 %x, i32 %y) {
 }
 
 ; CHECK-LABEL: uge_i32:
-; CHECK: i32.ge_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i32.ge_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @uge_i32(i32 %x, i32 %y) {
   %a = icmp uge i32 %x, %y

Modified: llvm/trunk/test/CodeGen/WebAssembly/comparisons_i64.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/comparisons_i64.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/comparisons_i64.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/comparisons_i64.ll Fri Feb 24 17:18:00 2017
@@ -4,12 +4,14 @@
 ; Test that basic 64-bit integer comparison operations assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-LABEL: eq_i64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i64.eq $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.eq $push[[NUM:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @eq_i64(i64 %x, i64 %y) {
   %a = icmp eq i64 %x, %y
@@ -18,7 +20,7 @@ define i32 @eq_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: ne_i64:
-; CHECK: i64.ne $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.ne $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ne_i64(i64 %x, i64 %y) {
   %a = icmp ne i64 %x, %y
@@ -27,7 +29,7 @@ define i32 @ne_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: slt_i64:
-; CHECK: i64.lt_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.lt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @slt_i64(i64 %x, i64 %y) {
   %a = icmp slt i64 %x, %y
@@ -36,7 +38,7 @@ define i32 @slt_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: sle_i64:
-; CHECK: i64.le_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.le_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @sle_i64(i64 %x, i64 %y) {
   %a = icmp sle i64 %x, %y
@@ -45,7 +47,7 @@ define i32 @sle_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: ult_i64:
-; CHECK: i64.lt_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.lt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ult_i64(i64 %x, i64 %y) {
   %a = icmp ult i64 %x, %y
@@ -54,7 +56,7 @@ define i32 @ult_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: ule_i64:
-; CHECK: i64.le_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.le_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ule_i64(i64 %x, i64 %y) {
   %a = icmp ule i64 %x, %y
@@ -63,7 +65,7 @@ define i32 @ule_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: sgt_i64:
-; CHECK: i64.gt_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.gt_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @sgt_i64(i64 %x, i64 %y) {
   %a = icmp sgt i64 %x, %y
@@ -72,7 +74,7 @@ define i32 @sgt_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: sge_i64:
-; CHECK: i64.ge_s $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.ge_s $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @sge_i64(i64 %x, i64 %y) {
   %a = icmp sge i64 %x, %y
@@ -81,7 +83,7 @@ define i32 @sge_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: ugt_i64:
-; CHECK: i64.gt_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.gt_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ugt_i64(i64 %x, i64 %y) {
   %a = icmp ugt i64 %x, %y
@@ -90,7 +92,7 @@ define i32 @ugt_i64(i64 %x, i64 %y) {
 }
 
 ; CHECK-LABEL: uge_i64:
-; CHECK: i64.ge_u $push[[NUM:[0-9]+]]=, $0, $1{{$}}
+; CHECK: i64.ge_u $push[[NUM:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @uge_i64(i64 %x, i64 %y) {
   %a = icmp uge i64 %x, %y

Modified: llvm/trunk/test/CodeGen/WebAssembly/copysign-casts.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/copysign-casts.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/copysign-casts.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/copysign-casts.ll Fri Feb 24 17:18:00 2017
@@ -4,14 +4,14 @@
 ; unfolded.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare double @copysign(double, double) nounwind readnone
 declare float @copysignf(float, float) nounwind readnone
 
 ; CHECK-LABEL: fold_promote:
-; CHECK: f64.promote/f32 $push0=, $1{{$}}
-; CHECK: f64.copysign    $push1=, $0, $pop0{{$}}
+; CHECK: f64.promote/f32 $push0=, $pop{{[0-9]+}}{{$}}
+; CHECK: f64.copysign    $push1=, $pop{{[0-9]+}}, $pop0{{$}}
 define double @fold_promote(double %a, float %b) {
   %c = fpext float %b to double
   %t = call double @copysign(double %a, double %c)
@@ -19,8 +19,8 @@ define double @fold_promote(double %a, f
 }
 
 ; CHECK-LABEL: fold_demote:{{$}}
-; CHECK: f32.demote/f64  $push0=, $1{{$}}
-; CHECK: f32.copysign    $push1=, $0, $pop0{{$}}
+; CHECK: f32.demote/f64  $push0=, $pop{{[0-9]+}}{{$}}
+; CHECK: f32.copysign    $push1=, $pop{{[0-9]+}}, $pop0{{$}}
 define float @fold_demote(float %a, double %b) {
   %c = fptrunc double %b to float
   %t = call float @copysignf(float %a, float %c)

Modified: llvm/trunk/test/CodeGen/WebAssembly/dbgvalue.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/dbgvalue.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/dbgvalue.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/dbgvalue.ll Fri Feb 24 17:18:00 2017
@@ -6,7 +6,7 @@
 ; CHECK: DW_TAG_variable
 source_filename = "test/CodeGen/WebAssembly/dbgvalue.ll"
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 @key = external local_unnamed_addr global [15 x i8], align 1
 @.str = external unnamed_addr constant [33 x i8], align 1

Modified: llvm/trunk/test/CodeGen/WebAssembly/dead-vreg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/dead-vreg.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/dead-vreg.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/dead-vreg.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Check that unused vregs aren't assigned registers.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 define void @foo(i32* nocapture %a, i32 %w, i32 %h) {
 ; CHECK-LABEL: foo:

Modified: llvm/trunk/test/CodeGen/WebAssembly/divrem-constant.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/divrem-constant.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/divrem-constant.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/divrem-constant.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test that integer div and rem by constant are optimized appropriately.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-LABEL: test_udiv_2:
 ; CHECK: i32.shr_u

Modified: llvm/trunk/test/CodeGen/WebAssembly/f32.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/f32.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/f32.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/f32.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test that basic 32-bit floating-point operations assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare float @llvm.fabs.f32(float)
 declare float @llvm.copysign.f32(float, float)
@@ -18,104 +18,106 @@ declare float @llvm.fma.f32(float, float
 ; CHECK-LABEL: fadd32:
 ; CHECK-NEXT: .param f32, f32{{$}}
 ; CHECK-NEXT: .result f32{{$}}
-; CHECK-NEXT: f32.add $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.add $push[[LR:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @fadd32(float %x, float %y) {
   %a = fadd float %x, %y
   ret float %a
 }
 
 ; CHECK-LABEL: fsub32:
-; CHECK: f32.sub $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.sub $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @fsub32(float %x, float %y) {
   %a = fsub float %x, %y
   ret float %a
 }
 
 ; CHECK-LABEL: fmul32:
-; CHECK: f32.mul $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.mul $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @fmul32(float %x, float %y) {
   %a = fmul float %x, %y
   ret float %a
 }
 
 ; CHECK-LABEL: fdiv32:
-; CHECK: f32.div $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.div $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @fdiv32(float %x, float %y) {
   %a = fdiv float %x, %y
   ret float %a
 }
 
 ; CHECK-LABEL: fabs32:
-; CHECK: f32.abs $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.abs $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @fabs32(float %x) {
   %a = call float @llvm.fabs.f32(float %x)
   ret float %a
 }
 
 ; CHECK-LABEL: fneg32:
-; CHECK: f32.neg $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.neg $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @fneg32(float %x) {
   %a = fsub float -0., %x
   ret float %a
 }
 
 ; CHECK-LABEL: copysign32:
-; CHECK: f32.copysign $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.copysign $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @copysign32(float %x, float %y) {
   %a = call float @llvm.copysign.f32(float %x, float %y)
   ret float %a
 }
 
 ; CHECK-LABEL: sqrt32:
-; CHECK: f32.sqrt $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.sqrt $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @sqrt32(float %x) {
   %a = call float @llvm.sqrt.f32(float %x)
   ret float %a
 }
 
 ; CHECK-LABEL: ceil32:
-; CHECK: f32.ceil $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.ceil $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @ceil32(float %x) {
   %a = call float @llvm.ceil.f32(float %x)
   ret float %a
 }
 
 ; CHECK-LABEL: floor32:
-; CHECK: f32.floor $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.floor $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @floor32(float %x) {
   %a = call float @llvm.floor.f32(float %x)
   ret float %a
 }
 
 ; CHECK-LABEL: trunc32:
-; CHECK: f32.trunc $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.trunc $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @trunc32(float %x) {
   %a = call float @llvm.trunc.f32(float %x)
   ret float %a
 }
 
 ; CHECK-LABEL: nearest32:
-; CHECK: f32.nearest $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.nearest $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @nearest32(float %x) {
   %a = call float @llvm.nearbyint.f32(float %x)
   ret float %a
 }
 
 ; CHECK-LABEL: nearest32_via_rint:
-; CHECK: f32.nearest $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f32.nearest $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @nearest32_via_rint(float %x) {
   %a = call float @llvm.rint.f32(float %x)
   ret float %a
@@ -128,7 +130,7 @@ define float @nearest32_via_rint(float %
 ; tests.
 
 ; CHECK-LABEL: fmin32:
-; CHECK: f32.min $push1=, $0, $pop0{{$}}
+; CHECK: f32.min $push1=, $pop{{[0-9]+}}, $pop[[LR]]{{$}}
 ; CHECK-NEXT: return $pop1{{$}}
 define float @fmin32(float %x) {
   %a = fcmp ult float %x, 0.0
@@ -137,7 +139,7 @@ define float @fmin32(float %x) {
 }
 
 ; CHECK-LABEL: fmax32:
-; CHECK: f32.max $push1=, $0, $pop0{{$}}
+; CHECK: f32.max $push1=, $pop{{[0-9]+}}, $pop[[LR]]{{$}}
 ; CHECK-NEXT: return $pop1{{$}}
 define float @fmax32(float %x) {
   %a = fcmp ugt float %x, 0.0
@@ -146,8 +148,8 @@ define float @fmax32(float %x) {
 }
 
 ; CHECK-LABEL: fma32:
-; CHECK: {{^}} f32.call $push0=, fmaf at FUNCTION, $0, $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: {{^}} f32.call $push[[LR:[0-9]+]]=, fmaf at FUNCTION, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define float @fma32(float %a, float %b, float %c) {
   %d = call float @llvm.fma.f32(float %a, float %b, float %c)
   ret float %d

Modified: llvm/trunk/test/CodeGen/WebAssembly/f64.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/f64.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/f64.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/f64.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test that basic 64-bit floating-point operations assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare double @llvm.fabs.f64(double)
 declare double @llvm.copysign.f64(double, double)
@@ -18,104 +18,106 @@ declare double @llvm.fma.f64(double, dou
 ; CHECK-LABEL: fadd64:
 ; CHECK-NEXT: .param f64, f64{{$}}
 ; CHECK-NEXT: .result f64{{$}}
-; CHECK-NEXT: f64.add $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.add $push[[LR:[0-9]+]]=, $pop[[L0]], $pop[[L1]]{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @fadd64(double %x, double %y) {
   %a = fadd double %x, %y
   ret double %a
 }
 
 ; CHECK-LABEL: fsub64:
-; CHECK: f64.sub $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.sub $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @fsub64(double %x, double %y) {
   %a = fsub double %x, %y
   ret double %a
 }
 
 ; CHECK-LABEL: fmul64:
-; CHECK: f64.mul $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.mul $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @fmul64(double %x, double %y) {
   %a = fmul double %x, %y
   ret double %a
 }
 
 ; CHECK-LABEL: fdiv64:
-; CHECK: f64.div $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.div $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @fdiv64(double %x, double %y) {
   %a = fdiv double %x, %y
   ret double %a
 }
 
 ; CHECK-LABEL: fabs64:
-; CHECK: f64.abs $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.abs $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @fabs64(double %x) {
   %a = call double @llvm.fabs.f64(double %x)
   ret double %a
 }
 
 ; CHECK-LABEL: fneg64:
-; CHECK: f64.neg $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.neg $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @fneg64(double %x) {
   %a = fsub double -0., %x
   ret double %a
 }
 
 ; CHECK-LABEL: copysign64:
-; CHECK: f64.copysign $push0=, $0, $1{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.copysign $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @copysign64(double %x, double %y) {
   %a = call double @llvm.copysign.f64(double %x, double %y)
   ret double %a
 }
 
 ; CHECK-LABEL: sqrt64:
-; CHECK: f64.sqrt $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.sqrt $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @sqrt64(double %x) {
   %a = call double @llvm.sqrt.f64(double %x)
   ret double %a
 }
 
 ; CHECK-LABEL: ceil64:
-; CHECK: f64.ceil $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.ceil $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @ceil64(double %x) {
   %a = call double @llvm.ceil.f64(double %x)
   ret double %a
 }
 
 ; CHECK-LABEL: floor64:
-; CHECK: f64.floor $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.floor $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @floor64(double %x) {
   %a = call double @llvm.floor.f64(double %x)
   ret double %a
 }
 
 ; CHECK-LABEL: trunc64:
-; CHECK: f64.trunc $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.trunc $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @trunc64(double %x) {
   %a = call double @llvm.trunc.f64(double %x)
   ret double %a
 }
 
 ; CHECK-LABEL: nearest64:
-; CHECK: f64.nearest $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.nearest $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @nearest64(double %x) {
   %a = call double @llvm.nearbyint.f64(double %x)
   ret double %a
 }
 
 ; CHECK-LABEL: nearest64_via_rint:
-; CHECK: f64.nearest $push0=, $0{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: f64.nearest $push[[LR:[0-9]+]]=, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @nearest64_via_rint(double %x) {
   %a = call double @llvm.rint.f64(double %x)
   ret double %a
@@ -128,7 +130,7 @@ define double @nearest64_via_rint(double
 ; tests.
 
 ; CHECK-LABEL: fmin64:
-; CHECK: f64.min $push1=, $0, $pop0{{$}}
+; CHECK: f64.min $push1=, $pop{{[0-9]+}}, $pop[[LR]]{{$}}
 ; CHECK-NEXT: return $pop1{{$}}
 define double @fmin64(double %x) {
   %a = fcmp ult double %x, 0.0
@@ -137,7 +139,7 @@ define double @fmin64(double %x) {
 }
 
 ; CHECK-LABEL: fmax64:
-; CHECK: f64.max $push1=, $0, $pop0{{$}}
+; CHECK: f64.max $push1=, $pop{{[0-9]+}}, $pop[[LR]]{{$}}
 ; CHECK-NEXT: return $pop1{{$}}
 define double @fmax64(double %x) {
   %a = fcmp ugt double %x, 0.0
@@ -146,8 +148,8 @@ define double @fmax64(double %x) {
 }
 
 ; CHECK-LABEL: fma64:
-; CHECK: {{^}} f64.call $push0=, fma at FUNCTION, $0, $1, $2{{$}}
-; CHECK-NEXT: return $pop0{{$}}
+; CHECK: {{^}} f64.call $push[[LR:[0-9]+]]=, fma at FUNCTION, $pop{{[0-9]+}}, $pop{{[0-9]+}}, $pop{{[0-9]+}}{{$}}
+; CHECK-NEXT: return $pop[[LR]]{{$}}
 define double @fma64(double %a, double %b, double %c) {
   %d = call double @llvm.fma.f64(double %a, double %b, double %c)
   ret double %d

Modified: llvm/trunk/test/CodeGen/WebAssembly/fast-isel-noreg.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/fast-isel-noreg.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/fast-isel-noreg.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/fast-isel-noreg.ll Fri Feb 24 17:18:00 2017
@@ -4,7 +4,7 @@
 ; Test that FastISel does not generate instructions with NoReg
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK: i32.const $push0=, 0
 define hidden i32 @a() #0 {

Modified: llvm/trunk/test/CodeGen/WebAssembly/globl.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/globl.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/globl.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/globl.ll Fri Feb 24 17:18:00 2017
@@ -1,7 +1,7 @@
 ; RUN: llc < %s -asm-verbose=false | FileCheck %s
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK: .globl foo
 ; CHECK-LABEL: foo:

Modified: llvm/trunk/test/CodeGen/WebAssembly/i128.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/i128.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/i128.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/i128.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test that basic 128-bit integer operations assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare i128 @llvm.ctlz.i128(i128, i1)
 declare i128 @llvm.cttz.i128(i128, i1)

Modified: llvm/trunk/test/CodeGen/WebAssembly/i32.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/i32.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/i32.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/i32.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test that basic 32-bit integer operations assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare i32 @llvm.ctlz.i32(i32, i1)
 declare i32 @llvm.cttz.i32(i32, i1)
@@ -12,7 +12,9 @@ declare i32 @llvm.ctpop.i32(i32)
 ; CHECK-LABEL: add32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.add $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.add $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @add32(i32 %x, i32 %y) {
   %a = add i32 %x, %y
@@ -22,7 +24,9 @@ define i32 @add32(i32 %x, i32 %y) {
 ; CHECK-LABEL: sub32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.sub $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.sub $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @sub32(i32 %x, i32 %y) {
   %a = sub i32 %x, %y
@@ -32,7 +36,9 @@ define i32 @sub32(i32 %x, i32 %y) {
 ; CHECK-LABEL: mul32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.mul $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.mul $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @mul32(i32 %x, i32 %y) {
   %a = mul i32 %x, %y
@@ -42,7 +48,9 @@ define i32 @mul32(i32 %x, i32 %y) {
 ; CHECK-LABEL: sdiv32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.div_s $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.div_s $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @sdiv32(i32 %x, i32 %y) {
   %a = sdiv i32 %x, %y
@@ -52,7 +60,9 @@ define i32 @sdiv32(i32 %x, i32 %y) {
 ; CHECK-LABEL: udiv32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.div_u $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.div_u $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @udiv32(i32 %x, i32 %y) {
   %a = udiv i32 %x, %y
@@ -62,7 +72,9 @@ define i32 @udiv32(i32 %x, i32 %y) {
 ; CHECK-LABEL: srem32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.rem_s $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.rem_s $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @srem32(i32 %x, i32 %y) {
   %a = srem i32 %x, %y
@@ -72,7 +84,9 @@ define i32 @srem32(i32 %x, i32 %y) {
 ; CHECK-LABEL: urem32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.rem_u $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.rem_u $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @urem32(i32 %x, i32 %y) {
   %a = urem i32 %x, %y
@@ -82,7 +96,9 @@ define i32 @urem32(i32 %x, i32 %y) {
 ; CHECK-LABEL: and32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.and $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.and $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @and32(i32 %x, i32 %y) {
   %a = and i32 %x, %y
@@ -92,7 +108,9 @@ define i32 @and32(i32 %x, i32 %y) {
 ; CHECK-LABEL: or32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.or $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.or $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @or32(i32 %x, i32 %y) {
   %a = or i32 %x, %y
@@ -102,7 +120,9 @@ define i32 @or32(i32 %x, i32 %y) {
 ; CHECK-LABEL: xor32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.xor $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.xor $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @xor32(i32 %x, i32 %y) {
   %a = xor i32 %x, %y
@@ -112,7 +132,9 @@ define i32 @xor32(i32 %x, i32 %y) {
 ; CHECK-LABEL: shl32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.shl $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.shl $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @shl32(i32 %x, i32 %y) {
   %a = shl i32 %x, %y
@@ -122,7 +144,9 @@ define i32 @shl32(i32 %x, i32 %y) {
 ; CHECK-LABEL: shr32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.shr_u $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.shr_u $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @shr32(i32 %x, i32 %y) {
   %a = lshr i32 %x, %y
@@ -132,7 +156,9 @@ define i32 @shr32(i32 %x, i32 %y) {
 ; CHECK-LABEL: sar32:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.shr_s $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.shr_s $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @sar32(i32 %x, i32 %y) {
   %a = ashr i32 %x, %y
@@ -142,7 +168,8 @@ define i32 @sar32(i32 %x, i32 %y) {
 ; CHECK-LABEL: clz32:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.clz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.clz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @clz32(i32 %x) {
   %a = call i32 @llvm.ctlz.i32(i32 %x, i1 false)
@@ -152,7 +179,8 @@ define i32 @clz32(i32 %x) {
 ; CHECK-LABEL: clz32_zero_undef:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.clz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.clz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @clz32_zero_undef(i32 %x) {
   %a = call i32 @llvm.ctlz.i32(i32 %x, i1 true)
@@ -162,7 +190,8 @@ define i32 @clz32_zero_undef(i32 %x) {
 ; CHECK-LABEL: ctz32:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.ctz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.ctz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @ctz32(i32 %x) {
   %a = call i32 @llvm.cttz.i32(i32 %x, i1 false)
@@ -172,7 +201,8 @@ define i32 @ctz32(i32 %x) {
 ; CHECK-LABEL: ctz32_zero_undef:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.ctz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.ctz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @ctz32_zero_undef(i32 %x) {
   %a = call i32 @llvm.cttz.i32(i32 %x, i1 true)
@@ -182,7 +212,8 @@ define i32 @ctz32_zero_undef(i32 %x) {
 ; CHECK-LABEL: popcnt32:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.popcnt $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.popcnt $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @popcnt32(i32 %x) {
   %a = call i32 @llvm.ctpop.i32(i32 %x)
@@ -192,7 +223,8 @@ define i32 @popcnt32(i32 %x) {
 ; CHECK-LABEL: eqz32:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.eqz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.eqz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @eqz32(i32 %x) {
   %a = icmp eq i32 %x, 0
@@ -203,7 +235,9 @@ define i32 @eqz32(i32 %x) {
 ; CHECK-LABEL: rotl:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.rotl $push0=, $0, $1
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.rotl $push0=, $pop[[L0]], $pop[[L1]]
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @rotl(i32 %x, i32 %y) {
   %z = sub i32 32, %y
@@ -216,7 +250,9 @@ define i32 @rotl(i32 %x, i32 %y) {
 ; CHECK-LABEL: masked_rotl:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.rotl $push0=, $0, $1
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.rotl $push0=, $pop[[L0]], $pop[[L1]]
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @masked_rotl(i32 %x, i32 %y) {
   %a = and i32 %y, 31
@@ -230,7 +266,9 @@ define i32 @masked_rotl(i32 %x, i32 %y)
 ; CHECK-LABEL: rotr:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.rotr $push0=, $0, $1
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.rotr $push0=, $pop[[L0]], $pop[[L1]]
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @rotr(i32 %x, i32 %y) {
   %z = sub i32 32, %y
@@ -243,7 +281,9 @@ define i32 @rotr(i32 %x, i32 %y) {
 ; CHECK-LABEL: masked_rotr:
 ; CHECK-NEXT: .param i32, i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.rotr $push0=, $0, $1
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.rotr $push0=, $pop[[L0]], $pop[[L1]]
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @masked_rotr(i32 %x, i32 %y) {
   %a = and i32 %y, 31

Modified: llvm/trunk/test/CodeGen/WebAssembly/i64.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/i64.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/i64.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/i64.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test that basic 64-bit integer operations assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare i64 @llvm.ctlz.i64(i64, i1)
 declare i64 @llvm.cttz.i64(i64, i1)
@@ -12,7 +12,9 @@ declare i64 @llvm.ctpop.i64(i64)
 ; CHECK-LABEL: add64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.add $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.add $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @add64(i64 %x, i64 %y) {
   %a = add i64 %x, %y
@@ -22,7 +24,9 @@ define i64 @add64(i64 %x, i64 %y) {
 ; CHECK-LABEL: sub64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.sub $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.sub $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @sub64(i64 %x, i64 %y) {
   %a = sub i64 %x, %y
@@ -32,7 +36,9 @@ define i64 @sub64(i64 %x, i64 %y) {
 ; CHECK-LABEL: mul64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.mul $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.mul $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @mul64(i64 %x, i64 %y) {
   %a = mul i64 %x, %y
@@ -42,7 +48,9 @@ define i64 @mul64(i64 %x, i64 %y) {
 ; CHECK-LABEL: sdiv64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.div_s $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.div_s $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @sdiv64(i64 %x, i64 %y) {
   %a = sdiv i64 %x, %y
@@ -52,7 +60,9 @@ define i64 @sdiv64(i64 %x, i64 %y) {
 ; CHECK-LABEL: udiv64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.div_u $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.div_u $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @udiv64(i64 %x, i64 %y) {
   %a = udiv i64 %x, %y
@@ -62,7 +72,9 @@ define i64 @udiv64(i64 %x, i64 %y) {
 ; CHECK-LABEL: srem64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.rem_s $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.rem_s $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @srem64(i64 %x, i64 %y) {
   %a = srem i64 %x, %y
@@ -72,7 +84,9 @@ define i64 @srem64(i64 %x, i64 %y) {
 ; CHECK-LABEL: urem64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.rem_u $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.rem_u $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @urem64(i64 %x, i64 %y) {
   %a = urem i64 %x, %y
@@ -82,7 +96,9 @@ define i64 @urem64(i64 %x, i64 %y) {
 ; CHECK-LABEL: and64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.and $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.and $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @and64(i64 %x, i64 %y) {
   %a = and i64 %x, %y
@@ -92,7 +108,9 @@ define i64 @and64(i64 %x, i64 %y) {
 ; CHECK-LABEL: or64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.or $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.or $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @or64(i64 %x, i64 %y) {
   %a = or i64 %x, %y
@@ -102,7 +120,9 @@ define i64 @or64(i64 %x, i64 %y) {
 ; CHECK-LABEL: xor64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.xor $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.xor $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @xor64(i64 %x, i64 %y) {
   %a = xor i64 %x, %y
@@ -112,7 +132,9 @@ define i64 @xor64(i64 %x, i64 %y) {
 ; CHECK-LABEL: shl64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.shl $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.shl $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @shl64(i64 %x, i64 %y) {
   %a = shl i64 %x, %y
@@ -122,7 +144,9 @@ define i64 @shl64(i64 %x, i64 %y) {
 ; CHECK-LABEL: shr64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.shr_u $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.shr_u $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @shr64(i64 %x, i64 %y) {
   %a = lshr i64 %x, %y
@@ -132,7 +156,9 @@ define i64 @shr64(i64 %x, i64 %y) {
 ; CHECK-LABEL: sar64:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.shr_s $push0=, $0, $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.shr_s $push0=, $pop[[L0]], $pop[[L1]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @sar64(i64 %x, i64 %y) {
   %a = ashr i64 %x, %y
@@ -142,7 +168,8 @@ define i64 @sar64(i64 %x, i64 %y) {
 ; CHECK-LABEL: clz64:
 ; CHECK-NEXT: .param i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.clz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.clz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @clz64(i64 %x) {
   %a = call i64 @llvm.ctlz.i64(i64 %x, i1 false)
@@ -152,7 +179,8 @@ define i64 @clz64(i64 %x) {
 ; CHECK-LABEL: clz64_zero_undef:
 ; CHECK-NEXT: .param i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.clz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.clz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @clz64_zero_undef(i64 %x) {
   %a = call i64 @llvm.ctlz.i64(i64 %x, i1 true)
@@ -162,7 +190,8 @@ define i64 @clz64_zero_undef(i64 %x) {
 ; CHECK-LABEL: ctz64:
 ; CHECK-NEXT: .param i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.ctz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.ctz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @ctz64(i64 %x) {
   %a = call i64 @llvm.cttz.i64(i64 %x, i1 false)
@@ -172,7 +201,8 @@ define i64 @ctz64(i64 %x) {
 ; CHECK-LABEL: ctz64_zero_undef:
 ; CHECK-NEXT: .param i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.ctz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.ctz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @ctz64_zero_undef(i64 %x) {
   %a = call i64 @llvm.cttz.i64(i64 %x, i1 true)
@@ -182,7 +212,8 @@ define i64 @ctz64_zero_undef(i64 %x) {
 ; CHECK-LABEL: popcnt64:
 ; CHECK-NEXT: .param i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.popcnt $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.popcnt $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @popcnt64(i64 %x) {
   %a = call i64 @llvm.ctpop.i64(i64 %x)
@@ -192,7 +223,8 @@ define i64 @popcnt64(i64 %x) {
 ; CHECK-LABEL: eqz64:
 ; CHECK-NEXT: .param i64{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i64.eqz $push0=, $0{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.eqz $push0=, $pop[[L0]]{{$}}
 ; CHECK-NEXT: return $pop0{{$}}
 define i32 @eqz64(i64 %x) {
   %a = icmp eq i64 %x, 0
@@ -203,7 +235,9 @@ define i32 @eqz64(i64 %x) {
 ; CHECK-LABEL: rotl:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.rotl $push0=, $0, $1
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.rotl $push0=, $pop[[L0]], $pop[[L1]]
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @rotl(i64 %x, i64 %y) {
   %z = sub i64 64, %y
@@ -216,7 +250,9 @@ define i64 @rotl(i64 %x, i64 %y) {
 ; CHECK-LABEL: masked_rotl:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.rotl $push0=, $0, $1
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.rotl $push0=, $pop[[L0]], $pop[[L1]]
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @masked_rotl(i64 %x, i64 %y) {
   %a = and i64 %y, 63
@@ -230,7 +266,9 @@ define i64 @masked_rotl(i64 %x, i64 %y)
 ; CHECK-LABEL: rotr:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.rotr $push0=, $0, $1
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.rotr $push0=, $pop[[L0]], $pop[[L1]]
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @rotr(i64 %x, i64 %y) {
   %z = sub i64 64, %y
@@ -243,7 +281,9 @@ define i64 @rotr(i64 %x, i64 %y) {
 ; CHECK-LABEL: masked_rotr:
 ; CHECK-NEXT: .param i64, i64{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.rotr $push0=, $0, $1
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.rotr $push0=, $pop[[L0]], $pop[[L1]]
 ; CHECK-NEXT: return $pop0{{$}}
 define i64 @masked_rotr(i64 %x, i64 %y) {
   %a = and i64 %y, 63

Modified: llvm/trunk/test/CodeGen/WebAssembly/ident.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/ident.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/ident.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/ident.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test llvm.ident.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK: .ident "hello world"
 

Modified: llvm/trunk/test/CodeGen/WebAssembly/immediates.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/immediates.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/immediates.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/immediates.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test that basic immediates assemble as expected.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-LABEL: zero_i32:
 ; CHECK-NEXT: .result i32{{$}}

Modified: llvm/trunk/test/CodeGen/WebAssembly/implicit-def.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/implicit-def.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/implicit-def.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/implicit-def.ll Fri Feb 24 17:18:00 2017
@@ -1,6 +1,6 @@
 ; RUN: llc -o - %s | FileCheck %s
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; Test that stackified IMPLICIT_DEF instructions are converted into
 ; CONST_I32 to provide an explicit push.

Modified: llvm/trunk/test/CodeGen/WebAssembly/load.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/load.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/load.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/load.ll Fri Feb 24 17:18:00 2017
@@ -4,12 +4,13 @@
 ; Test that basic loads are assembled properly.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-LABEL: ldi32:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i32{{$}}
-; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i32.load $push[[NUM:[0-9]+]]=, 0($pop[[L0]]){{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i32 @ldi32(i32 *%p) {
   %v = load i32, i32* %p
@@ -19,7 +20,8 @@ define i32 @ldi32(i32 *%p) {
 ; CHECK-LABEL: ldi64:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result i64{{$}}
-; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: i64.load $push[[NUM:[0-9]+]]=, 0($pop[[L0]]){{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define i64 @ldi64(i64 *%p) {
   %v = load i64, i64* %p
@@ -29,7 +31,8 @@ define i64 @ldi64(i64 *%p) {
 ; CHECK-LABEL: ldf32:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result f32{{$}}
-; CHECK-NEXT: f32.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f32.load $push[[NUM:[0-9]+]]=, 0($pop[[L0]]){{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define float @ldf32(float *%p) {
   %v = load float, float* %p
@@ -39,7 +42,8 @@ define float @ldf32(float *%p) {
 ; CHECK-LABEL: ldf64:
 ; CHECK-NEXT: .param i32{{$}}
 ; CHECK-NEXT: .result f64{{$}}
-; CHECK-NEXT: f64.load $push[[NUM:[0-9]+]]=, 0($0){{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: f64.load $push[[NUM:[0-9]+]]=, 0($pop[[L0]]){{$}}
 ; CHECK-NEXT: return $pop[[NUM]]{{$}}
 define double @ldf64(double *%p) {
   %v = load double, double* %p

Modified: llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-ehsjlj-options.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; RUN: llc < %s | FileCheck %s --check-prefix=NONE
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 %struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
 

Modified: llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions-whitelist.ll Fri Feb 24 17:18:00 2017
@@ -1,7 +1,7 @@
 ; RUN: opt < %s -wasm-lower-em-ehsjlj -emscripten-cxx-exceptions-whitelist=do_catch -S | FileCheck %s
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 define void @dont_catch() personality i8* bitcast (i32 (...)* @__gxx_personality_v0 to i8*) {
 ; CHECK-LABEL: @dont_catch(

Modified: llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-exceptions.ll Fri Feb 24 17:18:00 2017
@@ -1,7 +1,7 @@
 ; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 @_ZTIi = external constant i8*
 @_ZTIc = external constant i8*

Modified: llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/lower-em-sjlj.ll Fri Feb 24 17:18:00 2017
@@ -1,7 +1,7 @@
 ; RUN: opt < %s -wasm-lower-em-ehsjlj -S | FileCheck %s
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 %struct.__jmp_buf_tag = type { [6 x i32], i32, [32 x i32] }
 

Modified: llvm/trunk/test/CodeGen/WebAssembly/non-executable-stack.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/non-executable-stack.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/non-executable-stack.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/non-executable-stack.ll Fri Feb 24 17:18:00 2017
@@ -4,6 +4,6 @@
 ; because wasm's stack is always non-executable.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-NOT: .note.GNU-stack

Modified: llvm/trunk/test/CodeGen/WebAssembly/offset-folding.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/offset-folding.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/offset-folding.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/offset-folding.ll Fri Feb 24 17:18:00 2017
@@ -3,7 +3,7 @@
 ; Test that constant offsets can be folded into global addresses.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 @x = external global [0 x i32]
 @y = global [50 x i32] zeroinitializer

Modified: llvm/trunk/test/CodeGen/WebAssembly/store.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/store.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/store.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/store.ll Fri Feb 24 17:18:00 2017
@@ -4,11 +4,13 @@
 ; Test that basic stores are assembled properly.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 ; CHECK-LABEL: sti32:
 ; CHECK-NEXT: .param i32, i32{{$}}
-; CHECK-NEXT: i32.store 0($0), $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i32.store 0($pop[[L0]]), $pop[[L1]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @sti32(i32 *%p, i32 %v) {
   store i32 %v, i32* %p
@@ -17,7 +19,9 @@ define void @sti32(i32 *%p, i32 %v) {
 
 ; CHECK-LABEL: sti64:
 ; CHECK-NEXT: .param i32, i64{{$}}
-; CHECK-NEXT: i64.store 0($0), $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: i64.store 0($pop[[L0]]), $pop[[L1]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @sti64(i64 *%p, i64 %v) {
   store i64 %v, i64* %p
@@ -26,7 +30,9 @@ define void @sti64(i64 *%p, i64 %v) {
 
 ; CHECK-LABEL: stf32:
 ; CHECK-NEXT: .param i32, f32{{$}}
-; CHECK-NEXT: f32.store 0($0), $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f32.store 0($pop[[L0]]), $pop[[L1]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @stf32(float *%p, float %v) {
   store float %v, float* %p
@@ -35,7 +41,9 @@ define void @stf32(float *%p, float %v)
 
 ; CHECK-LABEL: stf64:
 ; CHECK-NEXT: .param i32, f64{{$}}
-; CHECK-NEXT: f64.store 0($0), $1{{$}}
+; CHECK-NEXT: get_local $push[[L0:[0-9]+]]=, 0{{$}}
+; CHECK-NEXT: get_local $push[[L1:[0-9]+]]=, 1{{$}}
+; CHECK-NEXT: f64.store 0($pop[[L0]]), $pop[[L1]]{{$}}
 ; CHECK-NEXT: return{{$}}
 define void @stf64(double *%p, double %v) {
   store double %v, double* %p

Modified: llvm/trunk/test/CodeGen/WebAssembly/switch.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/switch.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/switch.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/switch.ll Fri Feb 24 17:18:00 2017
@@ -4,7 +4,7 @@
 ; the blocks in a way that isn't interesting here.
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare void @foo0()
 declare void @foo1()

Modified: llvm/trunk/test/CodeGen/WebAssembly/unreachable.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/WebAssembly/unreachable.ll?rev=296190&r1=296189&r2=296190&view=diff
==============================================================================
--- llvm/trunk/test/CodeGen/WebAssembly/unreachable.ll (original)
+++ llvm/trunk/test/CodeGen/WebAssembly/unreachable.ll Fri Feb 24 17:18:00 2017
@@ -5,7 +5,7 @@
 ; wasm unreachable
 
 target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128"
-target triple = "wasm32-unknown-unknown"
+target triple = "wasm32-unknown-unknown-wasm"
 
 declare void @llvm.trap()
 declare void @llvm.debugtrap()




More information about the llvm-commits mailing list