Subzero. WASM. Additional progress.

This change includes a number of improvements since the last WASM
CL. It compiles against a newer version of V8 that matches the current
WASM binary format. Many more WASM instructions are supported, as well
as global variable initializers.

There is also the beginning of a runtime library that implements some
system calls required by the WASM C library. The c2wasm-exe.sh script
can be used to compile a C program to a .wasm module, which is then
compiled by Subzero into a native executable.

This change includes a new Breakpoint instruction, which inserts an
unconditional breakpoint into the executable. This has been helpful in
debugging code generation for some WASM instructions. The Breakpoint
instruction is only completely implemented on X86.

BUG= https://bugs.chromium.org/p/nativeclient/issues/detail?id=4369
R=stichnot@chromium.org

Review URL: https://codereview.chromium.org/1876413002 .
diff --git a/src/IceCfg.cpp b/src/IceCfg.cpp
index bb738a7..285b489 100644
--- a/src/IceCfg.cpp
+++ b/src/IceCfg.cpp
@@ -599,6 +599,7 @@
   TimerMarker _(TimerStack::TT_alloca, this);
   const uint32_t StackAlignment = getTarget()->getStackAlignment();
   CfgNode *EntryNode = getEntryNode();
+  assert(EntryNode);
   // LLVM enforces power of 2 alignment.
   assert(llvm::isPowerOf2_32(StackAlignment));
   // Determine if there are large alignment allocations in the entry block or
diff --git a/src/IceInst.cpp b/src/IceInst.cpp
index 1265d58..aac42c3 100644
--- a/src/IceInst.cpp
+++ b/src/IceInst.cpp
@@ -105,6 +105,7 @@
     X(Store, "store");
     X(Switch, "switch");
     X(Assign, "assign");
+    X(Breakpoint, "break");
     X(BundleLock, "bundlelock");
     X(BundleUnlock, "bundleunlock");
     X(FakeDef, "fakedef");
@@ -516,8 +517,10 @@
 NodeList InstSwitch::getTerminatorEdges() const {
   NodeList OutEdges;
   OutEdges.reserve(NumCases + 1);
+  assert(LabelDefault);
   OutEdges.push_back(LabelDefault);
   for (SizeT I = 0; I < NumCases; ++I) {
+    assert(Labels[I]);
     OutEdges.push_back(Labels[I]);
   }
   std::sort(OutEdges.begin(), OutEdges.end(),
@@ -1047,6 +1050,9 @@
   Inst::dump(Func);
 }
 
+InstBreakpoint::InstBreakpoint(Cfg *Func)
+    : InstHighLevel(Func, Inst::Breakpoint, 0, nullptr) {}
+
 bool checkForRedundantAssign(const Variable *Dest, const Operand *Source) {
   const auto *SrcVar = llvm::dyn_cast<const Variable>(Source);
   if (!SrcVar)
diff --git a/src/IceInst.h b/src/IceInst.h
index 1b49419..db273aa 100644
--- a/src/IceInst.h
+++ b/src/IceInst.h
@@ -62,6 +62,7 @@
     Store,
     Switch,
     Assign,       // not part of LLVM/PNaCl bitcode
+    Breakpoint,   // not part of LLVM/PNaCl bitcode
     BundleLock,   // not part of LLVM/PNaCl bitcode
     BundleUnlock, // not part of LLVM/PNaCl bitcode
     FakeDef,      // not part of LLVM/PNaCl bitcode
@@ -976,6 +977,29 @@
   GlobalString FuncName;
 };
 
+/// This instruction inserts an unconditional breakpoint.
+///
+/// On x86, this assembles into an INT 3 instruction.
+///
+/// This instruction is primarily meant for debugging the code generator.
+class InstBreakpoint : public InstHighLevel {
+public:
+  InstBreakpoint() = delete;
+  InstBreakpoint(const InstBreakpoint &) = delete;
+  InstBreakpoint &operator=(const InstBreakpoint &) = delete;
+
+  InstBreakpoint(Cfg *Func);
+
+public:
+  static InstBreakpoint *create(Cfg *Func) {
+    return new (Func->allocate<InstBreakpoint>()) InstBreakpoint(Func);
+  }
+
+  static bool classof(const Inst *Instr) {
+    return Instr->getKind() == Breakpoint;
+  }
+};
+
 /// The Target instruction is the base class for all target-specific
 /// instructions.
 class InstTarget : public Inst {
diff --git a/src/IceInstX86Base.h b/src/IceInstX86Base.h
index 761d412..1c2e8e6 100644
--- a/src/IceInstX86Base.h
+++ b/src/IceInstX86Base.h
@@ -107,6 +107,7 @@
       Imul,
       ImulImm,
       Insertps,
+      Int3,
       Jmp,
       Label,
       Lea,
@@ -2442,6 +2443,27 @@
     explicit InstX86UD2(Cfg *Func);
   };
 
+  /// Int3 instruction.
+  class InstX86Int3 final : public InstX86Base {
+    InstX86Int3() = delete;
+    InstX86Int3(const InstX86Int3 &) = delete;
+    InstX86Int3 &operator=(const InstX86Int3 &) = delete;
+
+  public:
+    static InstX86Int3 *create(Cfg *Func) {
+      return new (Func->allocate<InstX86Int3>()) InstX86Int3(Func);
+    }
+    void emit(const Cfg *Func) const override;
+    void emitIAS(const Cfg *Func) const override;
+    void dump(const Cfg *Func) const override;
+    static bool classof(const Inst *Instr) {
+      return InstX86Base::isClassof(Instr, InstX86Base::Int3);
+    }
+
+  private:
+    explicit InstX86Int3(Cfg *Func);
+  };
+
   /// Test instruction.
   class InstX86Test final : public InstX86Base {
     InstX86Test() = delete;
@@ -2914,6 +2936,7 @@
   using Icmp = typename InstImpl<TraitsType>::InstX86Icmp;
   using Ucomiss = typename InstImpl<TraitsType>::InstX86Ucomiss;
   using UD2 = typename InstImpl<TraitsType>::InstX86UD2;
+  using Int3 = typename InstImpl<TraitsType>::InstX86Int3;
   using Test = typename InstImpl<TraitsType>::InstX86Test;
   using Mfence = typename InstImpl<TraitsType>::InstX86Mfence;
   using Store = typename InstImpl<TraitsType>::InstX86Store;
diff --git a/src/IceInstX86BaseImpl.h b/src/IceInstX86BaseImpl.h
index b9ebf51..bc5811e 100644
--- a/src/IceInstX86BaseImpl.h
+++ b/src/IceInstX86BaseImpl.h
@@ -263,6 +263,10 @@
     : InstX86Base(Func, InstX86Base::UD2, 0, nullptr) {}
 
 template <typename TraitsType>
+InstImpl<TraitsType>::InstX86Int3::InstX86Int3(Cfg *Func)
+    : InstX86Base(Func, InstX86Base::Int3, 0, nullptr) {}
+
+template <typename TraitsType>
 InstImpl<TraitsType>::InstX86Test::InstX86Test(Cfg *Func, Operand *Src1,
                                                Operand *Src2)
     : InstX86Base(Func, InstX86Base::Test, 2, nullptr) {
@@ -1780,6 +1784,30 @@
 }
 
 template <typename TraitsType>
+void InstImpl<TraitsType>::InstX86Int3::emit(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrEmit();
+  assert(this->getSrcSize() == 0);
+  Str << "\t"
+         "int 3";
+}
+
+template <typename TraitsType>
+void InstImpl<TraitsType>::InstX86Int3::emitIAS(const Cfg *Func) const {
+  Assembler *Asm = Func->getAssembler<Assembler>();
+  Asm->int3();
+}
+
+template <typename TraitsType>
+void InstImpl<TraitsType>::InstX86Int3::dump(const Cfg *Func) const {
+  if (!BuildDefs::dump())
+    return;
+  Ostream &Str = Func->getContext()->getStrDump();
+  Str << "int 3";
+}
+
+template <typename TraitsType>
 void InstImpl<TraitsType>::InstX86Test::emit(const Cfg *Func) const {
   if (!BuildDefs::dump())
     return;
diff --git a/src/IceTargetLowering.cpp b/src/IceTargetLowering.cpp
index 29fbc7b..496845c 100644
--- a/src/IceTargetLowering.cpp
+++ b/src/IceTargetLowering.cpp
@@ -400,6 +400,9 @@
     case Inst::Br:
       lowerBr(llvm::cast<InstBr>(Instr));
       break;
+    case Inst::Breakpoint:
+      lowerBreakpoint(llvm::cast<InstBreakpoint>(Instr));
+      break;
     case Inst::Call:
       lowerCall(llvm::cast<InstCall>(Instr));
       break;
diff --git a/src/IceTargetLowering.h b/src/IceTargetLowering.h
index 37bf127..abf6987 100644
--- a/src/IceTargetLowering.h
+++ b/src/IceTargetLowering.h
@@ -375,6 +375,7 @@
   virtual void lowerArithmetic(const InstArithmetic *Instr) = 0;
   virtual void lowerAssign(const InstAssign *Instr) = 0;
   virtual void lowerBr(const InstBr *Instr) = 0;
+  virtual void lowerBreakpoint(const InstBreakpoint *Instr) = 0;
   virtual void lowerCall(const InstCall *Instr) = 0;
   virtual void lowerCast(const InstCast *Instr) = 0;
   virtual void lowerFcmp(const InstFcmp *Instr) = 0;
diff --git a/src/IceTargetLoweringARM32.cpp b/src/IceTargetLoweringARM32.cpp
index 3de321e..8c0aca6 100644
--- a/src/IceTargetLoweringARM32.cpp
+++ b/src/IceTargetLoweringARM32.cpp
@@ -5818,6 +5818,10 @@
   _br(Instr->getLabelDefault());
 }
 
+void TargetARM32::lowerBreakpoint(const InstBreakpoint *Instr) {
+  UnimplementedLoweringError(this, Instr);
+}
+
 void TargetARM32::lowerUnreachable(const InstUnreachable * /*Instr*/) {
   _trap();
 }
diff --git a/src/IceTargetLoweringARM32.h b/src/IceTargetLoweringARM32.h
index 2cfa945..408db29 100644
--- a/src/IceTargetLoweringARM32.h
+++ b/src/IceTargetLoweringARM32.h
@@ -278,6 +278,7 @@
                            Operand *Val);
   void lowerAtomicRMW(Variable *Dest, uint32_t Operation, Operand *Ptr,
                       Operand *Val);
+  void lowerBreakpoint(const InstBreakpoint *Instr) override;
   void lowerIntrinsicCall(const InstIntrinsicCall *Instr) override;
   void lowerInsertElement(const InstInsertElement *Instr) override;
   void lowerLoad(const InstLoad *Instr) override;
diff --git a/src/IceTargetLoweringMIPS32.cpp b/src/IceTargetLoweringMIPS32.cpp
index 8b12f88..238b7bb 100644
--- a/src/IceTargetLoweringMIPS32.cpp
+++ b/src/IceTargetLoweringMIPS32.cpp
@@ -1155,6 +1155,10 @@
   UnimplementedLoweringError(this, Instr);
 }
 
