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

Unified Diff: src/WasmTranslator.cpp

Issue 1876413002: Subzero. WASM. Additional progress. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Code review feedback and merging with 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') | wasm-tests/hello-printf.c » ('j') | 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
index b42ad7761442d9adee2475aaa18f9eefa8cb1f0a..6c1ed24659c1307cf613a8fd2233c9da218f6167 100644
--- a/src/WasmTranslator.cpp
+++ b/src/WasmTranslator.cpp
@@ -17,14 +17,33 @@
#if ALLOW_WASM
-#include "llvm/Support/StreamingMemoryObject.h"
-
#include "WasmTranslator.h"
+#ifdef __clang__
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wunused-parameter"
+#pragma clang diagnostic ignored "-Wcovered-switch-default"
+#endif // __clang__
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic push
+#pragma GCC diagnostic ignored "-Wunused-but-set-variable"
+#endif // defined(__GNUC__) && !defined(__clang__)
+
#include "src/wasm/module-decoder.h"
#include "src/wasm/wasm-opcodes.h"
#include "src/zone.h"
+#include "src/bit-vector.h"
+
+#include "src/wasm/ast-decoder-impl.h"
+
+#ifdef __clang__
+#pragma clang diagnostic pop
+#endif // __clang__
+#if defined(__GNUC__) && !defined(__clang__)
+#pragma GCC diagnostic pop
+#endif // defined(__GNUC__) && !defined(__clang__)
+
#include "IceCfgNode.h"
#include "IceGlobalInits.h"
@@ -35,21 +54,17 @@ using namespace v8::internal;
using namespace v8::internal::wasm;
using v8::internal::wasm::DecodeWasmModule;
-#include "src/wasm/ast-decoder-impl.h"
-
+#undef LOG
#define LOG(Expr) log([&](Ostream & out) { Expr; })
namespace {
-Ice::Type toIceType(v8::internal::MachineType) {
- // TODO(eholk): actually convert this.
- return IceType_i32;
+std::string toStdString(WasmName Name) {
+ return std::string(Name.name, Name.length);
}
Ice::Type toIceType(wasm::LocalType Type) {
switch (Type) {
- default:
- llvm::report_fatal_error("unexpected enum value");
case MachineRepresentation::kNone:
llvm::report_fatal_error("kNone type not supported");
case MachineRepresentation::kBit:
@@ -71,6 +86,57 @@ Ice::Type toIceType(wasm::LocalType Type) {
case MachineRepresentation::kTagged:
llvm::report_fatal_error("kTagged type not supported");
}
+ llvm::report_fatal_error("unexpected type");
+}
+
+Ice::Type toIceType(v8::internal::MachineType Type) {
+ // TODO (eholk): reorder these based on expected call frequency.
+ if (Type == MachineType::Int32()) {
+ return IceType_i32;
+ }
+ if (Type == MachineType::Uint32()) {
+ return IceType_i32;
+ }
+ if (Type == MachineType::Int8()) {
+ return IceType_i8;
+ }
+ if (Type == MachineType::Uint8()) {
+ return IceType_i8;
+ }
+ if (Type == MachineType::Int16()) {
+ return IceType_i16;
+ }
+ if (Type == MachineType::Uint16()) {
+ return IceType_i16;
+ }
+ if (Type == MachineType::Int64()) {
+ return IceType_i64;
+ }
+ if (Type == MachineType::Uint64()) {
+ return IceType_i64;
+ }
+ if (Type == MachineType::Float32()) {
+ return IceType_f32;
+ }
+ if (Type == MachineType::Float64()) {
+ return IceType_f64;
+ }
+ llvm::report_fatal_error("Unsupported MachineType");
+}
+
+std::string fnNameFromId(uint32_t Id) {
+ return std::string("fn") + to_string(Id);
+}
+
+std::string getFunctionName(const WasmModule *Module, uint32_t func_index) {
+ // Try to find the function name in the export table
+ for (const auto Export : Module->export_table) {
+ if (Export.func_index == func_index) {
+ return "__szwasm_" + toStdString(Module->GetName(Export.name_offset,
+ Export.name_length));
+ }
+ }
+ return fnNameFromId(func_index);
}
} // end of anonymous namespace
@@ -132,7 +198,11 @@ public:
Ostream &operator<<(Ostream &Out, const OperandNode &Op) {
if (Op.isOperand()) {
- Out << "(Operand*)" << Op.toOperand();
+ const auto *Oper = Op.toOperand();
+ Out << "(Operand*)" << Oper;
+ if (Oper) {
+ Out << "::" << Oper->getType();
+ }
} else if (Op.isCfgNode()) {
Out << "(CfgNode*)" << Op.toCfgNode();
} else {
@@ -141,7 +211,7 @@ Ostream &operator<<(Ostream &Out, const OperandNode &Op) {
return Out;
}
-constexpr bool isComparison(wasm::WasmOpcode Opcode) {
+bool isComparison(wasm::WasmOpcode Opcode) {
switch (Opcode) {
case kExprI32Ne:
case kExprI64Ne:
@@ -157,6 +227,16 @@ constexpr bool isComparison(wasm::WasmOpcode Opcode) {
case kExprI64GtS:
case kExprI32GtU:
case kExprI64GtU:
+ case kExprF32Ne:
+ case kExprF64Ne:
+ case kExprF32Le:
+ case kExprF64Le:
+ case kExprI32LeS:
+ case kExprI64LeS:
+ case kExprI32GeU:
+ case kExprI64GeU:
+ case kExprI32LeU:
+ case kExprI64LeU:
return true;
default:
return false;
@@ -172,7 +252,7 @@ class IceBuilder {
public:
explicit IceBuilder(class Cfg *Func)
- : Func(Func), Ctx(Func->getContext()), ControlPtr(nullptr) {}
+ : ControlPtr(nullptr), Func(Func), Ctx(Func->getContext()) {}
/// Allocates a buffer of Nodes for use by V8.
Node *Buffer(size_t Count) {
@@ -181,14 +261,14 @@ public:
}
Node Error() { llvm::report_fatal_error("Error"); }
- Node Start(unsigned Params) {
+ Node Start(uint32_t Params) {
LOG(out << "Start(" << Params << ") = ");
- auto *Entry = Func->makeNode();
- Func->setEntryNode(Entry);
+ auto *Entry = Func->getEntryNode();
+ assert(Entry);
LOG(out << Node(Entry) << "\n");
return OperandNode(Entry);
}
- Node Param(unsigned Index, wasm::LocalType Type) {
+ Node Param(uint32_t Index, wasm::LocalType Type) {
LOG(out << "Param(" << Index << ") = ");
auto *Arg = makeVariable(toIceType(Type));
assert(Index == NextArg);
@@ -208,25 +288,25 @@ public:
LOG(out << "Terminate(" << Effect << ", " << Control << ")"
<< "\n");
}
- Node Merge(unsigned Count, Node *Controls) {
+ Node Merge(uint32_t Count, Node *Controls) {
LOG(out << "Merge(" << Count);
- for (unsigned i = 0; i < Count; ++i) {
+ for (uint32_t i = 0; i < Count; ++i) {
LOG(out << ", " << Controls[i]);
}
LOG(out << ") = ");
auto *MergedNode = Func->makeNode();
- for (unsigned i = 0; i < Count; ++i) {
+ for (uint32_t i = 0; i < Count; ++i) {
CfgNode *Control = Controls[i];
Control->appendInst(InstBr::create(Func, MergedNode));
}
LOG(out << (OperandNode)MergedNode << "\n");
return OperandNode(MergedNode);
}
- Node Phi(wasm::LocalType Type, unsigned Count, Node *Vals, Node Control) {
+ Node Phi(wasm::LocalType, uint32_t Count, Node *Vals, Node Control) {
LOG(out << "Phi(" << Count << ", " << Control);
- for (int i = 0; i < Count; ++i) {
+ for (uint32_t i = 0; i < Count; ++i) {
LOG(out << ", " << Vals[i]);
}
LOG(out << ") = ");
@@ -243,7 +323,7 @@ public:
// TODO(eholk): find a better way besides multiplying by some arbitrary
// constant.
auto *Phi = InstPhi::create(Func, Count * 10, Dest);
- for (int i = 0; i < Count; ++i) {
+ for (uint32_t i = 0; i < Count; ++i) {
auto *Op = Vals[i].toOperand();
assert(Op);
Phi->addArgument(Op, InEdges[i]);
@@ -253,10 +333,10 @@ public:
LOG(out << Node(Dest) << "\n");
return OperandNode(Dest);
}
- Node EffectPhi(unsigned Count, Node *Effects, Node Control) {
+ Node EffectPhi(uint32_t Count, Node *Effects, Node Control) {
// TODO(eholk): this function is almost certainly wrong.
LOG(out << "EffectPhi(" << Count << ", " << Control << "):\n");
- for (unsigned i = 0; i < Count; ++i) {
+ for (uint32_t i = 0; i < Count; ++i) {
LOG(out << " " << Effects[i] << "\n");
}
return OperandNode(nullptr);
@@ -294,13 +374,18 @@ public:
LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left
<< ", " << Right << ") = ");
auto *Dest = makeVariable(
- isComparison(Opcode) ? IceType_i1 : Left.toOperand()->getType());
+ isComparison(Opcode) ? IceType_i32 : Left.toOperand()->getType());
switch (Opcode) {
case kExprI32Add:
case kExprI64Add:
Control()->appendInst(
InstArithmetic::create(Func, InstArithmetic::Add, Dest, Left, Right));
break;
+ case kExprF32Add:
+ case kExprF64Add:
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Fadd,
+ Dest, Left, Right));
+ break;
case kExprI32Sub:
case kExprI64Sub:
Control()->appendInst(
@@ -321,6 +406,11 @@ public:
Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Urem,
Dest, Left, Right));
break;
+ case kExprI32RemS:
+ case kExprI64RemS:
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Srem,
+ Dest, Left, Right));
+ break;
case kExprI32Ior:
case kExprI64Ior:
Control()->appendInst(
@@ -336,6 +426,28 @@ public:
Control()->appendInst(
InstArithmetic::create(Func, InstArithmetic::Shl, Dest, Left, Right));
break;
+ case kExprI32Rol: {
+ // TODO(eholk): add rotate as an ICE instruction to make it easier to take
+ // advantage of hardware support.
+
+ // TODO(eholk): don't hardcode so many numbers.
+ auto *Masked = makeVariable(IceType_i32);
+ auto *Bottom = makeVariable(IceType_i32);
+ auto *Top = makeVariable(IceType_i32);
+ Control()->appendInst(InstArithmetic::create(
+ Func, InstArithmetic::And, Masked, Right, Ctx->getConstantInt32(31)));
+ Control()->appendInst(
+ InstArithmetic::create(Func, InstArithmetic::Shl, Top, Left, Masked));
+ auto *RotShift = makeVariable(IceType_i32);
+ Control()->appendInst(
+ InstArithmetic::create(Func, InstArithmetic::Sub, RotShift,
+ Ctx->getConstantInt32(32), Masked));
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Lshr,
+ Bottom, Left, Masked));
+ Control()->appendInst(
+ InstArithmetic::create(Func, InstArithmetic::Or, Dest, Top, Bottom));
+ break;
+ }
case kExprI32ShrU:
case kExprI64ShrU:
case kExprI32ShrS:
@@ -349,39 +461,112 @@ public:
InstArithmetic::create(Func, InstArithmetic::And, Dest, Left, Right));
break;
case kExprI32Ne:
- case kExprI64Ne:
+ case kExprI64Ne: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstIcmp::create(Func, InstIcmp::Ne, TmpDest, Left, Right));
Control()->appendInst(
- InstIcmp::create(Func, InstIcmp::Ne, Dest, Left, Right));
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
break;
+ }
case kExprI32Eq:
- case kExprI64Eq:
+ case kExprI64Eq: {
+ auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
- InstIcmp::create(Func, InstIcmp::Eq, Dest, Left, Right));
+ InstIcmp::create(Func, InstIcmp::Eq, TmpDest, Left, Right));
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
break;
+ }
case kExprI32LtS:
- case kExprI64LtS:
+ case kExprI64LtS: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstIcmp::create(Func, InstIcmp::Slt, TmpDest, Left, Right));
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+ break;
+ }
+ case kExprI32LeS:
+ case kExprI64LeS: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstIcmp::create(Func, InstIcmp::Sle, TmpDest, Left, Right));
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+ break;
+ }
+ case kExprI32GeU:
+ case kExprI64GeU: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstIcmp::create(Func, InstIcmp::Uge, TmpDest, Left, Right));
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+ break;
+ }
+ case kExprI32LeU:
+ case kExprI64LeU: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstIcmp::create(Func, InstIcmp::Ule, TmpDest, Left, Right));
Control()->appendInst(
- InstIcmp::create(Func, InstIcmp::Slt, Dest, Left, Right));
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
break;
+ }
case kExprI32LtU:
- case kExprI64LtU:
+ case kExprI64LtU: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstIcmp::create(Func, InstIcmp::Ult, TmpDest, Left, Right));
Control()->appendInst(
- InstIcmp::create(Func, InstIcmp::Ult, Dest, Left, Right));
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
break;
+ }
case kExprI32GeS:
- case kExprI64GeS:
+ case kExprI64GeS: {
+ auto *TmpDest = makeVariable(IceType_i1);
Control()->appendInst(
- InstIcmp::create(Func, InstIcmp::Sge, Dest, Left, Right));
+ InstIcmp::create(Func, InstIcmp::Sge, TmpDest, Left, Right));
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+ }
case kExprI32GtS:
- case kExprI64GtS:
+ case kExprI64GtS: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstIcmp::create(Func, InstIcmp::Sgt, TmpDest, Left, Right));
Control()->appendInst(
- InstIcmp::create(Func, InstIcmp::Sgt, Dest, Left, Right));
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
break;
+ }
case kExprI32GtU:
- case kExprI64GtU:
+ case kExprI64GtU: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstIcmp::create(Func, InstIcmp::Ugt, TmpDest, Left, Right));
Control()->appendInst(
- InstIcmp::create(Func, InstIcmp::Ugt, Dest, Left, Right));
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
break;
+ }
+ case kExprF32Ne:
+ case kExprF64Ne: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstFcmp::create(Func, InstFcmp::Une, TmpDest, Left, Right));
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+ break;
+ }
+ case kExprF32Le:
+ case kExprF64Le: {
+ auto *TmpDest = makeVariable(IceType_i1);
+ Control()->appendInst(
+ InstFcmp::create(Func, InstFcmp::Ule, TmpDest, Left, Right));
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Dest, TmpDest));
+ break;
+ }
default:
LOG(out << "Unknown binop: " << WasmOpcodes::OpcodeName(Opcode) << "\n");
llvm::report_fatal_error("Uncovered or invalid binop.");
@@ -395,6 +580,14 @@ public:
<< ") = ");
Ice::Variable *Dest = nullptr;
switch (Opcode) {
+ case kExprI32Eqz: {
+ Dest = makeVariable(IceType_i32);
+ auto *Tmp = makeVariable(IceType_i1);
+ Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input,
+ Ctx->getConstantInt32(0)));
+ Control()->appendInst(InstCast::create(Func, InstCast::Sext, Dest, Tmp));
+ break;
+ }
case kExprF32Neg: {
Dest = makeVariable(IceType_f32);
Control()->appendInst(InstArithmetic::create(
@@ -412,6 +605,21 @@ public:
Control()->appendInst(
InstCast::create(Func, InstCast::Zext, Dest, Input));
break;
+ case kExprI64SConvertI32:
+ Dest = makeVariable(IceType_i64);
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Dest, Input));
+ break;
+ case kExprI32ConvertI64:
+ Dest = makeVariable(IceType_i32);
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Trunc, Dest, Input));
+ break;
+ case kExprF64SConvertI32:
+ Dest = makeVariable(IceType_f64);
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sitofp, Dest, Input));
+ break;
default:
LOG(out << "Unknown unop: " << WasmOpcodes::OpcodeName(Opcode) << "\n");
llvm::report_fatal_error("Uncovered or invalid unop.");
@@ -420,14 +628,14 @@ public:
LOG(out << Dest << "\n");
return OperandNode(Dest);
}
- unsigned InputCount(CfgNode *Node) const { return Node->getInEdges().size(); }
+ uint32_t InputCount(CfgNode *Node) const { return Node->getInEdges().size(); }
bool IsPhiWithMerge(Node Phi, Node Merge) const {
LOG(out << "IsPhiWithMerge(" << Phi << ", " << Merge << ")"
<< "\n");
if (Phi && Phi.isOperand()) {
LOG(out << " ...is operand"
<< "\n");
- if (auto *Inst = getDefiningInst(Phi)) {
+ if (getDefiningInst(Phi)) {
LOG(out << " ...has defining instruction"
<< "\n");
LOG(out << getDefNode(Phi) << "\n");
@@ -444,6 +652,7 @@ public:
LOG(out << "AppendToPhi(" << Merge << ", " << Phi << ", " << From << ")"
<< "\n");
auto *Inst = getDefiningInst(Phi);
+ assert(Inst->getDest()->getType() == From.toOperand()->getType());
Inst->addArgument(From, getDefNode(From));
}
@@ -463,13 +672,50 @@ public:
LOG(out << *TrueNode << ", " << *FalseNode << ")"
<< "\n");
- Ctrl->appendInst(InstBr::create(Func, Cond, *TrueNode, *FalseNode));
+ auto *CondBool = makeVariable(IceType_i1);
+ Ctrl->appendInst(InstCast::create(Func, InstCast::Trunc, CondBool, Cond));
+
+ Ctrl->appendInst(InstBr::create(Func, CondBool, *TrueNode, *FalseNode));
return OperandNode(nullptr);
}
- Node Switch(unsigned Count, Node Key) { llvm::report_fatal_error("Switch"); }
- Node IfValue(int32_t Value, Node Sw) { llvm::report_fatal_error("IfValue"); }
- Node IfDefault(Node Sw) { llvm::report_fatal_error("IfDefault"); }
- Node Return(unsigned Count, Node *Vals) {
+ InstSwitch *CurrentSwitch = nullptr;
+ CfgNode *SwitchNode = nullptr;
+ SizeT SwitchIndex = 0;
+ Node Switch(uint32_t Count, Node Key) {
+ LOG(out << "Switch(" << Count << ", " << Key << ")\n");
+
+ assert(!CurrentSwitch);
+
+ auto *Default = Func->makeNode();
+ // Count - 1 because the decoder counts the default label but Subzero does
+ // not.
+ CurrentSwitch = InstSwitch::create(Func, Count - 1, Key, Default);
+ SwitchIndex = 0;
+ SwitchNode = Control();
+ // We don't actually append the switch to the CfgNode here because not all
+ // the branches are ready.
+ return Node(nullptr);
+ }
+ Node IfValue(int32_t Value, Node) {
+ LOG(out << "IfValue(" << Value << ") [Index = " << SwitchIndex << "]\n");
+ assert(CurrentSwitch);
+ auto *Target = Func->makeNode();
+ CurrentSwitch->addBranch(SwitchIndex++, Value, Target);
+ return Node(Target);
+ }
+ Node IfDefault(Node) {
+ LOG(out << "IfDefault(...) [Index = " << SwitchIndex << "]\n");
+ assert(CurrentSwitch);
+ assert(CurrentSwitch->getLabelDefault());
+ // Now we append the switch, since this should be the last edge.
+ assert(SwitchIndex == CurrentSwitch->getNumCases());
+ SwitchNode->appendInst(CurrentSwitch);
+ SwitchNode = nullptr;
+ auto Default = Node(CurrentSwitch->getLabelDefault());
+ CurrentSwitch = nullptr;
+ return Default;
+ }
+ Node Return(uint32_t Count, Node *Vals) {
assert(1 >= Count);
LOG(out << "Return(");
if (Count > 0)
@@ -511,20 +757,20 @@ public:
const auto NumArgs = Sig->parameter_count();
LOG(out << " number of args: " << NumArgs << "\n");
- const auto TargetName =
- Ctx->getGlobalString(Module->GetName(Target.name_offset));
+ const auto TargetName = getFunctionName(Module, Index);
LOG(out << " target name: " << TargetName << "\n");
assert(Sig->return_count() <= 1);
- auto *TargetOperand = Ctx->getConstantSym(0, TargetName);
+ auto TargetOperand =
+ Ctx->getConstantSym(0, Ctx->getGlobalString(TargetName));
auto *Dest = Sig->return_count() > 0
? makeVariable(toIceType(Sig->GetReturn()))
: nullptr;
auto *Call = InstCall::create(Func, NumArgs, Dest, TargetOperand,
false /* HasTailCall */);
- for (int i = 0; i < NumArgs; ++i) {
+ for (uint32_t i = 0; i < NumArgs; ++i) {
// The builder reserves the first argument for the code object.
LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n");
Call->addArg(Args[i + 1]);
@@ -545,13 +791,17 @@ public:
LOG(out << " number of args: " << NumArgs << "\n");
const auto &Target = Module->import_table[Index];
- const auto TargetName =
- Ctx->getGlobalString(Module->GetName(Target.function_name_offset));
+ const auto ModuleName = toStdString(
+ Module->GetName(Target.module_name_offset, Target.module_name_length));
+ const auto FnName = toStdString(Module->GetName(
+ Target.function_name_offset, Target.function_name_length));
+
+ const auto TargetName = Ctx->getGlobalString(ModuleName + "$$" + FnName);
LOG(out << " target name: " << TargetName << "\n");
assert(Sig->return_count() <= 1);
- auto *TargetOperand = Ctx->getConstantSym(0, TargetName);
+ auto TargetOperand = Ctx->getConstantExternSym(TargetName);
auto *Dest = Sig->return_count() > 0
? makeVariable(toIceType(Sig->GetReturn()))
@@ -559,9 +809,10 @@ public:
constexpr bool NoTailCall = false;
auto *Call =
InstCall::create(Func, NumArgs, Dest, TargetOperand, NoTailCall);
- for (int i = 0; i < NumArgs; ++i) {
+ for (uint32_t i = 0; i < NumArgs; ++i) {
// The builder reserves the first argument for the code object.
LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n");
+ assert(Args[i + 1].toOperand()->getType() == toIceType(Sig->GetParam(i)));
Call->addArg(Args[i + 1]);
}
@@ -569,41 +820,140 @@ public:
LOG(out << "Call Result = " << Node(Dest) << "\n");
return OperandNode(Dest);
}
- Node CallIndirect(uint32_t Index, Node *Args) {
- llvm::report_fatal_error("CallIndirect");
+ Node CallIndirect(uint32_t SigIndex, Node *Args) {
+ LOG(out << "CallIndirect(" << SigIndex << ")\n");
+ // TODO(eholk): Compile to something better than a switch.
+ const auto *Module = this->Module->module;
+ assert(Module);
+ const auto &IndirectTable = Module->function_table;
+
+ // TODO(eholk): This should probably actually call abort instead.
+ auto *Abort = Func->makeNode();
+ Abort->appendInst(InstUnreachable::create(Func));
+
+ assert(Args[0].toOperand());
+
+ auto *Switch = InstSwitch::create(Func, IndirectTable.size(),
+ Args[0].toOperand(), Abort);
+ assert(Abort);
+
+ const bool HasReturn = Module->signatures[SigIndex]->return_count() != 0;
+ const Ice::Type DestTy =
+ HasReturn ? toIceType(Module->signatures[SigIndex]->GetReturn())
+ : IceType_void;
+
+ auto *Dest = HasReturn ? makeVariable(DestTy) : nullptr;
+
+ auto *ExitNode = Func->makeNode();
+ auto *PhiInst =
+ HasReturn ? InstPhi::create(Func, IndirectTable.size(), Dest) : nullptr;
+
+ for (uint32_t Index = 0; Index < IndirectTable.size(); ++Index) {
+ const auto &Target = Module->functions[IndirectTable[Index]];
+
+ if (SigIndex == Target.sig_index) {
+ auto *CallNode = Func->makeNode();
+ auto *SavedControl = Control();
+ *ControlPtr = OperandNode(CallNode);
+ auto *Tmp = CallDirect(Target.func_index, Args).toOperand();
+ *ControlPtr = OperandNode(SavedControl);
+ if (PhiInst) {
+ PhiInst->addArgument(Tmp, CallNode);
+ }
+ CallNode->appendInst(InstBr::create(Func, ExitNode));
+ Switch->addBranch(Index, Index, CallNode);
+ } else {
+ Switch->addBranch(Index, Index, Abort);
+ }
+ }
+
+ if (PhiInst) {
+ ExitNode->appendInst(PhiInst);
+ }
+
+ Control()->appendInst(Switch);
+ *ControlPtr = OperandNode(ExitNode);
+ return OperandNode(Dest);
+ }
+ Node Invert(Node Node) {
+ (void)Node;
+ llvm::report_fatal_error("Invert");
}
- Node Invert(Node Node) { llvm::report_fatal_error("Invert"); }
- Node FunctionTable() { llvm::report_fatal_error("FunctionTable"); }
//-----------------------------------------------------------------------
// Operations that concern the linear memory.
//-----------------------------------------------------------------------
- Node MemSize(uint32_t Offset) { llvm::report_fatal_error("MemSize"); }
- Node LoadGlobal(uint32_t Index) { llvm::report_fatal_error("LoadGlobal"); }
+ Node MemSize(uint32_t Offset) {
+ (void)Offset;
+ llvm::report_fatal_error("MemSize");
+ }
+ Node LoadGlobal(uint32_t Index) {
+ (void)Index;
+ llvm::report_fatal_error("LoadGlobal");
+ }
Node StoreGlobal(uint32_t Index, Node Val) {
+ (void)Index;
+ (void)Val;
llvm::report_fatal_error("StoreGlobal");
}
+
+ Operand *sanitizeAddress(Operand *Base, uint32_t Offset) {
+ // first, add the index and the offset together.
+ if (0 != Offset) {
+ auto *Addr = makeVariable(IceType_i32);
+ auto *OffsetConstant = Ctx->getConstantInt32(Offset);
+ Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
+ Addr, Base, OffsetConstant));
+ Base = Addr;
+ }
+
+ SizeT MemSize = Module->module->min_mem_pages * (16 << 10);
+ auto *WrappedAddr = makeVariable(IceType_i32);
+ Control()->appendInst(
+ InstArithmetic::create(Func, InstArithmetic::Add, WrappedAddr, Base,
+ Ctx->getConstantInt32(MemSize)));
+
+ auto ClampedAddr = makeVariable(IceType_i32);
+ Control()->appendInst(
+ InstArithmetic::create(Func, InstArithmetic::And, ClampedAddr, Base,
+ Ctx->getConstantInt32(MemSize - 1)));
+
+ auto RealAddr = Func->makeVariable(IceType_i32);
+ auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY"));
+ Control()->appendInst(InstArithmetic::create(
+ Func, InstArithmetic::Add, RealAddr, ClampedAddr, MemBase));
+ return RealAddr;
+ }
+
Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index,
uint32_t Offset) {
LOG(out << "LoadMem(" << Index << "[" << Offset << "]) = ");
- // first, add the index and the offset together.
- auto *OffsetConstant = Ctx->getConstantInt32(Offset);
- auto *Addr = makeVariable(IceType_i32);
- Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
- Addr, Index, OffsetConstant));
+ auto *RealAddr = sanitizeAddress(Index, Offset);
- // then load the memory
auto *LoadResult = makeVariable(toIceType(MemType));
- Control()->appendInst(InstLoad::create(Func, LoadResult, Addr));
+ Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr));
// and cast, if needed
Ice::Variable *Result = nullptr;
if (toIceType(Type) != toIceType(MemType)) {
- Result = makeVariable(toIceType(Type));
+ auto DestType = toIceType(Type);
+ Result = makeVariable(DestType);
// TODO(eholk): handle signs correctly.
- Control()->appendInst(
- InstCast::create(Func, InstCast::Sext, Result, LoadResult));
+ if (isScalarIntegerType(DestType)) {
+ if (MemType.IsSigned()) {
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sext, Result, LoadResult));
+ } else {
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Zext, Result, LoadResult));
+ }
+ } else if (isScalarFloatingType(DestType)) {
+ Control()->appendInst(
+ InstCast::create(Func, InstCast::Sitofp, Result, LoadResult));
+ } else {
+ llvm::report_fatal_error("Unsupported type for memory load");
+ }
} else {
Result = LoadResult;
}
@@ -615,13 +965,7 @@ public:
LOG(out << "StoreMem(" << Index << "[" << Offset << "] = " << Val << ")"
<< "\n");
- // TODO(eholk): surely there is a better way to do this.
-
- // first, add the index and the offset together.
- auto *OffsetConstant = Ctx->getConstantInt32(Offset);
- auto *Addr = makeVariable(IceType_i32);
- Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
- Addr, Index, OffsetConstant));
+ auto *RealAddr = sanitizeAddress(Index, Offset);
// cast the value to the right type, if needed
Operand *StoreVal = nullptr;
@@ -635,10 +979,11 @@ public:
}
// then store the memory
- Control()->appendInst(InstStore::create(Func, StoreVal, Addr));
+ Control()->appendInst(InstStore::create(Func, StoreVal, RealAddr));
}
- static void PrintDebugName(Node node) {
+ static void PrintDebugName(OperandNode Node) {
+ (void)Node;
llvm::report_fatal_error("PrintDebugName");
}
@@ -705,36 +1050,33 @@ private:
}
};
-std::string fnNameFromId(uint32_t Id) {
- return std::string("fn") + to_string(Id);
-}
-
std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone,
- FunctionEnv *Env,
- const byte *Base,
- const byte *Start,
- const byte *End) {
+ FunctionBody &Body) {
OstreamLocker L1(Ctx);
auto Func = Cfg::create(Ctx, getNextSequenceNumber());
Ice::CfgLocalAllocatorScope L2(Func.get());
- // TODO: parse the function signature...
+ // TODO(eholk): parse the function signature...
+
+ Func->setEntryNode(Func->makeNode());
IceBuilder Builder(Func.get());
- LR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder);
+ SR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder, Body);
LOG(out << getFlags().getDefaultGlobalPrefix() << "\n");
- Decoder.Decode(Env, Base, Start, End);
+ Decoder.Decode();
// We don't always know where the incoming branches are in phi nodes, so this
// function finds them.
Func->fixPhiNodes();
+ Func->computeInOutEdges();
+
return Func;
}
WasmTranslator::WasmTranslator(GlobalContext *Ctx)
- : Translator(Ctx), BufferSize(24 << 10), Buffer(new uint8_t[24 << 10]) {
+ : Translator(Ctx), Buffer(new uint8_t[24 << 10]), BufferSize(24 << 10) {
// TODO(eholk): compute the correct buffer size. This uses 24k by default,
// which has been big enough for testing but is not a general solution.
}
@@ -761,6 +1103,8 @@ void WasmTranslator::translate(
LOG(out << "Module info:"
<< "\n");
+ LOG(out << " min_mem_pages: " << Module->min_mem_pages << "\n");
+ LOG(out << " max_mem_pages: " << Module->max_mem_pages << "\n");
LOG(out << " number of globals: " << Module->globals.size() << "\n");
LOG(out << " number of signatures: " << Module->signatures.size()
<< "\n");
@@ -769,15 +1113,56 @@ void WasmTranslator::translate(
<< "\n");
LOG(out << " function table size: " << Module->function_table.size()
<< "\n");
+ LOG(out << " import table size: " << Module->import_table.size()
+ << "\n");
+ LOG(out << " export table size: " << Module->export_table.size()
+ << "\n");
- ModuleEnv ModuleEnv;
- ModuleEnv.module = Module;
+ LOG(out << "\n"
+ << "Data segment information:"
+ << "\n");
+ uint32_t Id = 0;
+ for (const auto Seg : Module->data_segments) {
+ LOG(out << Id << ": (" << Seg.source_offset << ", " << Seg.source_size
+ << ") => " << Seg.dest_addr);
+ if (Seg.init) {
+ LOG(out << " init\n");
+ } else {
+ LOG(out << "\n");
+ }
+ Id++;
+ }
+
+ LOG(out << "\n"
+ << "Import information:"
+ << "\n");
+ for (const auto Import : Module->import_table) {
+ auto ModuleName = toStdString(
+ Module->GetName(Import.module_name_offset, Import.module_name_length));
+ auto FnName = toStdString(Module->GetName(Import.function_name_offset,
+ Import.function_name_length));
+ LOG(out << " " << Import.sig_index << ": " << ModuleName << "::" << FnName
+ << "\n");
+ }
+
+ LOG(out << "\n"
+ << "Export information:"
+ << "\n");
+ for (const auto Export : Module->export_table) {
+ LOG(out << " " << Export.func_index << ": "
+ << toStdString(
+ Module->GetName(Export.name_offset, Export.name_length))
+ << " (" << Export.name_offset << ", " << Export.name_length << ")");
+ LOG(out << "\n");
+ }
LOG(out << "\n"
<< "Function information:"
<< "\n");
for (const auto F : Module->functions) {
- LOG(out << " " << F.name_offset << ": " << Module->GetName(F.name_offset));
+ LOG(out << " " << F.func_index << ": "
+ << toStdString(Module->GetName(F.name_offset, F.name_length))
+ << " (" << F.name_offset << ", " << F.name_length << ")");
if (F.exported)
LOG(out << " export");
if (F.external)
@@ -785,29 +1170,76 @@ void WasmTranslator::translate(
LOG(out << "\n");
}
- FunctionEnv Fenv;
- Fenv.module = &ModuleEnv;
+ LOG(out << "\n"
+ << "Indirect table:"
+ << "\n");
+ for (uint32_t F : Module->function_table) {
+ LOG(out << " " << F << ": " << getFunctionName(Module, F) << "\n");
+ }
+
+ ModuleEnv ModuleEnv;
+ ModuleEnv.module = Module;
+
+ FunctionBody Body;
+ Body.module = &ModuleEnv;
LOG(out << "Translating " << IRFilename << "\n");
+ {
+ unique_ptr<VariableDeclarationList> Globals =
+ makeUnique<VariableDeclarationList>();
+
+ // Global variables, etc go here.
+ auto *WasmMemory = VariableDeclaration::createExternal(Globals.get());
+ WasmMemory->setName(Ctx->getGlobalString("WASM_MEMORY"));
+
+ // Fill in the segments
+ SizeT WritePtr = 0;
+ for (const auto Seg : Module->data_segments) {
+ // fill in gaps with zero.
+ if (Seg.dest_addr > WritePtr) {
+ WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
+ Globals.get(), Seg.dest_addr - WritePtr));
+ WritePtr = Seg.dest_addr;
+ }
+
+ // Add the data
+ WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create(
+ Globals.get(), reinterpret_cast<const char *>(Module->module_start) +
+ Seg.source_offset,
+ Seg.source_size));
+
+ WritePtr += Seg.source_size;
+ }
+
+ // Pad the rest with zeros
+ SizeT DataSize = Module->min_mem_pages * (64 << 10);
+ if (WritePtr < DataSize) {
+ WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
+ Globals.get(), DataSize - WritePtr));
+ }
+
+ WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
+ Globals.get(), Module->min_mem_pages * (64 << 10)));
+
+ Globals->push_back(WasmMemory);
+
+ lowerGlobals(std::move(Globals));
+ }
+
// Translate each function.
- uint32_t Id = 0;
for (const auto Fn : Module->functions) {
- std::string NewName = fnNameFromId(Id++);
- LOG(out << " " << Fn.name_offset << ": " << Module->GetName(Fn.name_offset)
- << " -> " << NewName << "...");
-
- Fenv.sig = Fn.sig;
- Fenv.local_i32_count = Fn.local_i32_count;
- Fenv.local_i64_count = Fn.local_i64_count;
- Fenv.local_f32_count = Fn.local_f32_count;
- Fenv.local_f64_count = Fn.local_f64_count;
- Fenv.SumLocals();
-
- auto Func = translateFunction(&Zone, &Fenv, Buffer.get(),
- Buffer.get() + Fn.code_start_offset,
- Buffer.get() + Fn.code_end_offset);
- Func->setFunctionName(Ctx->getGlobalString(NewName));
+ const auto FnName = getFunctionName(Module, Fn.func_index);
+
+ LOG(out << " " << Fn.func_index << ": " << FnName << "...");
+
+ Body.sig = Fn.sig;
+ Body.base = Buffer.get();
+ Body.start = Buffer.get() + Fn.code_start_offset;
+ Body.end = Buffer.get() + Fn.code_end_offset;
+
+ auto Func = translateFunction(&Zone, Body);
+ Func->setFunctionName(Ctx->getGlobalString(FnName));
Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func)));
LOG(out << "done.\n");
« no previous file with comments | « src/WasmTranslator.h ('k') | wasm-tests/hello-printf.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698