Chromium Code Reviews| Index: src/WasmTranslator.cpp |
| diff --git a/src/WasmTranslator.cpp b/src/WasmTranslator.cpp |
| index b42ad7761442d9adee2475aaa18f9eefa8cb1f0a..853b520391c9e0665e97dc0de4d9d40c8baef8e3 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,58 @@ Ice::Type toIceType(wasm::LocalType Type) { |
| case MachineRepresentation::kTagged: |
| llvm::report_fatal_error("kTagged type not supported"); |
| } |
| + llvm_unreachable("unexpected type"); |
|
Jim Stichnoth
2016/04/14 20:03:44
Might as well make this report_fatal_error like ab
Eric Holk
2016/04/15 15:24:27
Done.
|
| +} |
| + |
| +Ice::Type toIceType(v8::internal::MachineType Type) { |
| + if (Type == MachineType::Int8()) { |
| + return IceType_i8; |
| + } else if (Type == MachineType::Uint8()) { |
|
Jim Stichnoth
2016/04/14 20:03:44
All these "else if" should just be "if" because of
Eric Holk
2016/04/15 15:24:27
I changed the `else if` to `if`.
I moved the 32-b
|
| + return IceType_i8; |
| + } else if (Type == MachineType::Int16()) { |
| + return IceType_i16; |
| + } else if (Type == MachineType::Uint16()) { |
| + return IceType_i16; |
| + } else if (Type == MachineType::Int32()) { |
| + return IceType_i32; |
| + } else if (Type == MachineType::Uint32()) { |
| + return IceType_i32; |
| + } else if (Type == MachineType::Int64()) { |
| + return IceType_i64; |
| + } else if (Type == MachineType::Uint64()) { |
| + return IceType_i64; |
| + } else if (Type == MachineType::Float32()) { |
| + return IceType_f32; |
| + } else if (Type == MachineType::Float64()) { |
| + return IceType_f64; |
| + } else { |
| + 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) { |
| + std::string FnName; |
| + bool NameFound = false; |
| + |
| + // Try to find the function name in the export table |
| + for (const auto Export : Module->export_table) { |
| + if (Export.func_index == func_index) { |
| + NameFound = true; |
| + FnName = "__szwasm_" + toStdString(Module->GetName(Export.name_offset, |
| + Export.name_length)); |
| + break; |
|
Jim Stichnoth
2016/04/14 20:03:44
Can you just return FnName here, and remove the Na
Eric Holk
2016/04/15 15:24:27
Done.
|
| + } |
| + } |
| + |
| + if (!NameFound) { |
| + FnName = fnNameFromId(func_index); |
| + } |
| + |
| + return FnName; |
| } |
| } // end of anonymous namespace |
| @@ -132,7 +199,11 @@ public: |
| Ostream &operator<<(Ostream &Out, const OperandNode &Op) { |
| if (Op.isOperand()) { |
| - Out << "(Operand*)" << Op.toOperand(); |
| + auto *Oper = Op.toOperand(); |
|
Jim Stichnoth
2016/04/14 20:03:44
const auto * ?
Eric Holk
2016/04/15 15:24:27
Done.
|
| + Out << "(Operand*)" << Oper; |
| + if (Oper) { |
| + Out << "::" << Oper->getType(); |
| + } |
| } else if (Op.isCfgNode()) { |
| Out << "(CfgNode*)" << Op.toCfgNode(); |
| } else { |
| @@ -141,7 +212,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 +228,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 +253,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) { |
| @@ -183,8 +264,8 @@ public: |
| Node Error() { llvm::report_fatal_error("Error"); } |
| Node Start(unsigned 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); |
| } |
| @@ -224,9 +305,9 @@ public: |
| LOG(out << (OperandNode)MergedNode << "\n"); |
| return OperandNode(MergedNode); |
| } |
| - Node Phi(wasm::LocalType Type, unsigned Count, Node *Vals, Node Control) { |
| + Node Phi(wasm::LocalType, unsigned Count, Node *Vals, Node Control) { |
|
Jim Stichnoth
2016/04/14 20:03:44
Can all these unsigneds be uint32_t instead? That
Eric Holk
2016/04/15 15:24:27
Done.
|
| 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 +324,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]); |
| @@ -294,13 +375,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 +407,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 +427,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 +462,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, TmpDest, Left, Right)); |
| Control()->appendInst( |
| - InstIcmp::create(Func, InstIcmp::Eq, Dest, Left, Right)); |
| + InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| break; |
| + } |
| case kExprI32LtS: |
| - case kExprI64LtS: |
| + case kExprI64LtS: { |
| + auto *TmpDest = makeVariable(IceType_i1); |
| Control()->appendInst( |
| - InstIcmp::create(Func, InstIcmp::Slt, Dest, Left, Right)); |
| + InstIcmp::create(Func, InstIcmp::Slt, TmpDest, Left, Right)); |
| + Control()->appendInst( |
| + InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| break; |
| + } |
| + case kExprI32LeS: |
| + case kExprI64LeS: { |
| + auto *TmpDest = makeVariable(IceType_i1); |
| + Control()->appendInst( |
| + InstIcmp::create(Func, InstIcmp::Sle, TmpDest, Left, Right)); |
| + Control()->appendInst( |
| + InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| + break; |
| + } |
| + case kExprI32GeU: |
| + case kExprI64GeU: { |
| + auto *TmpDest = makeVariable(IceType_i1); |
| + Control()->appendInst( |
| + InstIcmp::create(Func, InstIcmp::Uge, TmpDest, Left, Right)); |
| + Control()->appendInst( |
| + InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| + break; |
| + } |
| + case kExprI32LeU: |
| + case kExprI64LeU: { |
| + auto *TmpDest = makeVariable(IceType_i1); |
| + Control()->appendInst( |
| + InstIcmp::create(Func, InstIcmp::Ule, TmpDest, Left, Right)); |
| + Control()->appendInst( |
| + InstCast::create(Func, InstCast::Sext, Dest, TmpDest)); |
| + break; |
| + } |
| case kExprI32LtU: |
| - case kExprI64LtU: |
| + case kExprI64LtU: { |
| + auto *TmpDest = makeVariable(IceType_i1); |
| + Control()->appendInst( |
| + InstIcmp::create(Func, InstIcmp::Ult, 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, TmpDest, Left, Right)); |
| Control()->appendInst( |
| - InstIcmp::create(Func, InstIcmp::Sge, Dest, Left, Right)); |
| + 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( |
| + 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( |
| - InstIcmp::create(Func, InstIcmp::Ugt, Dest, Left, Right)); |
| + 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 +581,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 +606,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."); |
| @@ -427,7 +636,7 @@ public: |
| 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 +653,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,12 +673,49 @@ 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"); } |
| + InstSwitch *CurrentSwitch = nullptr; |
| + CfgNode *SwitchNode = nullptr; |
| + SizeT SwitchIndex = 0; |
| + Node Switch(unsigned 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(unsigned Count, Node *Vals) { |
| assert(1 >= Count); |
| LOG(out << "Return("); |
| @@ -511,20 +758,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 +792,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 +810,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 +821,141 @@ 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(InstBreakpoint::create(Func)); |
|
Jim Stichnoth
2016/04/14 20:03:44
remove?
Eric Holk
2016/04/15 15:24:27
Done.
|
| + 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_unreachable("Unsupported type for memory load"); |
| + } |
| } else { |
| Result = LoadResult; |
| } |
| @@ -615,13 +967,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 +981,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 +1052,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 +1105,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 +1115,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 +1172,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)); |
| + std::string FnName = getFunctionName(Module, Fn.func_index); |
|
Jim Stichnoth
2016/04/14 20:03:44
use "auto", like above?
Eric Holk
2016/04/15 15:24:27
Done. I went ahead and made it const too.
|
| + |
| + 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"); |