+void TargetMIPS32::lowerBreakpoint(const InstBreakpoint *Instr) {
+  UnimplementedLoweringError(this, Instr);
+}
+
 void TargetMIPS32::lowerUnreachable(const InstUnreachable *Instr) {
   UnimplementedLoweringError(this, Instr);
 }
diff --git a/src/IceTargetLoweringMIPS32.h b/src/IceTargetLoweringMIPS32.h
index 3216058..ea062e7 100644
--- a/src/IceTargetLoweringMIPS32.h
+++ b/src/IceTargetLoweringMIPS32.h
@@ -287,6 +287,7 @@
                             Operand *Src0, Operand *Src1);
   void lowerAssign(const InstAssign *Instr) override;
   void lowerBr(const InstBr *Instr) override;
+  void lowerBreakpoint(const InstBreakpoint *Instr) override;
   void lowerCall(const InstCall *Instr) override;
   void lowerCast(const InstCast *Instr) override;
   void lowerExtractElement(const InstExtractElement *Instr) override;
diff --git a/src/IceTargetLoweringX86Base.h b/src/IceTargetLoweringX86Base.h
index 1014493..7aeb933 100644
--- a/src/IceTargetLoweringX86Base.h
+++ b/src/IceTargetLoweringX86Base.h
@@ -247,6 +247,7 @@
   void lowerArithmetic(const InstArithmetic *Instr) override;
   void lowerAssign(const InstAssign *Instr) override;
   void lowerBr(const InstBr *Instr) override;
+  void lowerBreakpoint(const InstBreakpoint *Instr) override;
   void lowerCall(const InstCall *Instr) override;
   void lowerCast(const InstCast *Instr) override;
   void lowerExtractElement(const InstExtractElement *Instr) override;
@@ -656,6 +657,7 @@
     AutoMemorySandboxer<> _(this, &Dest, &Src0, &Src1);
     Context.insert<typename Traits::Insts::Insertps>(Dest, Src0, Src1);
   }
+  void _int3() { Context.insert<typename Traits::Insts::Int3>(); }
   void _jmp(Operand *Target) {
     AutoMemorySandboxer<> _(this, &Target);
     Context.insert<typename Traits::Insts::Jmp>(Target);
diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
index 0bf03eb..38cef5f 100644
--- a/src/IceTargetLoweringX86BaseImpl.h
+++ b/src/IceTargetLoweringX86BaseImpl.h
@@ -6096,6 +6096,12 @@
 }
 
 template <typename TraitsType>
