| Index: src/WasmTranslator.cpp | 
| diff --git a/src/WasmTranslator.cpp b/src/WasmTranslator.cpp | 
| new file mode 100644 | 
| index 0000000000000000000000000000000000000000..4773526f4db6150c42f2e5e56d0ba55bbd973e28 | 
| --- /dev/null | 
| +++ b/src/WasmTranslator.cpp | 
| @@ -0,0 +1,815 @@ | 
| +//===- subzero/src/WasmTranslator.cpp - WASM to Subzero Translation -------===// | 
| +// | 
| +//                        The Subzero Code Generator | 
| +// | 
| +// This file is distributed under the University of Illinois Open Source | 
| +// License. See LICENSE.TXT for details. | 
| +// | 
| +//===----------------------------------------------------------------------===// | 
| +/// | 
| +/// \file | 
| +/// \brief Defines a driver for translating Wasm bitcode into PNaCl bitcode. | 
| +/// | 
| +/// The translator uses V8's WebAssembly decoder to handle the binary Wasm | 
| +/// format but replaces the usual TurboFan builder with a new PNaCl builder. | 
| +/// | 
| +//===----------------------------------------------------------------------===// | 
| + | 
| +#include "llvm/Support/StreamingMemoryObject.h" | 
| + | 
| +#include "WasmTranslator.h" | 
| + | 
| +#include "src/wasm/module-decoder.h" | 
| +#include "src/wasm/wasm-opcodes.h" | 
| +#include "src/zone.h" | 
| + | 
| +#include "IceCfgNode.h" | 
| +#include "IceGlobalInits.h" | 
| + | 
| +using namespace std; | 
| +using namespace Ice; | 
| +using namespace v8; | 
| +using namespace v8::internal; | 
| +using namespace v8::internal::wasm; | 
| +using v8::internal::wasm::DecodeWasmModule; | 
| + | 
| +#include "src/wasm/ast-decoder-impl.h" | 
| + | 
| +#define LOG(Expr) log([&](Ostream & out) { Expr; }) | 
| + | 
| +namespace { | 
| + | 
| +Ice::Type toIceType(v8::internal::MachineType) { | 
| +  // TODO(eholk): actually convert this. | 
| +  return IceType_i32; | 
| +} | 
| + | 
| +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: | 
| +    return IceType_i1; | 
| +  case MachineRepresentation::kWord8: | 
| +    return IceType_i8; | 
| +  case MachineRepresentation::kWord16: | 
| +    return IceType_i16; | 
| +  case MachineRepresentation::kWord32: | 
| +    return IceType_i32; | 
| +  case MachineRepresentation::kWord64: | 
| +    return IceType_i64; | 
| +  case MachineRepresentation::kFloat32: | 
| +    return IceType_f32; | 
| +  case MachineRepresentation::kFloat64: | 
| +    return IceType_f64; | 
| +  case MachineRepresentation::kSimd128: | 
| +    llvm::report_fatal_error("ambiguous SIMD type"); | 
| +  case MachineRepresentation::kTagged: | 
| +    llvm::report_fatal_error("kTagged type not supported"); | 
| +  } | 
| +} | 
| + | 
| +} // end of anonymous namespace | 
| + | 
| +/// This class wraps either an Operand or a CfgNode. | 
| +/// | 
| +/// Turbofan's sea of nodes representation only has nodes for values, control | 
| +/// flow, etc. In Subzero these concepts are all separate. This class lets V8's | 
| +/// Wasm decoder treat Subzero objects as though they are all the same. | 
| +class OperandNode { | 
| +  static constexpr uintptr_t NODE_FLAG = 1; | 
| +  static constexpr uintptr_t UNDEF_PTR = (uintptr_t)-1; | 
| + | 
| +  uintptr_t Data = UNDEF_PTR; | 
| + | 
| +public: | 
| +  OperandNode() = default; | 
| +  explicit OperandNode(Operand *Operand) | 
| +      : Data(reinterpret_cast<uintptr_t>(Operand)) {} | 
| +  explicit OperandNode(CfgNode *Node) | 
| +      : Data(reinterpret_cast<uintptr_t>(Node) | NODE_FLAG) {} | 
| +  explicit OperandNode(nullptr_t) : Data(UNDEF_PTR) {} | 
| + | 
| +  operator Operand *() const { | 
| +    if (UNDEF_PTR == Data) { | 
| +      return nullptr; | 
| +    } | 
| +    if (!isOperand()) { | 
| +      llvm::report_fatal_error("This OperandNode is not an Operand"); | 
| +    } | 
| +    return reinterpret_cast<Operand *>(Data); | 
| +  } | 
| + | 
| +  operator CfgNode *() const { | 
| +    if (UNDEF_PTR == Data) { | 
| +      return nullptr; | 
| +    } | 
| +    if (!isCfgNode()) { | 
| +      llvm::report_fatal_error("This OperandNode is not a CfgNode"); | 
| +    } | 
| +    return reinterpret_cast<CfgNode *>(Data & ~NODE_FLAG); | 
| +  } | 
| + | 
| +  explicit operator bool() const { return (Data != UNDEF_PTR) && Data; } | 
| +  bool operator==(const OperandNode &Rhs) const { | 
| +    return (Data == Rhs.Data) || | 
| +           (UNDEF_PTR == Data && (Rhs.Data == 0 || Rhs.Data == NODE_FLAG)) || | 
| +           (UNDEF_PTR == Rhs.Data && (Data == 0 || Data == NODE_FLAG)); | 
| +  } | 
| +  bool operator!=(const OperandNode &Rhs) const { return !(*this == Rhs); } | 
| + | 
| +  bool isOperand() const { return (Data != UNDEF_PTR) && !(Data & NODE_FLAG); } | 
| +  bool isCfgNode() const { return (Data != UNDEF_PTR) && (Data & NODE_FLAG); } | 
| + | 
| +  Operand *toOperand() const { return static_cast<Operand *>(*this); } | 
| + | 
| +  CfgNode *toCfgNode() const { return static_cast<CfgNode *>(*this); } | 
| +}; | 
| + | 
| +Ostream &operator<<(Ostream &Out, const OperandNode &Op) { | 
| +  if (Op.isOperand()) { | 
| +    Out << "(Operand*)" << Op.toOperand(); | 
| +  } else if (Op.isCfgNode()) { | 
| +    Out << "(CfgNode*)" << Op.toCfgNode(); | 
| +  } else { | 
| +    Out << "nullptr"; | 
| +  } | 
| +  return Out; | 
| +} | 
| + | 
| +constexpr bool isComparison(wasm::WasmOpcode Opcode) { | 
| +  switch (Opcode) { | 
| +  case kExprI32Ne: | 
| +  case kExprI64Ne: | 
| +  case kExprI32Eq: | 
| +  case kExprI64Eq: | 
| +  case kExprI32LtS: | 
| +  case kExprI64LtS: | 
| +  case kExprI32LtU: | 
| +  case kExprI64LtU: | 
| +  case kExprI32GeS: | 
| +  case kExprI64GeS: | 
| +  case kExprI32GtS: | 
| +  case kExprI64GtS: | 
| +  case kExprI32GtU: | 
| +  case kExprI64GtU: | 
| +    return true; | 
| +  default: | 
| +    return false; | 
| +  } | 
| +} | 
| + | 
| +class IceBuilder { | 
| +  using Node = OperandNode; | 
| + | 
| +  IceBuilder() = delete; | 
| +  IceBuilder(const IceBuilder &) = delete; | 
| +  IceBuilder &operator=(const IceBuilder &) = delete; | 
| + | 
| +public: | 
| +  explicit IceBuilder(class Cfg *Func) | 
| +      : Func(Func), Ctx(Func->getContext()), ControlPtr(nullptr) {} | 
| + | 
| +  /// Allocates a buffer of Nodes for use by V8. | 
| +  Node *Buffer(size_t Count) { | 
| +    LOG(out << "Buffer(" << Count << ")\n"); | 
| +    return Func->allocateArrayOf<Node>(Count); | 
| +  } | 
| + | 
| +  Node Error() { llvm::report_fatal_error("Error"); } | 
| +  Node Start(unsigned Params) { | 
| +    LOG(out << "Start(" << Params << ") = "); | 
| +    auto *Entry = Func->makeNode(); | 
| +    Func->setEntryNode(Entry); | 
| +    LOG(out << Node(Entry) << "\n"); | 
| +    return OperandNode(Entry); | 
| +  } | 
| +  Node Param(unsigned Index, wasm::LocalType Type) { | 
| +    LOG(out << "Param(" << Index << ") = "); | 
| +    auto *Arg = makeVariable(toIceType(Type)); | 
| +    assert(Index == NextArg); | 
| +    Func->addArg(Arg); | 
| +    ++NextArg; | 
| +    LOG(out << Node(Arg) << "\n"); | 
| +    return OperandNode(Arg); | 
| +  } | 
| +  Node Loop(CfgNode *Entry) { | 
| +    auto *Loop = Func->makeNode(); | 
| +    LOG(out << "Loop(" << Entry << ") = " << Loop << "\n"); | 
| +    Entry->appendInst(InstBr::create(Func, Loop)); | 
| +    return OperandNode(Loop); | 
| +  } | 
| +  void Terminate(Node Effect, Node Control) { | 
| +    // TODO(eholk): this is almost certainly wrong | 
| +    LOG(out << "Terminate(" << Effect << ", " << Control << ")" | 
| +            << "\n"); | 
| +  } | 
| +  Node Merge(unsigned Count, Node *Controls) { | 
| +    LOG(out << "Merge(" << Count); | 
| +    for (unsigned i = 0; i < Count; ++i) { | 
| +      LOG(out << ", " << Controls[i]); | 
| +    } | 
| +    LOG(out << ") = "); | 
| + | 
| +    auto *MergedNode = Func->makeNode(); | 
| + | 
| +    for (unsigned 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) { | 
| +    LOG(out << "Phi(" << Count << ", " << Control); | 
| +    for (int i = 0; i < Count; ++i) { | 
| +      LOG(out << ", " << Vals[i]); | 
| +    } | 
| +    LOG(out << ") = "); | 
| + | 
| +    const auto &InEdges = Control.toCfgNode()->getInEdges(); | 
| +    assert(Count == InEdges.size()); | 
| + | 
| +    assert(Count > 0); | 
| + | 
| +    auto *Dest = makeVariable(Vals[0].toOperand()->getType(), Control); | 
| + | 
| +    // Multiply by 10 in case more things get added later. | 
| + | 
| +    // 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) { | 
| +      auto *Op = Vals[i].toOperand(); | 
| +      assert(Op); | 
| +      Phi->addArgument(Op, InEdges[i]); | 
| +    } | 
| +    setDefiningInst(Dest, Phi); | 
| +    Control.toCfgNode()->appendInst(Phi); | 
| +    LOG(out << Node(Dest) << "\n"); | 
| +    return OperandNode(Dest); | 
| +  } | 
| +  Node EffectPhi(unsigned 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) { | 
| +      LOG(out << "  " << Effects[i] << "\n"); | 
| +    } | 
| +    return OperandNode(nullptr); | 
| +  } | 
| +  Node Int32Constant(int32_t Value) { | 
| +    LOG(out << "Int32Constant(" << Value << ") = "); | 
| +    auto *Const = Ctx->getConstantInt32(Value); | 
| +    assert(Const); | 
| +    assert(Control()); | 
| +    LOG(out << Node(Const) << "\n"); | 
| +    return OperandNode(Const); | 
| +  } | 
| +  Node Int64Constant(int64_t Value) { | 
| +    LOG(out << "Int64Constant(" << Value << ") = "); | 
| +    auto *Const = Ctx->getConstantInt64(Value); | 
| +    assert(Const); | 
| +    LOG(out << Node(Const) << "\n"); | 
| +    return OperandNode(Const); | 
| +  } | 
| +  Node Float32Constant(float Value) { | 
| +    LOG(out << "Float32Constant(" << Value << ") = "); | 
| +    auto *Const = Ctx->getConstantFloat(Value); | 
| +    assert(Const); | 
| +    LOG(out << Node(Const) << "\n"); | 
| +    return OperandNode(Const); | 
| +  } | 
| +  Node Float64Constant(double Value) { | 
| +    LOG(out << "Float64Constant(" << Value << ") = "); | 
| +    auto *Const = Ctx->getConstantDouble(Value); | 
| +    assert(Const); | 
| +    LOG(out << Node(Const) << "\n"); | 
| +    return OperandNode(Const); | 
| +  } | 
| +  Node Binop(wasm::WasmOpcode Opcode, Node Left, Node Right) { | 
| +    LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left | 
| +            << ", " << Right << ") = "); | 
| +    auto *Dest = makeVariable( | 
| +        isComparison(Opcode) ? IceType_i1 : Left.toOperand()->getType()); | 
| +    switch (Opcode) { | 
| +    case kExprI32Add: | 
| +    case kExprI64Add: | 
| +      Control()->appendInst( | 
| +          InstArithmetic::create(Func, InstArithmetic::Add, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32Sub: | 
| +    case kExprI64Sub: | 
| +      Control()->appendInst( | 
| +          InstArithmetic::create(Func, InstArithmetic::Sub, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32Mul: | 
| +    case kExprI64Mul: | 
| +      Control()->appendInst( | 
| +          InstArithmetic::create(Func, InstArithmetic::Mul, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32DivU: | 
| +    case kExprI64DivU: | 
| +      Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Udiv, | 
| +                                                   Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32RemU: | 
| +    case kExprI64RemU: | 
| +      Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Urem, | 
| +                                                   Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32Ior: | 
| +    case kExprI64Ior: | 
| +      Control()->appendInst( | 
| +          InstArithmetic::create(Func, InstArithmetic::Or, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32Xor: | 
| +    case kExprI64Xor: | 
| +      Control()->appendInst( | 
| +          InstArithmetic::create(Func, InstArithmetic::Xor, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32Shl: | 
| +    case kExprI64Shl: | 
| +      Control()->appendInst( | 
| +          InstArithmetic::create(Func, InstArithmetic::Shl, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32ShrU: | 
| +    case kExprI64ShrU: | 
| +    case kExprI32ShrS: | 
| +    case kExprI64ShrS: | 
| +      Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Ashr, | 
| +                                                   Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32And: | 
| +    case kExprI64And: | 
| +      Control()->appendInst( | 
| +          InstArithmetic::create(Func, InstArithmetic::And, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32Ne: | 
| +    case kExprI64Ne: | 
| +      Control()->appendInst( | 
| +          InstIcmp::create(Func, InstIcmp::Ne, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32Eq: | 
| +    case kExprI64Eq: | 
| +      Control()->appendInst( | 
| +          InstIcmp::create(Func, InstIcmp::Eq, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32LtS: | 
| +    case kExprI64LtS: | 
| +      Control()->appendInst( | 
| +          InstIcmp::create(Func, InstIcmp::Slt, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32LtU: | 
| +    case kExprI64LtU: | 
| +      Control()->appendInst( | 
| +          InstIcmp::create(Func, InstIcmp::Ult, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32GeS: | 
| +    case kExprI64GeS: | 
| +      Control()->appendInst( | 
| +          InstIcmp::create(Func, InstIcmp::Sge, Dest, Left, Right)); | 
| +    case kExprI32GtS: | 
| +    case kExprI64GtS: | 
| +      Control()->appendInst( | 
| +          InstIcmp::create(Func, InstIcmp::Sgt, Dest, Left, Right)); | 
| +      break; | 
| +    case kExprI32GtU: | 
| +    case kExprI64GtU: | 
| +      Control()->appendInst( | 
| +          InstIcmp::create(Func, InstIcmp::Ugt, Dest, Left, Right)); | 
| +      break; | 
| +    default: | 
| +      LOG(out << "Unknown binop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); | 
| +      llvm::report_fatal_error("Uncovered or invalid binop."); | 
| +      return OperandNode(nullptr); | 
| +    } | 
| +    LOG(out << Dest << "\n"); | 
| +    return OperandNode(Dest); | 
| +  } | 
| +  Node Unop(wasm::WasmOpcode Opcode, Node Input) { | 
| +    LOG(out << "Unop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Input | 
| +            << ") = "); | 
| +    Ice::Variable *Dest = nullptr; | 
| +    switch (Opcode) { | 
| +    case kExprF32Neg: { | 
| +      Dest = makeVariable(IceType_f32); | 
| +      Control()->appendInst(InstArithmetic::create( | 
| +          Func, InstArithmetic::Fsub, Dest, Ctx->getConstantFloat(0), Input)); | 
| +      break; | 
| +    } | 
| +    case kExprF64Neg: { | 
| +      Dest = makeVariable(IceType_f64); | 
| +      Control()->appendInst(InstArithmetic::create( | 
| +          Func, InstArithmetic::Fsub, Dest, Ctx->getConstantDouble(0), Input)); | 
| +      break; | 
| +    } | 
| +    case kExprI64UConvertI32: | 
| +      Dest = makeVariable(IceType_i64); | 
| +      Control()->appendInst( | 
| +          InstCast::create(Func, InstCast::Zext, Dest, Input)); | 
| +      break; | 
| +    default: | 
| +      LOG(out << "Unknown unop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); | 
| +      llvm::report_fatal_error("Uncovered or invalid unop."); | 
| +      return OperandNode(nullptr); | 
| +    } | 
| +    LOG(out << Dest << "\n"); | 
| +    return OperandNode(Dest); | 
| +  } | 
| +  unsigned 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)) { | 
| +        LOG(out << "  ...has defining instruction" | 
| +                << "\n"); | 
| +        LOG(out << getDefNode(Phi) << "\n"); | 
| +        LOG(out << "  ..." << (getDefNode(Phi) == Merge) << "\n"); | 
| +        return getDefNode(Phi) == Merge; | 
| +      } | 
| +    } | 
| +    return false; | 
| +  } | 
| +  void AppendToMerge(CfgNode *Merge, CfgNode *From) const { | 
| +    From->appendInst(InstBr::create(Func, Merge)); | 
| +  } | 
| +  void AppendToPhi(Node Merge, Node Phi, Node From) { | 
| +    LOG(out << "AppendToPhi(" << Merge << ", " << Phi << ", " << From << ")" | 
| +            << "\n"); | 
| +    auto *Inst = getDefiningInst(Phi); | 
| +    Inst->addArgument(From, getDefNode(From)); | 
| +  } | 
| + | 
| +  //----------------------------------------------------------------------- | 
| +  // Operations that read and/or write {control} and {effect}. | 
| +  //----------------------------------------------------------------------- | 
| +  Node Branch(Node Cond, Node *TrueNode, Node *FalseNode) { | 
| +    // true_node and false_node appear to be out parameters. | 
| +    LOG(out << "Branch(" << Cond << ", "); | 
| + | 
| +    // save control here because true_node appears to alias control. | 
| +    auto *Ctrl = Control(); | 
| + | 
| +    *TrueNode = OperandNode(Func->makeNode()); | 
| +    *FalseNode = OperandNode(Func->makeNode()); | 
| + | 
| +    LOG(out << *TrueNode << ", " << *FalseNode << ")" | 
| +            << "\n"); | 
| + | 
| +    Ctrl->appendInst(InstBr::create(Func, Cond, *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) { | 
| +    assert(1 >= Count); | 
| +    LOG(out << "Return("); | 
| +    if (Count > 0) | 
| +      LOG(out << Vals[0]); | 
| +    LOG(out << ")" | 
| +            << "\n"); | 
| +    auto *Instr = | 
| +        1 == Count ? InstRet::create(Func, Vals[0]) : InstRet::create(Func); | 
| +    Control()->appendInst(Instr); | 
| +    Control()->setHasReturn(); | 
| +    LOG(out << Node(nullptr) << "\n"); | 
| +    return OperandNode(nullptr); | 
| +  } | 
| +  Node ReturnVoid() { | 
| +    LOG(out << "ReturnVoid() = "); | 
| +    auto *Instr = InstRet::create(Func); | 
| +    Control()->appendInst(Instr); | 
| +    Control()->setHasReturn(); | 
| +    LOG(out << Node(nullptr) << "\n"); | 
| +    return OperandNode(nullptr); | 
| +  } | 
| +  Node Unreachable() { | 
| +    LOG(out << "Unreachable() = "); | 
| +    auto *Instr = InstUnreachable::create(Func); | 
| +    Control()->appendInst(Instr); | 
| +    LOG(out << Node(nullptr) << "\n"); | 
| +    return OperandNode(nullptr); | 
| +  } | 
| + | 
| +  Node CallDirect(uint32_t Index, Node *Args) { | 
| +    LOG(out << "CallDirect(" << Index << ")" | 
| +            << "\n"); | 
| +    assert(Module->IsValidFunction(Index)); | 
| +    const auto *Module = this->Module->module; | 
| +    assert(Module); | 
| +    const auto &Target = Module->functions[Index]; | 
| +    const auto *Sig = Target.sig; | 
| +    assert(Sig); | 
| +    const auto NumArgs = Sig->parameter_count(); | 
| +    LOG(out << "  number of args: " << NumArgs << "\n"); | 
| + | 
| +    const auto TargetName = | 
| +        Ctx->getGlobalString(Module->GetName(Target.name_offset)); | 
| +    LOG(out << "  target name: " << TargetName << "\n"); | 
| + | 
| +    assert(Sig->return_count() <= 1); | 
| + | 
| +    auto *TargetOperand = Ctx->getConstantSym(0, 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) { | 
| +      // The builder reserves the first argument for the code object. | 
| +      LOG(out << "  args[" << i << "] = " << Args[i + 1] << "\n"); | 
| +      Call->addArg(Args[i + 1]); | 
| +    } | 
| + | 
| +    Control()->appendInst(Call); | 
| +    LOG(out << "Call Result = " << Node(Dest) << "\n"); | 
| +    return OperandNode(Dest); | 
| +  } | 
| +  Node CallImport(uint32_t Index, Node *Args) { | 
| +    LOG(out << "CallImport(" << Index << ")" | 
| +            << "\n"); | 
| +    const auto *Module = this->Module->module; | 
| +    assert(Module); | 
| +    const auto *Sig = this->Module->GetImportSignature(Index); | 
| +    assert(Sig); | 
| +    const auto NumArgs = Sig->parameter_count(); | 
| +    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)); | 
| +    LOG(out << "  target name: " << TargetName << "\n"); | 
| + | 
| +    assert(Sig->return_count() <= 1); | 
| + | 
| +    auto *TargetOperand = Ctx->getConstantSym(0, TargetName); | 
| + | 
| +    auto *Dest = Sig->return_count() > 0 | 
| +                     ? makeVariable(toIceType(Sig->GetReturn())) | 
| +                     : nullptr; | 
| +    constexpr bool NoTailCall = false; | 
| +    auto *Call = | 
| +        InstCall::create(Func, NumArgs, Dest, TargetOperand, NoTailCall); | 
| +    for (int 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]); | 
| +    } | 
| + | 
| +    Control()->appendInst(Call); | 
| +    LOG(out << "Call Result = " << Node(Dest) << "\n"); | 
| +    return OperandNode(Dest); | 
| +  } | 
| +  Node CallIndirect(uint32_t Index, Node *Args) { | 
| +    llvm::report_fatal_error("CallIndirect"); | 
| +  } | 
| +  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 StoreGlobal(uint32_t Index, Node Val) { | 
| +    llvm::report_fatal_error("StoreGlobal"); | 
| +  } | 
| +  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)); | 
| + | 
| +    // then load the memory | 
| +    auto *LoadResult = makeVariable(toIceType(MemType)); | 
| +    Control()->appendInst(InstLoad::create(Func, LoadResult, Addr)); | 
| + | 
| +    // and cast, if needed | 
| +    Ice::Variable *Result = nullptr; | 
| +    if (toIceType(Type) != toIceType(MemType)) { | 
| +      Result = makeVariable(toIceType(Type)); | 
| +      // TODO(eholk): handle signs correctly. | 
| +      Control()->appendInst( | 
| +          InstCast::create(Func, InstCast::Sext, Result, LoadResult)); | 
| +    } else { | 
| +      Result = LoadResult; | 
| +    } | 
| + | 
| +    LOG(out << Result << "\n"); | 
| +    return OperandNode(Result); | 
| +  } | 
| +  void StoreMem(MachineType Type, Node Index, uint32_t Offset, Node Val) { | 
| +    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)); | 
| + | 
| +    // cast the value to the right type, if needed | 
| +    Operand *StoreVal = nullptr; | 
| +    if (toIceType(Type) != Val.toOperand()->getType()) { | 
| +      auto *LocalStoreVal = makeVariable(toIceType(Type)); | 
| +      Control()->appendInst( | 
| +          InstCast::create(Func, InstCast::Trunc, LocalStoreVal, Val)); | 
| +      StoreVal = LocalStoreVal; | 
| +    } else { | 
| +      StoreVal = Val; | 
| +    } | 
| + | 
| +    // then store the memory | 
| +    Control()->appendInst(InstStore::create(Func, StoreVal, Addr)); | 
| +  } | 
| + | 
| +  static void PrintDebugName(Node node) { | 
| +    llvm::report_fatal_error("PrintDebugName"); | 
| +  } | 
| + | 
| +  CfgNode *Control() { | 
| +    return ControlPtr ? ControlPtr->toCfgNode() : Func->getEntryNode(); | 
| +  } | 
| +  Node Effect() { return *EffectPtr; } | 
| + | 
| +  void set_module(wasm::ModuleEnv *Module) { this->Module = Module; } | 
| + | 
| +  void set_control_ptr(Node *Control) { this->ControlPtr = Control; } | 
| + | 
| +  void set_effect_ptr(Node *Effect) { this->EffectPtr = Effect; } | 
| + | 
| +private: | 
| +  wasm::ModuleEnv *Module; | 
| +  Node *ControlPtr; | 
| +  Node *EffectPtr; | 
| + | 
| +  class Cfg *Func; | 
| +  GlobalContext *Ctx; | 
| + | 
| +  SizeT NextArg = 0; | 
| + | 
| +  CfgUnorderedMap<Operand *, InstPhi *> PhiMap; | 
| +  CfgUnorderedMap<Operand *, CfgNode *> DefNodeMap; | 
| + | 
| +  InstPhi *getDefiningInst(Operand *Op) const { | 
| +    const auto &Iter = PhiMap.find(Op); | 
| +    if (Iter == PhiMap.end()) { | 
| +      return nullptr; | 
| +    } | 
| +    return Iter->second; | 
| +  } | 
| + | 
| +  void setDefiningInst(Operand *Op, InstPhi *Phi) { | 
| +    LOG(out << "\n== setDefiningInst(" << Op << ", " << Phi << ") ==\n"); | 
| +    PhiMap.emplace(Op, Phi); | 
| +  } | 
| + | 
| +  Ice::Variable *makeVariable(Ice::Type Type) { | 
| +    return makeVariable(Type, Control()); | 
| +  } | 
| + | 
| +  Ice::Variable *makeVariable(Ice::Type Type, CfgNode *DefNode) { | 
| +    auto *Var = Func->makeVariable(Type); | 
| +    DefNodeMap.emplace(Var, DefNode); | 
| +    return Var; | 
| +  } | 
| + | 
| +  CfgNode *getDefNode(Operand *Op) const { | 
| +    const auto &Iter = DefNodeMap.find(Op); | 
| +    if (Iter == DefNodeMap.end()) { | 
| +      return nullptr; | 
| +    } | 
| +    return Iter->second; | 
| +  } | 
| + | 
| +  template <typename F = std::function<void(Ostream &)>> void log(F Fn) const { | 
| +    if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) { | 
| +      Fn(Ctx->getStrDump()); | 
| +      Ctx->getStrDump().flush(); | 
| +    } | 
| +  } | 
| +}; | 
| + | 
| +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) { | 
| +  OstreamLocker L1(Ctx); | 
| +  auto Func = Cfg::create(Ctx, getNextSequenceNumber()); | 
| +  Ice::CfgLocalAllocatorScope L2(Func.get()); | 
| + | 
| +  // TODO: parse the function signature... | 
| + | 
| +  IceBuilder Builder(Func.get()); | 
| +  LR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder); | 
| + | 
| +  LOG(out << getFlags().getDefaultGlobalPrefix() << "\n"); | 
| +  Decoder.Decode(Env, Base, Start, End); | 
| + | 
| +  // We don't always know where the incoming branches are in phi nodes, so this | 
| +  // function finds them. | 
| +  Func->fixPhiNodes(); | 
| + | 
| +  return Func; | 
| +} | 
| + | 
| +WasmTranslator::WasmTranslator(GlobalContext *Ctx) | 
| +    : Translator(Ctx), BufferSize(24 << 10), Buffer(new uint8_t[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. | 
| +} | 
| + | 
| +void WasmTranslator::translate( | 
| +    const std::string &IRFilename, | 
| +    std::unique_ptr<llvm::DataStreamer> InputStream) { | 
| +  LOG(out << "Initializing v8/wasm stuff..." | 
| +          << "\n"); | 
| +  Zone Zone; | 
| +  ZoneScope _(&Zone); | 
| + | 
| +  SizeT BytesRead = InputStream->GetBytes(Buffer.get(), BufferSize); | 
| +  LOG(out << "Read " << BytesRead << " bytes" | 
| +          << "\n"); | 
| + | 
| +  LOG(out << "Decoding module " << IRFilename << "\n"); | 
| + | 
| +  constexpr v8::internal::Isolate *NoIsolate = nullptr; | 
| +  auto Result = DecodeWasmModule(NoIsolate, &Zone, Buffer.get(), | 
| +                                 Buffer.get() + BytesRead, false, kWasmOrigin); | 
| + | 
| +  auto Module = Result.val; | 
| + | 
| +  LOG(out << "Module info:" | 
| +          << "\n"); | 
| +  LOG(out << "  number of globals:       " << Module->globals.size() << "\n"); | 
| +  LOG(out << "  number of signatures:    " << Module->signatures.size() | 
| +          << "\n"); | 
| +  LOG(out << "  number of functions:     " << Module->functions.size() << "\n"); | 
| +  LOG(out << "  number of data_segments: " << Module->data_segments.size() | 
| +          << "\n"); | 
| +  LOG(out << "  function table size:     " << Module->function_table.size() | 
| +          << "\n"); | 
| + | 
| +  ModuleEnv ModuleEnv; | 
| +  ModuleEnv.module = Module; | 
| + | 
| +  LOG(out << "\n" | 
| +          << "Function information:" | 
| +          << "\n"); | 
| +  for (const auto F : Module->functions) { | 
| +    LOG(out << "  " << F.name_offset << ": " << Module->GetName(F.name_offset)); | 
| +    if (F.exported) | 
| +      LOG(out << " export"); | 
| +    if (F.external) | 
| +      LOG(out << " extern"); | 
| +    LOG(out << "\n"); | 
| +  } | 
| + | 
| +  FunctionEnv Fenv; | 
| +  Fenv.module = &ModuleEnv; | 
| + | 
| +  LOG(out << "Translating " << IRFilename << "\n"); | 
| + | 
| +  // 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)); | 
| + | 
| +    Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func))); | 
| +    LOG(out << "done.\n"); | 
| +  } | 
| + | 
| +  return; | 
| +} | 
|  |