| Index: src/WasmTranslator.cpp
 | 
| diff --git a/src/WasmTranslator.cpp b/src/WasmTranslator.cpp
 | 
| index b42ad7761442d9adee2475aaa18f9eefa8cb1f0a..6c1ed24659c1307cf613a8fd2233c9da218f6167 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;
 | 
|  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 @@ Ice::Type toIceType(wasm::LocalType Type) {
 | 
|    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 @@ public:
 | 
|  
 | 
|  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 @@ Ostream &operator<<(Ostream &Out, const OperandNode &Op) {
 | 
|    return Out;
 | 
|  }
 | 
|  
 | 
| -constexpr bool isComparison(wasm::WasmOpcode Opcode) {
 | 
| +bool isComparison(wasm::WasmOpcode Opcode) {
 | 
|    switch (Opcode) {
 | 
|    case kExprI32Ne:
 | 
|    case kExprI64Ne:
 | 
| @@ -157,6 +227,16 @@ constexpr bool isComparison(wasm::WasmOpcode Opcode) {
 | 
|    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 @@ class IceBuilder {
 | 
|  
 | 
|  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 @@ public:
 | 
|    }
 | 
|  
 | 
|    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 @@ public:
 | 
|      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 @@ public:
 | 
|      // 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 @@ public:
 | 
|      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 @@ public:
 | 
|      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 @@ public:
 | 
|        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 @@ public:
 | 
|        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 @@ public:
 | 
|            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, TmpDest, Left, Right));
 | 
|        Control()->appendInst(
 | 
| -          InstIcmp::create(Func, InstIcmp::Ne, Dest, Left, Right));
 | 
| +          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, 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(
 | 
| -          InstIcmp::create(Func, InstIcmp::Slt, Dest, Left, Right));
 | 
| +          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, TmpDest, Left, Right));
 | 
|        Control()->appendInst(
 | 
| -          InstIcmp::create(Func, InstIcmp::Ult, Dest, Left, Right));
 | 
| +          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, TmpDest, Left, Right));
 | 
|        Control()->appendInst(
 | 
| -          InstIcmp::create(Func, InstIcmp::Sgt, Dest, Left, Right));
 | 
| +          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, TmpDest, Left, Right));
 | 
|        Control()->appendInst(
 | 
| -          InstIcmp::create(Func, InstIcmp::Ugt, Dest, Left, Right));
 | 
| +          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 @@ public:
 | 
|              << ") = ");
 | 
|      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 @@ public:
 | 
|        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 @@ public:
 | 
|      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 @@ public:
 | 
|      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 @@ public:
 | 
|      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 @@ public:
 | 
|      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 @@ public:
 | 
|      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 @@ public:
 | 
|      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 @@ public:
 | 
|      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) {
 | 
| +    (void)Node;
 | 
| +    llvm::report_fatal_error("Invert");
 | 
|    }
 | 
| -  Node Invert(Node Node) { llvm::report_fatal_error("Invert"); }
 | 
| -  Node FunctionTable() { llvm::report_fatal_error("FunctionTable"); }
 | 
|  
 | 
|    //-----------------------------------------------------------------------
 | 
|    // 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 @@ public:
 | 
|      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 @@ public:
 | 
|      }
 | 
|  
 | 
|      // 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 @@ private:
 | 
|    }
 | 
|  };
 | 
|  
 | 
| -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 @@ void WasmTranslator::translate(
 | 
|  
 | 
|    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 @@ void WasmTranslator::translate(
 | 
|            << "\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 @@ void WasmTranslator::translate(
 | 
|      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 << "...");
 | 
| -
 | 
| -    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();
 | 
| -
 | 
| -    auto Func = translateFunction(&Zone, &Fenv, Buffer.get(),
 | 
| -                                  Buffer.get() + Fn.code_start_offset,
 | 
| -                                  Buffer.get() + Fn.code_end_offset);
 | 
| -    Func->setFunctionName(Ctx->getGlobalString(NewName));
 | 
| +    const auto FnName = getFunctionName(Module, Fn.func_index);
 | 
| +
 | 
| +    LOG(out << "  " << Fn.func_index << ": " << FnName << "...");
 | 
| +
 | 
| +    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");
 | 
| 
 |