Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Unified Diff: src/WasmTranslator.cpp

Issue 1837663002: Initial Subzero WASM prototype. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Code review feedback and merging master Created 4 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/WasmTranslator.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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;
+}
« no previous file with comments | « src/WasmTranslator.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698