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"); |