+void TargetX86Base<TraitsType>::lowerBreakpoint(
+    const InstBreakpoint * /*Instr*/) {
+  _int3();
+}
+
+template <typename TraitsType>
 void TargetX86Base<TraitsType>::lowerRMW(const InstX86FakeRMW *RMW) {
   // If the beacon variable's live range does not end in this instruction, then
   // it must end in the modified Store instruction that follows. This means
diff --git a/src/WasmTranslator.cpp b/src/WasmTranslator.cpp
index b42ad77..6c1ed24 100644
--- a/src/WasmTranslator.cpp
+++ b/src/WasmTranslator.cpp
@@ -17,14 +17,33 @@
 
 #if ALLOW_WASM
 
-#include "llvm/Support/StreamingMemoryObject.h"
-
 #include "WasmTranslator.h"
 
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wcovered-switch-default"
+#endif // __clang__
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif // defined(__GNUC__) && !defined(__clang__)
+
 #include "src/wasm/module-decoder.h"
 #include "src/wasm/wasm-opcodes.h"
 #include "src/zone.h"
 
+#include "src/bit-vector.h"
+
+#include "src/wasm/ast-decoder-impl.h"
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif // __clang__
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif // defined(__GNUC__) && !defined(__clang__)
+
 #include "IceCfgNode.h"
 #include "IceGlobalInits.h"
 
@@ -35,21 +54,17 @@
 using namespace v8::internal::wasm;
 using v8::internal::wasm::DecodeWasmModule;
 
-#include "src/wasm/ast-decoder-impl.h"
-
+#undef LOG
 #define LOG(Expr) log([&](Ostream & out) { Expr; })
 
 namespace {
 
-Ice::Type toIceType(v8::internal::MachineType) {
-  // TODO(eholk): actually convert this.
-  return IceType_i32;
+std::string toStdString(WasmName Name) {
+  return std::string(Name.name, Name.length);
 }
 
 Ice::Type toIceType(wasm::LocalType Type) {
   switch (Type) {
-  default:
-    llvm::report_fatal_error("unexpected enum value");
   case MachineRepresentation::kNone:
     llvm::report_fatal_error("kNone type not supported");
   case MachineRepresentation::kBit:
@@ -71,6 +86,57 @@
   case MachineRepresentation::kTagged:
     llvm::report_fatal_error("kTagged type not supported");
   }
+  llvm::report_fatal_error("unexpected type");
+}
+
+Ice::Type toIceType(v8::internal::MachineType Type) {
+  // TODO (eholk): reorder these based on expected call frequency.
+  if (Type == MachineType::Int32()) {
+    return IceType_i32;
+  }
+  if (Type == MachineType::Uint32()) {
+    return IceType_i32;
+  }
+  if (Type == MachineType::Int8()) {
+    return IceType_i8;
+  }
+  if (Type == MachineType::Uint8()) {
+    return IceType_i8;
+  }
+  if (Type == MachineType::Int16()) {
+    return IceType_i16;
+  }
+  if (Type == MachineType::Uint16()) {
+    return IceType_i16;
+  }
+  if (Type == MachineType::Int64()) {
+    return IceType_i64;
+  }
+  if (Type == MachineType::Uint64()) {
+    return IceType_i64;
+  }
+  if (Type == MachineType::Float32()) {
+    return IceType_f32;
+  }
+  if (Type == MachineType::Float64()) {
+    return IceType_f64;
+  }
+  llvm::report_fatal_error("Unsupported MachineType");
+}
+
+std::string fnNameFromId(uint32_t Id) {
+  return std::string("fn") + to_string(Id);
+}
+
+std::string getFunctionName(const WasmModule *Module, uint32_t func_index) {
+  // Try to find the function name in the export table
+  for (const auto Export : Module->export_table) {
+    if (Export.func_index == func_index) {
+      return "__szwasm_" + toStdString(Module->GetName(Export.name_offset,
+                                                       Export.name_length));
+    }
+  }
+  return fnNameFromId(func_index);
 }
 
 } // end of anonymous namespace
@@ -132,7 +198,11 @@
 
 Ostream &operator<<(Ostream &Out, const OperandNode &Op) {
   if (Op.isOperand()) {
-    Out << "(Operand*)" << Op.toOperand();
+    const auto *Oper = Op.toOperand();
+    Out << "(Operand*)" << Oper;
+    if (Oper) {
+      Out << "::" << Oper->getType();
+    }
   } else if (Op.isCfgNode()) {
     Out << "(CfgNode*)" << Op.toCfgNode();
   } else {
@@ -141,7 +211,7 @@
   return Out;
 }
 
-constexpr bool isComparison(wasm::WasmOpcode Opcode) {
+bool isComparison(wasm::WasmOpcode Opcode) {
   switch (Opcode) {
   case kExprI32Ne:
   case kExprI64Ne:
@@ -157,6 +227,16 @@
   case kExprI64GtS:
   case kExprI32GtU:
   case kExprI64GtU:
+  case kExprF32Ne:
+  case kExprF64Ne:
+  case kExprF32Le:
+  case kExprF64Le:
+  case kExprI32LeS:
+  case kExprI64LeS:
+  case kExprI32GeU:
+  case kExprI64GeU:
+  case kExprI32LeU:
+  case kExprI64LeU:
     return true;
   default:
     return false;
@@ -172,7 +252,7 @@
 
 public:
   explicit IceBuilder(class Cfg *Func)
-      : Func(Func), Ctx(Func->getContext()), ControlPtr(nullptr) {}
+      : ControlPtr(nullptr), Func(Func), Ctx(Func->getContext()) {}
 
   /// Allocates a buffer of Nodes for use by V8.
   Node *Buffer(size_t Count) {
@@ -181,14 +261,14 @@
   }
 
   Node Error() { llvm::report_fatal_error("Error"); }
-  Node Start(unsigned Params) {
+  Node Start(uint32_t Params) {
     LOG(out << "Start(" << Params << ") = ");
-    auto *Entry = Func->makeNode();
-    Func->setEntryNode(Entry);
+    auto *Entry = Func->getEntryNode();
+    assert(Entry);
     LOG(out << Node(Entry) << "\n");
     return OperandNode(Entry);
   }
-  Node Param(unsigned Index, wasm::LocalType Type) {
+  Node Param(uint32_t Index, wasm::LocalType Type) {
     LOG(out << "Param(" << Index << ") = ");
     auto *Arg = makeVariable(toIceType(Type));
     assert(Index == NextArg);
@@ -208,25 +288,25 @@
     LOG(out << "Terminate(" << Effect << ", " << Control << ")"
             << "\n");
   }
-  Node Merge(unsigned Count, Node *Controls) {
+  Node Merge(uint32_t Count, Node *Controls) {
     LOG(out << "Merge(" << Count);
-    for (unsigned i = 0; i < Count; ++i) {
+    for (uint32_t i = 0; i < Count; ++i) {
       LOG(out << ", " << Controls[i]);
     }
     LOG(out << ") = ");
 
     auto *MergedNode = Func->makeNode();
 
-    for (unsigned i = 0; i < Count; ++i) {
+    for (uint32_t i = 0; i < Count; ++i) {
       CfgNode *Control = Controls[i];
       Control->appendInst(InstBr::create(Func, MergedNode));
     }
     LOG(out << (OperandNode)MergedNode << "\n");
     return OperandNode(MergedNode);
   }
-  Node Phi(wasm::LocalType Type, unsigned Count, Node *Vals, Node Control) {
+  Node Phi(wasm::LocalType, uint32_t Count, Node *Vals, Node Control) {
     LOG(out << "Phi(" << Count << ", " << Control);
-    for (int i = 0; i < Count; ++i) {
+    for (uint32_t i = 0; i < Count; ++i) {
       LOG(out << ", " << Vals[i]);
     }
     LOG(out << ") = ");
@@ -243,7 +323,7 @@
     // TODO(eholk): find a better way besides multiplying by some arbitrary
     // constant.
     auto *Phi = InstPhi::create(Func, Count * 10, Dest);
-    for (int i = 0; i < Count; ++i) {
+    for (uint32_t i = 0; i < Count; ++i) {
       auto *Op = Vals[i].toOperand();
       assert(Op);
       Phi->addArgument(Op, InEdges[i]);
@@ -253,10 +333,10 @@
     LOG(out << Node(Dest) << "\n");
     return OperandNode(Dest);
   }
-  Node EffectPhi(unsigned Count, Node *Effects, Node Control) {
+  Node EffectPhi(uint32_t Count, Node *Effects, Node Control) {
     // TODO(eholk): this function is almost certainly wrong.
     LOG(out << "EffectPhi(" << Count << ", " << Control << "):\n");
-    for (unsigned i = 0; i < Count; ++i) {
+    for (uint32_t i = 0; i < Count; ++i) {
       LOG(out << "  " << Effects[i] << "\n");
     }
     return OperandNode(nullptr);
@@ -294,13 +374,18 @@
     LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left
             << ", " << Right << ") = ");
     auto *Dest = makeVariable(
-        isComparison(Opcode) ? IceType_i1 : Left.toOperand()->getType());
+        isComparison(Opcode) ? IceType_i32 : Left.toOperand()->getType());
     switch (Opcode) {
     case kExprI32Add:
     case kExprI64Add:
       Control()->appendInst(
           InstArithmetic::create(Func, InstArithmetic::Add, Dest, Left, Right));
       break;
+    case kExprF32Add:
+    case kExprF64Add:
+      Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Fadd,
+                                                   Dest, Left, Right));
+      break;
     case kExprI32Sub:
     case kExprI64Sub:
       Control()->appendInst(
@@ -321,6 +406,11 @@
       Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Urem,
                                                    Dest, Left, Right));
       break;
+    case kExprI32RemS:
+    case kExprI64RemS:
+      Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Srem,
+                                                   Dest, Left, Right));
+      break;
     case kExprI32Ior:
     case kExprI64Ior:
       Control()->appendInst(
@@ -336,6 +426,28 @@
       Control()->appendInst(
           InstArithmetic::create(Func, InstArithmetic::Shl, Dest, Left, Right));
       break;
+    case kExprI32Rol: {
+      // TODO(eholk): add rotate as an ICE instruction to make it easier to take
+      // advantage of hardware support.
+
+      // TODO(eholk): don't hardcode so many numbers.
+      auto *Masked = makeVariable(IceType_i32);
+      auto *Bottom = makeVariable(IceType_i32);
+      auto *Top = makeVariable(IceType_i32);
+      Control()->appendInst(InstArithmetic::create(
+          Func, InstArithmetic::And, Masked, Right, Ctx->getConstantInt32(31)));
+      Control()->appendInst(
+          InstArithmetic::create(Func, InstArithmetic::Shl, Top, Left, Masked));
+      auto *RotShift = makeVariable(IceType_i32);
+      Control()->appendInst(
+          InstArithmetic::create(Func, InstArithmetic::Sub, RotShift,
+                                 Ctx->getConstantInt32(32), Masked));
+      Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Lshr,
+                                                   Bottom, Left, Masked));
+      Control()->appendInst(
+          InstArithmetic::create(Func, InstArithmetic::Or, Dest, Top, Bottom));
+      break;
+    }
     case kExprI32ShrU:
     case kExprI64ShrU:
     case kExprI32ShrS:
@@ -349,39 +461,112 @@
           InstArithmetic::create(Func, InstArithmetic::And, Dest, Left, Right));
       break;
     case kExprI32Ne:
-    case kExprI64Ne:
+    case kExprI64Ne: {
+      auto *TmpDest = makeVariable(IceType_i1);
       Control()->appendInst(
-          InstIcmp::create(Func, InstIcmp::Ne, Dest, Left, Right));
+          InstIcmp::create(Func, InstIcmp::Ne, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
       break;
+    }
     case kExprI32Eq:
-    case kExprI64Eq:
+    case kExprI64Eq: {
+      auto *TmpDest = makeVariable(IceType_i1);
       Control()->appendInst(
-          InstIcmp::create(Func, InstIcmp::Eq, Dest, Left, Right));
+          InstIcmp::create(Func, InstIcmp::Eq, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
       break;
+    }
     case kExprI32LtS:
-    case kExprI64LtS:
+    case kExprI64LtS: {
+      auto *TmpDest = makeVariable(IceType_i1);
       Control()->appendInst(
-          InstIcmp::create(Func, InstIcmp::Slt, Dest, Left, Right));
+          InstIcmp::create(Func, InstIcmp::Slt, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
       break;
+    }
+    case kExprI32LeS:
+    case kExprI64LeS: {
+      auto *TmpDest = makeVariable(IceType_i1);
+      Control()->appendInst(
+          InstIcmp::create(Func, InstIcmp::Sle, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+      break;
+    }
+    case kExprI32GeU:
+    case kExprI64GeU: {
+      auto *TmpDest = makeVariable(IceType_i1);
+      Control()->appendInst(
+          InstIcmp::create(Func, InstIcmp::Uge, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+      break;
+    }
+    case kExprI32LeU:
+    case kExprI64LeU: {
+      auto *TmpDest = makeVariable(IceType_i1);
+      Control()->appendInst(
+          InstIcmp::create(Func, InstIcmp::Ule, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+      break;
+    }
     case kExprI32LtU:
-    case kExprI64LtU:
+    case kExprI64LtU: {
+      auto *TmpDest = makeVariable(IceType_i1);
       Control()->appendInst(
-          InstIcmp::create(Func, InstIcmp::Ult, Dest, Left, Right));
+          InstIcmp::create(Func, InstIcmp::Ult, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
       break;
+    }
     case kExprI32GeS:
-    case kExprI64GeS:
+    case kExprI64GeS: {
+      auto *TmpDest = makeVariable(IceType_i1);
       Control()->appendInst(
-          InstIcmp::create(Func, InstIcmp::Sge, Dest, Left, Right));
+          InstIcmp::create(Func, InstIcmp::Sge, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+    }
     case kExprI32GtS:
-    case kExprI64GtS:
+    case kExprI64GtS: {
+      auto *TmpDest = makeVariable(IceType_i1);
       Control()->appendInst(
-          InstIcmp::create(Func, InstIcmp::Sgt, Dest, Left, Right));
+          InstIcmp::create(Func, InstIcmp::Sgt, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
       break;
+    }
     case kExprI32GtU:
-    case kExprI64GtU:
+    case kExprI64GtU: {
+      auto *TmpDest = makeVariable(IceType_i1);
       Control()->appendInst(
-          InstIcmp::create(Func, InstIcmp::Ugt, Dest, Left, Right));
+          InstIcmp::create(Func, InstIcmp::Ugt, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
       break;
+    }
+    case kExprF32Ne:
+    case kExprF64Ne: {
+      auto *TmpDest = makeVariable(IceType_i1);
+      Control()->appendInst(
+          InstFcmp::create(Func, InstFcmp::Une, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+      break;
+    }
+    case kExprF32Le:
+    case kExprF64Le: {
+      auto *TmpDest = makeVariable(IceType_i1);
+      Control()->appendInst(
+          InstFcmp::create(Func, InstFcmp::Ule, TmpDest, Left, Right));
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+      break;
+    }
     default:
       LOG(out << "Unknown binop: " << WasmOpcodes::OpcodeName(Opcode) << "\n");
       llvm::report_fatal_error("Uncovered or invalid binop.");
@@ -395,6 +580,14 @@
             << ") = ");
     Ice::Variable *Dest = nullptr;
     switch (Opcode) {
+    case kExprI32Eqz: {
+      Dest = makeVariable(IceType_i32);
+      auto *Tmp = makeVariable(IceType_i1);
+      Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input,
+                                             Ctx->getConstantInt32(0)));
+      Control()->appendInst(InstCast::create(Func, InstCast::Sext, Dest, Tmp));
+      break;
+    }
     case kExprF32Neg: {
       Dest = makeVariable(IceType_f32);
       Control()->appendInst(InstArithmetic::create(
@@ -412,6 +605,21 @@
       Control()->appendInst(
           InstCast::create(Func, InstCast::Zext, Dest, Input));
       break;
+    case kExprI64SConvertI32:
+      Dest = makeVariable(IceType_i64);
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sext, Dest, Input));
+      break;
+    case kExprI32ConvertI64:
+      Dest = makeVariable(IceType_i32);
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Trunc, Dest, Input));
+      break;
+    case kExprF64SConvertI32:
+      Dest = makeVariable(IceType_f64);
+      Control()->appendInst(
+          InstCast::create(Func, InstCast::Sitofp, Dest, Input));
+      break;
     default:
       LOG(out << "Unknown unop: " << WasmOpcodes::OpcodeName(Opcode) << "\n");
       llvm::report_fatal_error("Uncovered or invalid unop.");
@@ -420,14 +628,14 @@
     LOG(out << Dest << "\n");
     return OperandNode(Dest);
   }
-  unsigned InputCount(CfgNode *Node) const { return Node->getInEdges().size(); }
+  uint32_t InputCount(CfgNode *Node) const { return Node->getInEdges().size(); }
   bool IsPhiWithMerge(Node Phi, Node Merge) const {
     LOG(out << "IsPhiWithMerge(" << Phi << ", " << Merge << ")"
             << "\n");
     if (Phi && Phi.isOperand()) {
       LOG(out << "  ...is operand"
               << "\n");
-      if (auto *Inst = getDefiningInst(Phi)) {
+      if (getDefiningInst(Phi)) {
         LOG(out << "  ...has defining instruction"
                 << "\n");
         LOG(out << getDefNode(Phi) << "\n");
@@ -444,6 +652,7 @@
     LOG(out << "AppendToPhi(" << Merge << ", " << Phi << ", " << From << ")"
             << "\n");
     auto *Inst = getDefiningInst(Phi);
+    assert(Inst->getDest()->getType() == From.toOperand()->getType());
     Inst->addArgument(From, getDefNode(From));
   }
 
@@ -463,13 +672,50 @@
     LOG(out << *TrueNode << ", " << *FalseNode << ")"
             << "\n");
 
-    Ctrl->appendInst(InstBr::create(Func, Cond, *TrueNode, *FalseNode));
+    auto *CondBool = makeVariable(IceType_i1);
+    Ctrl->appendInst(InstCast::create(Func, InstCast::Trunc, CondBool, Cond));
+
+    Ctrl->appendInst(InstBr::create(Func, CondBool, *TrueNode, *FalseNode));
     return OperandNode(nullptr);
   }
-  Node Switch(unsigned Count, Node Key) { llvm::report_fatal_error("Switch"); }
-  Node IfValue(int32_t Value, Node Sw) { llvm::report_fatal_error("IfValue"); }
-  Node IfDefault(Node Sw) { llvm::report_fatal_error("IfDefault"); }
-  Node Return(unsigned Count, Node *Vals) {
+  InstSwitch *CurrentSwitch = nullptr;
+  CfgNode *SwitchNode = nullptr;
+  SizeT SwitchIndex = 0;
+  Node Switch(uint32_t Count, Node Key) {
+    LOG(out << "Switch(" << Count << ", " << Key << ")\n");
+
+    assert(!CurrentSwitch);
+
+    auto *Default = Func->makeNode();
+    // Count - 1 because the decoder counts the default label but Subzero does
+    // not.
+    CurrentSwitch = InstSwitch::create(Func, Count - 1, Key, Default);
+    SwitchIndex = 0;
+    SwitchNode = Control();
+    // We don't actually append the switch to the CfgNode here because not all
+    // the branches are ready.
+    return Node(nullptr);
+  }
+  Node IfValue(int32_t Value, Node) {
+    LOG(out << "IfValue(" << Value << ") [Index = " << SwitchIndex << "]\n");
+    assert(CurrentSwitch);
+    auto *Target = Func->makeNode();
+    CurrentSwitch->addBranch(SwitchIndex++, Value, Target);
+    return Node(Target);
+  }
+  Node IfDefault(Node) {
+    LOG(out << "IfDefault(...) [Index = " << SwitchIndex << "]\n");
+    assert(CurrentSwitch);
+    assert(CurrentSwitch->getLabelDefault());
+    // Now we append the switch, since this should be the last edge.
+    assert(SwitchIndex == CurrentSwitch->getNumCases());
+    SwitchNode->appendInst(CurrentSwitch);
+    SwitchNode = nullptr;
+    auto Default = Node(CurrentSwitch->getLabelDefault());
+    CurrentSwitch = nullptr;
+    return Default;
+  }
+  Node Return(uint32_t Count, Node *Vals) {
     assert(1 >= Count);
     LOG(out << "Return(");
     if (Count > 0)
@@ -511,20 +757,20 @@
     const auto NumArgs = Sig->parameter_count();
     LOG(out << "  number of args: " << NumArgs << "\n");
 
-    const auto TargetName =
-        Ctx->getGlobalString(Module->GetName(Target.name_offset));
+    const auto TargetName = getFunctionName(Module, Index);
     LOG(out << "  target name: " << TargetName << "\n");
 
     assert(Sig->return_count() <= 1);
 
-    auto *TargetOperand = Ctx->getConstantSym(0, TargetName);
+    auto TargetOperand =
+        Ctx->getConstantSym(0, Ctx->getGlobalString(TargetName));
 
     auto *Dest = Sig->return_count() > 0
                      ? makeVariable(toIceType(Sig->GetReturn()))
                      : nullptr;
     auto *Call = InstCall::create(Func, NumArgs, Dest, TargetOperand,
                                   false /* HasTailCall */);
-    for (int i = 0; i < NumArgs; ++i) {
+    for (uint32_t i = 0; i < NumArgs; ++i) {
       // The builder reserves the first argument for the code object.
       LOG(out << "  args[" << i << "] = " << Args[i + 1] << "\n");
       Call->addArg(Args[i + 1]);
@@ -545,13 +791,17 @@
     LOG(out << "  number of args: " << NumArgs << "\n");
 
     const auto &Target = Module->import_table[Index];
-    const auto TargetName =
-        Ctx->getGlobalString(Module->GetName(Target.function_name_offset));
+    const auto ModuleName = toStdString(
+        Module->GetName(Target.module_name_offset, Target.module_name_length));
+    const auto FnName = toStdString(Module->GetName(
+        Target.function_name_offset, Target.function_name_length));
+
+    const auto TargetName = Ctx->getGlobalString(ModuleName + "$$" + FnName);
     LOG(out << "  target name: " << TargetName << "\n");
 
     assert(Sig->return_count() <= 1);
 
-    auto *TargetOperand = Ctx->getConstantSym(0, TargetName);
+    auto TargetOperand = Ctx->getConstantExternSym(TargetName);
 
     auto *Dest = Sig->return_count() > 0
                      ? makeVariable(toIceType(Sig->GetReturn()))
@@ -559,9 +809,10 @@
     constexpr bool NoTailCall = false;
     auto *Call =
         InstCall::create(Func, NumArgs, Dest, TargetOperand, NoTailCall);
-    for (int i = 0; i < NumArgs; ++i) {
+    for (uint32_t i = 0; i < NumArgs; ++i) {
       // The builder reserves the first argument for the code object.
       LOG(out << "  args[" << i << "] = " << Args[i + 1] << "\n");
+      assert(Args[i + 1].toOperand()->getType() == toIceType(Sig->GetParam(i)));
       Call->addArg(Args[i + 1]);
     }
 
@@ -569,41 +820,140 @@
     LOG(out << "Call Result = " << Node(Dest) << "\n");
     return OperandNode(Dest);
   }
-  Node CallIndirect(uint32_t Index, Node *Args) {
-    llvm::report_fatal_error("CallIndirect");
+  Node CallIndirect(uint32_t SigIndex, Node *Args) {
+    LOG(out << "CallIndirect(" << SigIndex << ")\n");
+    // TODO(eholk): Compile to something better than a switch.
+    const auto *Module = this->Module->module;
+    assert(Module);
+    const auto &IndirectTable = Module->function_table;
+
+    // TODO(eholk): This should probably actually call abort instead.
+    auto *Abort = Func->makeNode();
+    Abort->appendInst(InstUnreachable::create(Func));
+
+    assert(Args[0].toOperand());
+
+    auto *Switch = InstSwitch::create(Func, IndirectTable.size(),
+                                      Args[0].toOperand(), Abort);
+    assert(Abort);
+
+    const bool HasReturn = Module->signatures[SigIndex]->return_count() != 0;
+    const Ice::Type DestTy =
+        HasReturn ? toIceType(Module->signatures[SigIndex]->GetReturn())
+                  : IceType_void;
+
+    auto *Dest = HasReturn ? makeVariable(DestTy) : nullptr;
+
+    auto *ExitNode = Func->makeNode();
+    auto *PhiInst =
+        HasReturn ? InstPhi::create(Func, IndirectTable.size(), Dest) : nullptr;
+
+    for (uint32_t Index = 0; Index < IndirectTable.size(); ++Index) {
+      const auto &Target = Module->functions[IndirectTable[Index]];
+
+      if (SigIndex == Target.sig_index) {
+        auto *CallNode = Func->makeNode();
+        auto *SavedControl = Control();
+        *ControlPtr = OperandNode(CallNode);
+        auto *Tmp = CallDirect(Target.func_index, Args).toOperand();
+        *ControlPtr = OperandNode(SavedControl);
+        if (PhiInst) {
+          PhiInst->addArgument(Tmp, CallNode);
+        }
+        CallNode->appendInst(InstBr::create(Func, ExitNode));
+        Switch->addBranch(Index, Index, CallNode);
+      } else {
+        Switch->addBranch(Index, Index, Abort);
+      }
+    }
+
+    if (PhiInst) {
+      ExitNode->appendInst(PhiInst);
+    }
+
+    Control()->appendInst(Switch);
+    *ControlPtr = OperandNode(ExitNode);
+    return OperandNode(Dest);
   }
-  Node Invert(Node Node) { llvm::report_fatal_error("Invert"); }
-  Node FunctionTable() { llvm::report_fatal_error("FunctionTable"); }
+  Node Invert(Node Node) {
+    (void)Node;
+    llvm::report_fatal_error("Invert");
+  }
 
   //-----------------------------------------------------------------------
   // Operations that concern the linear memory.
   //-----------------------------------------------------------------------
-  Node MemSize(uint32_t Offset) { llvm::report_fatal_error("MemSize"); }
-  Node LoadGlobal(uint32_t Index) { llvm::report_fatal_error("LoadGlobal"); }
+  Node MemSize(uint32_t Offset) {
+    (void)Offset;
+    llvm::report_fatal_error("MemSize");
+  }
+  Node LoadGlobal(uint32_t Index) {
+    (void)Index;
+    llvm::report_fatal_error("LoadGlobal");
+  }
   Node StoreGlobal(uint32_t Index, Node Val) {
+    (void)Index;
+    (void)Val;
     llvm::report_fatal_error("StoreGlobal");
   }
+
+  Operand *sanitizeAddress(Operand *Base, uint32_t Offset) {
+    // first, add the index and the offset together.
+    if (0 != Offset) {
+      auto *Addr = makeVariable(IceType_i32);
+      auto *OffsetConstant = Ctx->getConstantInt32(Offset);
+      Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
+                                                   Addr, Base, OffsetConstant));
+      Base = Addr;
+    }
+
+    SizeT MemSize = Module->module->min_mem_pages * (16 << 10);
+    auto *WrappedAddr = makeVariable(IceType_i32);
+    Control()->appendInst(
+        InstArithmetic::create(Func, InstArithmetic::Add, WrappedAddr, Base,
+                               Ctx->getConstantInt32(MemSize)));
+
+    auto ClampedAddr = makeVariable(IceType_i32);
+    Control()->appendInst(
+        InstArithmetic::create(Func, InstArithmetic::And, ClampedAddr, Base,
+                               Ctx->getConstantInt32(MemSize - 1)));
+
+    auto RealAddr = Func->makeVariable(IceType_i32);
+    auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY"));
+    Control()->appendInst(InstArithmetic::create(
+        Func, InstArithmetic::Add, RealAddr, ClampedAddr, MemBase));
+    return RealAddr;
+  }
+
   Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index,
                uint32_t Offset) {
     LOG(out << "LoadMem(" << Index << "[" << Offset << "]) = ");
 
-    // first, add the index and the offset together.
-    auto *OffsetConstant = Ctx->getConstantInt32(Offset);
-    auto *Addr = makeVariable(IceType_i32);
-    Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
-                                                 Addr, Index, OffsetConstant));
+    auto *RealAddr = sanitizeAddress(Index, Offset);
 
-    // then load the memory
     auto *LoadResult = makeVariable(toIceType(MemType));
-    Control()->appendInst(InstLoad::create(Func, LoadResult, Addr));
+    Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr));
 
     // and cast, if needed
     Ice::Variable *Result = nullptr;
     if (toIceType(Type) != toIceType(MemType)) {
-      Result = makeVariable(toIceType(Type));
+      auto DestType = toIceType(Type);
+      Result = makeVariable(DestType);
       // TODO(eholk): handle signs correctly.
-      Control()->appendInst(
-          InstCast::create(Func, InstCast::Sext, Result, LoadResult));
+      if (isScalarIntegerType(DestType)) {
+        if (MemType.IsSigned()) {
+          Control()->appendInst(
+              InstCast::create(Func, InstCast::Sext, Result, LoadResult));
+        } else {
+          Control()->appendInst(
+              InstCast::create(Func, InstCast::Zext, Result, LoadResult));
+        }
+      } else if (isScalarFloatingType(DestType)) {
+        Control()->appendInst(
+            InstCast::create(Func, InstCast::Sitofp, Result, LoadResult));
+      } else {
+        llvm::report_fatal_error("Unsupported type for memory load");
+      }
     } else {
       Result = LoadResult;
     }
@@ -615,13 +965,7 @@
     LOG(out << "StoreMem(" << Index << "[" << Offset << "] = " << Val << ")"
             << "\n");
 
-    // TODO(eholk): surely there is a better way to do this.
-
-    // first, add the index and the offset together.
-    auto *OffsetConstant = Ctx->getConstantInt32(Offset);
-    auto *Addr = makeVariable(IceType_i32);
-    Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
-                                                 Addr, Index, OffsetConstant));
+    auto *RealAddr = sanitizeAddress(Index, Offset);
 
     // cast the value to the right type, if needed
     Operand *StoreVal = nullptr;
@@ -635,10 +979,11 @@
     }
 
     // then store the memory
-    Control()->appendInst(InstStore::create(Func, StoreVal, Addr));
+    Control()->appendInst(InstStore::create(Func, StoreVal, RealAddr));
   }
 
-  static void PrintDebugName(Node node) {
+  static void PrintDebugName(OperandNode Node) {
+    (void)Node;
     llvm::report_fatal_error("PrintDebugName");
   }
 
@@ -705,36 +1050,33 @@
   }
 };
 
-std::string fnNameFromId(uint32_t Id) {
-  return std::string("fn") + to_string(Id);
-}
-
 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone,
-                                                       FunctionEnv *Env,
-                                                       const byte *Base,
-                                                       const byte *Start,
-                                                       const byte *End) {
+                                                       FunctionBody &Body) {
   OstreamLocker L1(Ctx);
   auto Func = Cfg::create(Ctx, getNextSequenceNumber());
   Ice::CfgLocalAllocatorScope L2(Func.get());
 
-  // TODO: parse the function signature...
+  // TODO(eholk): parse the function signature...
+
+  Func->setEntryNode(Func->makeNode());
 
   IceBuilder Builder(Func.get());
-  LR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder);
+  SR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder, Body);
 
   LOG(out << getFlags().getDefaultGlobalPrefix() << "\n");
-  Decoder.Decode(Env, Base, Start, End);
+  Decoder.Decode();
 
   // We don't always know where the incoming branches are in phi nodes, so this
   // function finds them.
   Func->fixPhiNodes();
 
+  Func->computeInOutEdges();
+
   return Func;
 }
 
 WasmTranslator::WasmTranslator(GlobalContext *Ctx)
-    : Translator(Ctx), BufferSize(24 << 10), Buffer(new uint8_t[24 << 10]) {
+    : Translator(Ctx), Buffer(new uint8_t[24 << 10]), BufferSize(24 << 10) {
   // TODO(eholk): compute the correct buffer size. This uses 24k by default,
   // which has been big enough for testing but is not a general solution.
 }
@@ -761,6 +1103,8 @@
 
   LOG(out << "Module info:"
           << "\n");
+  LOG(out << "  min_mem_pages:           " << Module->min_mem_pages << "\n");
+  LOG(out << "  max_mem_pages:           " << Module->max_mem_pages << "\n");
   LOG(out << "  number of globals:       " << Module->globals.size() << "\n");
   LOG(out << "  number of signatures:    " << Module->signatures.size()
           << "\n");
@@ -769,15 +1113,56 @@
           << "\n");
   LOG(out << "  function table size:     " << Module->function_table.size()
           << "\n");
+  LOG(out << "  import table size:       " << Module->import_table.size()
+          << "\n");
+  LOG(out << "  export table size:       " << Module->export_table.size()
+          << "\n");
 
-  ModuleEnv ModuleEnv;
-  ModuleEnv.module = Module;
+  LOG(out << "\n"
+          << "Data segment information:"
+          << "\n");
+  uint32_t Id = 0;
+  for (const auto Seg : Module->data_segments) {
+    LOG(out << Id << ":  (" << Seg.source_offset << ", " << Seg.source_size
+            << ") => " << Seg.dest_addr);
+    if (Seg.init) {
+      LOG(out << " init\n");
+    } else {
+      LOG(out << "\n");
+    }
+    Id++;
+  }
+
+  LOG(out << "\n"
+          << "Import information:"
+          << "\n");
+  for (const auto Import : Module->import_table) {
+    auto ModuleName = toStdString(
+        Module->GetName(Import.module_name_offset, Import.module_name_length));
+    auto FnName = toStdString(Module->GetName(Import.function_name_offset,
+                                              Import.function_name_length));
+    LOG(out << "  " << Import.sig_index << ": " << ModuleName << "::" << FnName
+            << "\n");
+  }
+
+  LOG(out << "\n"
+          << "Export information:"
+          << "\n");
+  for (const auto Export : Module->export_table) {
+    LOG(out << "  " << Export.func_index << ": "
+            << toStdString(
+                   Module->GetName(Export.name_offset, Export.name_length))
+            << " (" << Export.name_offset << ", " << Export.name_length << ")");
+    LOG(out << "\n");
+  }
 
   LOG(out << "\n"
           << "Function information:"
           << "\n");
   for (const auto F : Module->functions) {
-    LOG(out << "  " << F.name_offset << ": " << Module->GetName(F.name_offset));
+    LOG(out << "  " << F.func_index << ": "
+            << toStdString(Module->GetName(F.name_offset, F.name_length))
+            << " (" << F.name_offset << ", " << F.name_length << ")");
     if (F.exported)
       LOG(out << " export");
     if (F.external)
@@ -785,29 +1170,76 @@
     LOG(out << "\n");
   }
 
-  FunctionEnv Fenv;
-  Fenv.module = &ModuleEnv;
+  LOG(out << "\n"
+          << "Indirect table:"
+          << "\n");
+  for (uint32_t F : Module->function_table) {
+    LOG(out << "  " << F << ": " << getFunctionName(Module, F) << "\n");
+  }
+
+  ModuleEnv ModuleEnv;
+  ModuleEnv.module = Module;
+
+  FunctionBody Body;
+  Body.module = &ModuleEnv;
 
   LOG(out << "Translating " << IRFilename << "\n");
 
+  {
+    unique_ptr<VariableDeclarationList> Globals =
+        makeUnique<VariableDeclarationList>();
+
+    // Global variables, etc go here.
+    auto *WasmMemory = VariableDeclaration::createExternal(Globals.get());
+    WasmMemory->setName(Ctx->getGlobalString("WASM_MEMORY"));
+
+    // Fill in the segments
+    SizeT WritePtr = 0;
+    for (const auto Seg : Module->data_segments) {
+      // fill in gaps with zero.
+      if (Seg.dest_addr > WritePtr) {
+        WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
+            Globals.get(), Seg.dest_addr - WritePtr));
+        WritePtr = Seg.dest_addr;
+      }
+
+      // Add the data
+      WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create(
+          Globals.get(), reinterpret_cast<const char *>(Module->module_start) +
+                             Seg.source_offset,
+          Seg.source_size));
+
+      WritePtr += Seg.source_size;
+    }
+
+    // Pad the rest with zeros
+    SizeT DataSize = Module->min_mem_pages * (64 << 10);
+    if (WritePtr < DataSize) {
+      WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
+          Globals.get(), DataSize - WritePtr));
+    }
+
+    WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
+        Globals.get(), Module->min_mem_pages * (64 << 10)));
+
+    Globals->push_back(WasmMemory);
+
+    lowerGlobals(std::move(Globals));
+  }
+
   // Translate each function.
-  uint32_t Id = 0;
   for (const auto Fn : Module->functions) {
-    std::string NewName = fnNameFromId(Id++);
-    LOG(out << "  " << Fn.name_offset << ": " << Module->GetName(Fn.name_offset)
-            << " -> " << NewName << "...");
+    const auto FnName = getFunctionName(Module, Fn.func_index);
 
-    Fenv.sig = Fn.sig;
-    Fenv.local_i32_count = Fn.local_i32_count;
-    Fenv.local_i64_count = Fn.local_i64_count;
-    Fenv.local_f32_count = Fn.local_f32_count;
-    Fenv.local_f64_count = Fn.local_f64_count;
-    Fenv.SumLocals();
+    LOG(out << "  " << Fn.func_index << ": " << FnName << "...");
 
-    auto Func = translateFunction(&Zone, &Fenv, Buffer.get(),
-                                  Buffer.get() + Fn.code_start_offset,
-                                  Buffer.get() + Fn.code_end_offset);
-    Func->setFunctionName(Ctx->getGlobalString(NewName));
+    Body.sig = Fn.sig;
+    Body.base = Buffer.get();
+    Body.start = Buffer.get() + Fn.code_start_offset;
+    Body.end = Buffer.get() + Fn.code_end_offset;
+
+    auto Func = translateFunction(&Zone, Body);
+    Func->setFunctionName(Ctx->getGlobalString(FnName));
 
     Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func)));
     LOG(out << "done.\n");
diff --git a/src/WasmTranslator.h b/src/WasmTranslator.h
index 4a23bc1..7b023b3 100644
--- a/src/WasmTranslator.h
+++ b/src/WasmTranslator.h
@@ -20,11 +20,22 @@
 #include "IceGlobalContext.h"
 #include "IceTranslator.h"
 
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#endif // __clang__
+
+#include "llvm/Support/StreamingMemoryObject.h"
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif // __clang__
+
 namespace v8 {
 namespace internal {
 class Zone;
 namespace wasm {
-class FunctionEnv;
+struct FunctionBody;
 } // end of namespace wasm
 } // end of namespace internal
 } // end of namespace v8
@@ -53,15 +64,10 @@
   ///
   /// Parameters:
   ///   Zone - an arena for the V8 code to allocate from.
-  ///   Env - information about the function (signature, variable count, etc.).
-  ///   Base - a pointer to the start of the Wasm module.
-  ///   Start - a pointer to the start of the function within the module.
-  ///   End - a pointer to the end of the function.
-  std::unique_ptr<Cfg> translateFunction(v8::internal::Zone *Zone,
-                                         v8::internal::wasm::FunctionEnv *Env,
-                                         const uint8_t *Base,
-                                         const uint8_t *Start,
-                                         const uint8_t *End);
+  ///   Body - information about the function to translate
+  std::unique_ptr<Cfg>
+  translateFunction(v8::internal::Zone *Zone,
+                    v8::internal::wasm::FunctionBody &Body);
 
 private:
   std::unique_ptr<uint8_t[]> Buffer;