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

Side by Side Diff: src/WasmTranslator.cpp

Issue 1890283002: Subzero, Wasm: Link and run torture tests; bug fixes. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: 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 unified diff | Download patch
OLDNEW
1 //===- subzero/src/WasmTranslator.cpp - WASM to Subzero Translation -------===// 1 //===- subzero/src/WasmTranslator.cpp - WASM to Subzero Translation -------===//
2 // 2 //
3 // The Subzero Code Generator 3 // The Subzero Code Generator
4 // 4 //
5 // This file is distributed under the University of Illinois Open Source 5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details. 6 // License. See LICENSE.TXT for details.
7 // 7 //
8 //===----------------------------------------------------------------------===// 8 //===----------------------------------------------------------------------===//
9 /// 9 ///
10 /// \file 10 /// \file
11 /// \brief Defines a driver for translating Wasm bitcode into PNaCl bitcode. 11 /// \brief Defines a driver for translating Wasm bitcode into PNaCl bitcode.
12 /// 12 ///
13 /// The translator uses V8's WebAssembly decoder to handle the binary Wasm 13 /// The translator uses V8's WebAssembly decoder to handle the binary Wasm
14 /// format but replaces the usual TurboFan builder with a new PNaCl builder. 14 /// format but replaces the usual TurboFan builder with a new PNaCl builder.
15 /// 15 ///
16 //===----------------------------------------------------------------------===// 16 //===----------------------------------------------------------------------===//
17 17
18 #if ALLOW_WASM 18 #if ALLOW_WASM
19 19
20 #include "llvm/Support/StreamingMemoryObject.h" 20 #include "WasmTranslator.h"
21 21
22 #include "WasmTranslator.h" 22 #ifdef __clang__
23 #pragma clang diagnostic push
24 #pragma clang diagnostic ignored "-Wunused-parameter"
25 #pragma clang diagnostic ignored "-Wcovered-switch-default"
26 #endif // __clang__
27 #if defined(__GNUC__) && !defined(__clang__)
28 #pragma GCC diagnostic push
29 #pragma GCC diagnostic ignored "-Wunused-but-set-variable"
30 #endif // defined(__GNUC__) && !defined(__clang__)
23 31
24 #include "src/wasm/module-decoder.h" 32 #include "src/wasm/module-decoder.h"
25 #include "src/wasm/wasm-opcodes.h" 33 #include "src/wasm/wasm-opcodes.h"
26 #include "src/zone.h" 34 #include "src/zone.h"
27 35
36 #include "src/bit-vector.h"
37
38 #include "src/wasm/ast-decoder-impl.h"
39
40 #ifdef __clang__
41 #pragma clang diagnostic pop
42 #endif // __clang__
43 #if defined(__GNUC__) && !defined(__clang__)
44 #pragma GCC diagnostic pop
45 #endif // defined(__GNUC__) && !defined(__clang__)
46
28 #include "IceCfgNode.h" 47 #include "IceCfgNode.h"
29 #include "IceGlobalInits.h" 48 #include "IceGlobalInits.h"
30 49
31 using namespace std; 50 using namespace std;
32 using namespace Ice; 51 using namespace Ice;
33 using namespace v8; 52 using namespace v8;
34 using namespace v8::internal; 53 using namespace v8::internal;
35 using namespace v8::internal::wasm; 54 using namespace v8::internal::wasm;
36 using v8::internal::wasm::DecodeWasmModule; 55 using v8::internal::wasm::DecodeWasmModule;
37 56
38 #include "src/wasm/ast-decoder-impl.h" 57 #undef LOG
39
40 #define LOG(Expr) log([&](Ostream & out) { Expr; }) 58 #define LOG(Expr) log([&](Ostream & out) { Expr; })
41 59
42 namespace { 60 namespace {
61 // 64KB
62 const uint32_t WASM_PAGE_SIZE = 64 << 10;
43 63
44 Ice::Type toIceType(v8::internal::MachineType) { 64 std::string toStdString(WasmName Name) {
45 // TODO(eholk): actually convert this. 65 return std::string(Name.name, Name.length);
46 return IceType_i32;
47 } 66 }
48 67
49 Ice::Type toIceType(wasm::LocalType Type) { 68 Ice::Type toIceType(wasm::LocalType Type) {
50 switch (Type) { 69 switch (Type) {
51 default:
52 llvm::report_fatal_error("unexpected enum value");
53 case MachineRepresentation::kNone: 70 case MachineRepresentation::kNone:
54 llvm::report_fatal_error("kNone type not supported"); 71 llvm::report_fatal_error("kNone type not supported");
55 case MachineRepresentation::kBit: 72 case MachineRepresentation::kBit:
56 return IceType_i1; 73 return IceType_i1;
57 case MachineRepresentation::kWord8: 74 case MachineRepresentation::kWord8:
58 return IceType_i8; 75 return IceType_i8;
59 case MachineRepresentation::kWord16: 76 case MachineRepresentation::kWord16:
60 return IceType_i16; 77 return IceType_i16;
61 case MachineRepresentation::kWord32: 78 case MachineRepresentation::kWord32:
62 return IceType_i32; 79 return IceType_i32;
63 case MachineRepresentation::kWord64: 80 case MachineRepresentation::kWord64:
64 return IceType_i64; 81 return IceType_i64;
65 case MachineRepresentation::kFloat32: 82 case MachineRepresentation::kFloat32:
66 return IceType_f32; 83 return IceType_f32;
67 case MachineRepresentation::kFloat64: 84 case MachineRepresentation::kFloat64:
68 return IceType_f64; 85 return IceType_f64;
69 case MachineRepresentation::kSimd128: 86 case MachineRepresentation::kSimd128:
70 llvm::report_fatal_error("ambiguous SIMD type"); 87 llvm::report_fatal_error("ambiguous SIMD type");
71 case MachineRepresentation::kTagged: 88 case MachineRepresentation::kTagged:
72 llvm::report_fatal_error("kTagged type not supported"); 89 llvm::report_fatal_error("kTagged type not supported");
73 } 90 }
91 llvm::report_fatal_error("unexpected type");
92 }
93
94 Ice::Type toIceType(v8::internal::MachineType Type) {
95 // TODO (eholk): reorder these based on expected call frequency.
96 if (Type == MachineType::Int32()) {
97 return IceType_i32;
98 }
99 if (Type == MachineType::Uint32()) {
100 return IceType_i32;
101 }
102 if (Type == MachineType::Int8()) {
103 return IceType_i8;
104 }
105 if (Type == MachineType::Uint8()) {
106 return IceType_i8;
107 }
108 if (Type == MachineType::Int16()) {
109 return IceType_i16;
110 }
111 if (Type == MachineType::Uint16()) {
112 return IceType_i16;
113 }
114 if (Type == MachineType::Int64()) {
115 return IceType_i64;
116 }
117 if (Type == MachineType::Uint64()) {
118 return IceType_i64;
119 }
120 if (Type == MachineType::Float32()) {
121 return IceType_f32;
122 }
123 if (Type == MachineType::Float64()) {
124 return IceType_f64;
125 }
126 llvm::report_fatal_error("Unsupported MachineType");
127 }
128
129 std::string fnNameFromId(uint32_t Id) {
130 return std::string("fn") + to_string(Id);
131 }
132
133 std::string getFunctionName(const WasmModule *Module, uint32_t func_index) {
134 // Try to find the function name in the export table
135 for (const auto Export : Module->export_table) {
136 if (Export.func_index == func_index) {
137 return "__szwasm_" + toStdString(Module->GetName(Export.name_offset,
138 Export.name_length));
139 }
140 }
141 return fnNameFromId(func_index);
74 } 142 }
75 143
76 } // end of anonymous namespace 144 } // end of anonymous namespace
77 145
78 /// This class wraps either an Operand or a CfgNode. 146 /// This class wraps either an Operand or a CfgNode.
79 /// 147 ///
80 /// Turbofan's sea of nodes representation only has nodes for values, control 148 /// Turbofan's sea of nodes representation only has nodes for values, control
81 /// flow, etc. In Subzero these concepts are all separate. This class lets V8's 149 /// flow, etc. In Subzero these concepts are all separate. This class lets V8's
82 /// Wasm decoder treat Subzero objects as though they are all the same. 150 /// Wasm decoder treat Subzero objects as though they are all the same.
83 class OperandNode { 151 class OperandNode {
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
125 bool isOperand() const { return (Data != UNDEF_PTR) && !(Data & NODE_FLAG); } 193 bool isOperand() const { return (Data != UNDEF_PTR) && !(Data & NODE_FLAG); }
126 bool isCfgNode() const { return (Data != UNDEF_PTR) && (Data & NODE_FLAG); } 194 bool isCfgNode() const { return (Data != UNDEF_PTR) && (Data & NODE_FLAG); }
127 195
128 Operand *toOperand() const { return static_cast<Operand *>(*this); } 196 Operand *toOperand() const { return static_cast<Operand *>(*this); }
129 197
130 CfgNode *toCfgNode() const { return static_cast<CfgNode *>(*this); } 198 CfgNode *toCfgNode() const { return static_cast<CfgNode *>(*this); }
131 }; 199 };
132 200
133 Ostream &operator<<(Ostream &Out, const OperandNode &Op) { 201 Ostream &operator<<(Ostream &Out, const OperandNode &Op) {
134 if (Op.isOperand()) { 202 if (Op.isOperand()) {
135 Out << "(Operand*)" << Op.toOperand(); 203 const auto *Oper = Op.toOperand();
204 Out << "(Operand*)" << Oper;
205 if (Oper) {
206 Out << "::" << Oper->getType();
207 }
136 } else if (Op.isCfgNode()) { 208 } else if (Op.isCfgNode()) {
137 Out << "(CfgNode*)" << Op.toCfgNode(); 209 Out << "(CfgNode*)" << Op.toCfgNode();
138 } else { 210 } else {
139 Out << "nullptr"; 211 Out << "nullptr";
140 } 212 }
141 return Out; 213 return Out;
142 } 214 }
143 215
144 constexpr bool isComparison(wasm::WasmOpcode Opcode) { 216 bool isComparison(wasm::WasmOpcode Opcode) {
145 switch (Opcode) { 217 switch (Opcode) {
146 case kExprI32Ne: 218 case kExprI32Ne:
147 case kExprI64Ne: 219 case kExprI64Ne:
148 case kExprI32Eq: 220 case kExprI32Eq:
149 case kExprI64Eq: 221 case kExprI64Eq:
150 case kExprI32LtS: 222 case kExprI32LtS:
151 case kExprI64LtS: 223 case kExprI64LtS:
152 case kExprI32LtU: 224 case kExprI32LtU:
153 case kExprI64LtU: 225 case kExprI64LtU:
154 case kExprI32GeS: 226 case kExprI32GeS:
155 case kExprI64GeS: 227 case kExprI64GeS:
156 case kExprI32GtS: 228 case kExprI32GtS:
157 case kExprI64GtS: 229 case kExprI64GtS:
158 case kExprI32GtU: 230 case kExprI32GtU:
159 case kExprI64GtU: 231 case kExprI64GtU:
232 case kExprF32Ne:
233 case kExprF64Ne:
234 case kExprF32Le:
235 case kExprF64Le:
236 case kExprI32LeS:
237 case kExprI64LeS:
238 case kExprI32GeU:
239 case kExprI64GeU:
240 case kExprI32LeU:
241 case kExprI64LeU:
160 return true; 242 return true;
161 default: 243 default:
162 return false; 244 return false;
163 } 245 }
164 } 246 }
165 247
166 class IceBuilder { 248 class IceBuilder {
167 using Node = OperandNode; 249 using Node = OperandNode;
168 250
169 IceBuilder() = delete; 251 IceBuilder() = delete;
170 IceBuilder(const IceBuilder &) = delete; 252 IceBuilder(const IceBuilder &) = delete;
171 IceBuilder &operator=(const IceBuilder &) = delete; 253 IceBuilder &operator=(const IceBuilder &) = delete;
172 254
173 public: 255 public:
174 explicit IceBuilder(class Cfg *Func) 256 explicit IceBuilder(class Cfg *Func)
175 : Func(Func), Ctx(Func->getContext()), ControlPtr(nullptr) {} 257 : ControlPtr(nullptr), Func(Func), Ctx(Func->getContext()) {}
176 258
177 /// Allocates a buffer of Nodes for use by V8. 259 /// Allocates a buffer of Nodes for use by V8.
178 Node *Buffer(size_t Count) { 260 Node *Buffer(size_t Count) {
179 LOG(out << "Buffer(" << Count << ")\n"); 261 LOG(out << "Buffer(" << Count << ")\n");
180 return Func->allocateArrayOf<Node>(Count); 262 return Func->allocateArrayOf<Node>(Count);
181 } 263 }
182 264
183 Node Error() { llvm::report_fatal_error("Error"); } 265 Node Error() { llvm::report_fatal_error("Error"); }
184 Node Start(unsigned Params) { 266 Node Start(uint32_t Params) {
185 LOG(out << "Start(" << Params << ") = "); 267 LOG(out << "Start(" << Params << ") = ");
186 auto *Entry = Func->makeNode(); 268 auto *Entry = Func->getEntryNode();
187 Func->setEntryNode(Entry); 269 assert(Entry);
188 LOG(out << Node(Entry) << "\n"); 270 LOG(out << Node(Entry) << "\n");
189 return OperandNode(Entry); 271 return OperandNode(Entry);
190 } 272 }
191 Node Param(unsigned Index, wasm::LocalType Type) { 273 Node Param(uint32_t Index, wasm::LocalType Type) {
192 LOG(out << "Param(" << Index << ") = "); 274 LOG(out << "Param(" << Index << ") = ");
193 auto *Arg = makeVariable(toIceType(Type)); 275 auto *Arg = makeVariable(toIceType(Type));
194 assert(Index == NextArg); 276 assert(Index == NextArg);
195 Func->addArg(Arg); 277 Func->addArg(Arg);
196 ++NextArg; 278 ++NextArg;
197 LOG(out << Node(Arg) << "\n"); 279 LOG(out << Node(Arg) << "\n");
198 return OperandNode(Arg); 280 return OperandNode(Arg);
199 } 281 }
200 Node Loop(CfgNode *Entry) { 282 Node Loop(CfgNode *Entry) {
201 auto *Loop = Func->makeNode(); 283 auto *Loop = Func->makeNode();
202 LOG(out << "Loop(" << Entry << ") = " << Loop << "\n"); 284 LOG(out << "Loop(" << Entry << ") = " << Loop << "\n");
203 Entry->appendInst(InstBr::create(Func, Loop)); 285 Entry->appendInst(InstBr::create(Func, Loop));
204 return OperandNode(Loop); 286 return OperandNode(Loop);
205 } 287 }
206 void Terminate(Node Effect, Node Control) { 288 void Terminate(Node Effect, Node Control) {
207 // TODO(eholk): this is almost certainly wrong 289 // TODO(eholk): this is almost certainly wrong
208 LOG(out << "Terminate(" << Effect << ", " << Control << ")" 290 LOG(out << "Terminate(" << Effect << ", " << Control << ")"
209 << "\n"); 291 << "\n");
210 } 292 }
211 Node Merge(unsigned Count, Node *Controls) { 293 Node Merge(uint32_t Count, Node *Controls) {
212 LOG(out << "Merge(" << Count); 294 LOG(out << "Merge(" << Count);
213 for (unsigned i = 0; i < Count; ++i) { 295 for (uint32_t i = 0; i < Count; ++i) {
214 LOG(out << ", " << Controls[i]); 296 LOG(out << ", " << Controls[i]);
215 } 297 }
216 LOG(out << ") = "); 298 LOG(out << ") = ");
217 299
218 auto *MergedNode = Func->makeNode(); 300 auto *MergedNode = Func->makeNode();
219 301
220 for (unsigned i = 0; i < Count; ++i) { 302 for (uint32_t i = 0; i < Count; ++i) {
221 CfgNode *Control = Controls[i]; 303 CfgNode *Control = Controls[i];
222 Control->appendInst(InstBr::create(Func, MergedNode)); 304 Control->appendInst(InstBr::create(Func, MergedNode));
223 } 305 }
224 LOG(out << (OperandNode)MergedNode << "\n"); 306 LOG(out << (OperandNode)MergedNode << "\n");
225 return OperandNode(MergedNode); 307 return OperandNode(MergedNode);
226 } 308 }
227 Node Phi(wasm::LocalType Type, unsigned Count, Node *Vals, Node Control) { 309 Node Phi(wasm::LocalType, uint32_t Count, Node *Vals, Node Control) {
228 LOG(out << "Phi(" << Count << ", " << Control); 310 LOG(out << "Phi(" << Count << ", " << Control);
229 for (int i = 0; i < Count; ++i) { 311 for (uint32_t i = 0; i < Count; ++i) {
230 LOG(out << ", " << Vals[i]); 312 LOG(out << ", " << Vals[i]);
231 } 313 }
232 LOG(out << ") = "); 314 LOG(out << ") = ");
233 315
234 const auto &InEdges = Control.toCfgNode()->getInEdges(); 316 const auto &InEdges = Control.toCfgNode()->getInEdges();
235 assert(Count == InEdges.size()); 317 //assert(Count == InEdges.size());
236 318
237 assert(Count > 0); 319 assert(Count > 0);
238 320
239 auto *Dest = makeVariable(Vals[0].toOperand()->getType(), Control); 321 auto *Dest = makeVariable(Vals[0].toOperand()->getType(), Control);
240 322
241 // Multiply by 10 in case more things get added later. 323 // Multiply by 10 in case more things get added later.
242 324
243 // TODO(eholk): find a better way besides multiplying by some arbitrary 325 // TODO(eholk): find a better way besides multiplying by some arbitrary
244 // constant. 326 // constant.
245 auto *Phi = InstPhi::create(Func, Count * 10, Dest); 327 auto *Phi = InstPhi::create(Func, Count * 10, Dest);
246 for (int i = 0; i < Count; ++i) { 328 for (uint32_t i = 0; i < Count; ++i) {
247 auto *Op = Vals[i].toOperand(); 329 auto *Op = Vals[i].toOperand();
248 assert(Op); 330 assert(Op);
249 Phi->addArgument(Op, InEdges[i]); 331 Phi->addArgument(Op, InEdges[i]);
250 } 332 }
251 setDefiningInst(Dest, Phi); 333 setDefiningInst(Dest, Phi);
252 Control.toCfgNode()->appendInst(Phi); 334 constexpr bool AllowPhisAnywhere = true;
335 Control.toCfgNode()->appendInst(Phi, AllowPhisAnywhere);
253 LOG(out << Node(Dest) << "\n"); 336 LOG(out << Node(Dest) << "\n");
254 return OperandNode(Dest); 337 return OperandNode(Dest);
255 } 338 }
256 Node EffectPhi(unsigned Count, Node *Effects, Node Control) { 339 Node EffectPhi(uint32_t Count, Node *Effects, Node Control) {
257 // TODO(eholk): this function is almost certainly wrong. 340 // TODO(eholk): this function is almost certainly wrong.
258 LOG(out << "EffectPhi(" << Count << ", " << Control << "):\n"); 341 LOG(out << "EffectPhi(" << Count << ", " << Control << "):\n");
259 for (unsigned i = 0; i < Count; ++i) { 342 for (uint32_t i = 0; i < Count; ++i) {
260 LOG(out << " " << Effects[i] << "\n"); 343 LOG(out << " " << Effects[i] << "\n");
261 } 344 }
262 return OperandNode(nullptr); 345 return OperandNode(nullptr);
263 } 346 }
264 Node Int32Constant(int32_t Value) { 347 Node Int32Constant(int32_t Value) {
265 LOG(out << "Int32Constant(" << Value << ") = "); 348 LOG(out << "Int32Constant(" << Value << ") = ");
266 auto *Const = Ctx->getConstantInt32(Value); 349 auto *Const = Ctx->getConstantInt32(Value);
267 assert(Const); 350 assert(Const);
268 assert(Control()); 351 assert(Control());
269 LOG(out << Node(Const) << "\n"); 352 LOG(out << Node(Const) << "\n");
(...skipping 17 matching lines...) Expand all
287 LOG(out << "Float64Constant(" << Value << ") = "); 370 LOG(out << "Float64Constant(" << Value << ") = ");
288 auto *Const = Ctx->getConstantDouble(Value); 371 auto *Const = Ctx->getConstantDouble(Value);
289 assert(Const); 372 assert(Const);
290 LOG(out << Node(Const) << "\n"); 373 LOG(out << Node(Const) << "\n");
291 return OperandNode(Const); 374 return OperandNode(Const);
292 } 375 }
293 Node Binop(wasm::WasmOpcode Opcode, Node Left, Node Right) { 376 Node Binop(wasm::WasmOpcode Opcode, Node Left, Node Right) {
294 LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left 377 LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left
295 << ", " << Right << ") = "); 378 << ", " << Right << ") = ");
296 auto *Dest = makeVariable( 379 auto *Dest = makeVariable(
297 isComparison(Opcode) ? IceType_i1 : Left.toOperand()->getType()); 380 isComparison(Opcode) ? IceType_i32 : Left.toOperand()->getType());
298 switch (Opcode) { 381 switch (Opcode) {
299 case kExprI32Add: 382 case kExprI32Add:
300 case kExprI64Add: 383 case kExprI64Add:
301 Control()->appendInst( 384 Control()->appendInst(
302 InstArithmetic::create(Func, InstArithmetic::Add, Dest, Left, Right)); 385 InstArithmetic::create(Func, InstArithmetic::Add, Dest, Left, Right));
303 break; 386 break;
387 case kExprF32Add:
388 case kExprF64Add:
389 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Fadd,
390 Dest, Left, Right));
391 break;
304 case kExprI32Sub: 392 case kExprI32Sub:
305 case kExprI64Sub: 393 case kExprI64Sub:
306 Control()->appendInst( 394 Control()->appendInst(
307 InstArithmetic::create(Func, InstArithmetic::Sub, Dest, Left, Right)); 395 InstArithmetic::create(Func, InstArithmetic::Sub, Dest, Left, Right));
308 break; 396 break;
309 case kExprI32Mul: 397 case kExprI32Mul:
310 case kExprI64Mul: 398 case kExprI64Mul:
311 Control()->appendInst( 399 Control()->appendInst(
312 InstArithmetic::create(Func, InstArithmetic::Mul, Dest, Left, Right)); 400 InstArithmetic::create(Func, InstArithmetic::Mul, Dest, Left, Right));
313 break; 401 break;
314 case kExprI32DivU: 402 case kExprI32DivU:
315 case kExprI64DivU: 403 case kExprI64DivU:
316 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Udiv, 404 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Udiv,
317 Dest, Left, Right)); 405 Dest, Left, Right));
318 break; 406 break;
319 case kExprI32RemU: 407 case kExprI32RemU:
320 case kExprI64RemU: 408 case kExprI64RemU:
321 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Urem, 409 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Urem,
322 Dest, Left, Right)); 410 Dest, Left, Right));
323 break; 411 break;
412 case kExprI32RemS:
413 case kExprI64RemS:
414 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Srem,
415 Dest, Left, Right));
416 break;
324 case kExprI32Ior: 417 case kExprI32Ior:
325 case kExprI64Ior: 418 case kExprI64Ior:
326 Control()->appendInst( 419 Control()->appendInst(
327 InstArithmetic::create(Func, InstArithmetic::Or, Dest, Left, Right)); 420 InstArithmetic::create(Func, InstArithmetic::Or, Dest, Left, Right));
328 break; 421 break;
329 case kExprI32Xor: 422 case kExprI32Xor:
330 case kExprI64Xor: 423 case kExprI64Xor:
331 Control()->appendInst( 424 Control()->appendInst(
332 InstArithmetic::create(Func, InstArithmetic::Xor, Dest, Left, Right)); 425 InstArithmetic::create(Func, InstArithmetic::Xor, Dest, Left, Right));
333 break; 426 break;
334 case kExprI32Shl: 427 case kExprI32Shl:
335 case kExprI64Shl: 428 case kExprI64Shl:
336 Control()->appendInst( 429 Control()->appendInst(
337 InstArithmetic::create(Func, InstArithmetic::Shl, Dest, Left, Right)); 430 InstArithmetic::create(Func, InstArithmetic::Shl, Dest, Left, Right));
338 break; 431 break;
432 case kExprI32Rol: {
433 // TODO(eholk): add rotate as an ICE instruction to make it easier to take
434 // advantage of hardware support.
435
436 // TODO(eholk): don't hardcode so many numbers.
437 auto *Masked = makeVariable(IceType_i32);
438 auto *Bottom = makeVariable(IceType_i32);
439 auto *Top = makeVariable(IceType_i32);
440 Control()->appendInst(InstArithmetic::create(
441 Func, InstArithmetic::And, Masked, Right, Ctx->getConstantInt32(31)));
442 Control()->appendInst(
443 InstArithmetic::create(Func, InstArithmetic::Shl, Top, Left, Masked));
444 auto *RotShift = makeVariable(IceType_i32);
445 Control()->appendInst(
446 InstArithmetic::create(Func, InstArithmetic::Sub, RotShift,
447 Ctx->getConstantInt32(32), Masked));
448 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Lshr,
449 Bottom, Left, Masked));
450 Control()->appendInst(
451 InstArithmetic::create(Func, InstArithmetic::Or, Dest, Top, Bottom));
452 break;
453 }
339 case kExprI32ShrU: 454 case kExprI32ShrU:
340 case kExprI64ShrU: 455 case kExprI64ShrU:
341 case kExprI32ShrS: 456 case kExprI32ShrS:
342 case kExprI64ShrS: 457 case kExprI64ShrS:
343 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Ashr, 458 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Ashr,
344 Dest, Left, Right)); 459 Dest, Left, Right));
345 break; 460 break;
346 case kExprI32And: 461 case kExprI32And:
347 case kExprI64And: 462 case kExprI64And:
348 Control()->appendInst( 463 Control()->appendInst(
349 InstArithmetic::create(Func, InstArithmetic::And, Dest, Left, Right)); 464 InstArithmetic::create(Func, InstArithmetic::And, Dest, Left, Right));
350 break; 465 break;
351 case kExprI32Ne: 466 case kExprI32Ne:
352 case kExprI64Ne: 467 case kExprI64Ne: {
468 auto *TmpDest = makeVariable(IceType_i1);
353 Control()->appendInst( 469 Control()->appendInst(
354 InstIcmp::create(Func, InstIcmp::Ne, Dest, Left, Right)); 470 InstIcmp::create(Func, InstIcmp::Ne, TmpDest, Left, Right));
471 Control()->appendInst(
472 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
355 break; 473 break;
474 }
356 case kExprI32Eq: 475 case kExprI32Eq:
357 case kExprI64Eq: 476 case kExprI64Eq: {
477 auto *TmpDest = makeVariable(IceType_i1);
358 Control()->appendInst( 478 Control()->appendInst(
359 InstIcmp::create(Func, InstIcmp::Eq, Dest, Left, Right)); 479 InstIcmp::create(Func, InstIcmp::Eq, TmpDest, Left, Right));
480 Control()->appendInst(
481 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
360 break; 482 break;
483 }
361 case kExprI32LtS: 484 case kExprI32LtS:
362 case kExprI64LtS: 485 case kExprI64LtS: {
486 auto *TmpDest = makeVariable(IceType_i1);
363 Control()->appendInst( 487 Control()->appendInst(
364 InstIcmp::create(Func, InstIcmp::Slt, Dest, Left, Right)); 488 InstIcmp::create(Func, InstIcmp::Slt, TmpDest, Left, Right));
489 Control()->appendInst(
490 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
365 break; 491 break;
492 }
493 case kExprI32LeS:
494 case kExprI64LeS: {
495 auto *TmpDest = makeVariable(IceType_i1);
496 Control()->appendInst(
497 InstIcmp::create(Func, InstIcmp::Sle, TmpDest, Left, Right));
498 Control()->appendInst(
499 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
500 break;
501 }
502 case kExprI32GeU:
503 case kExprI64GeU: {
504 auto *TmpDest = makeVariable(IceType_i1);
505 Control()->appendInst(
506 InstIcmp::create(Func, InstIcmp::Uge, TmpDest, Left, Right));
507 Control()->appendInst(
508 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
509 break;
510 }
511 case kExprI32LeU:
512 case kExprI64LeU: {
513 auto *TmpDest = makeVariable(IceType_i1);
514 Control()->appendInst(
515 InstIcmp::create(Func, InstIcmp::Ule, TmpDest, Left, Right));
516 Control()->appendInst(
517 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
518 break;
519 }
366 case kExprI32LtU: 520 case kExprI32LtU:
367 case kExprI64LtU: 521 case kExprI64LtU: {
522 auto *TmpDest = makeVariable(IceType_i1);
368 Control()->appendInst( 523 Control()->appendInst(
369 InstIcmp::create(Func, InstIcmp::Ult, Dest, Left, Right)); 524 InstIcmp::create(Func, InstIcmp::Ult, TmpDest, Left, Right));
525 Control()->appendInst(
526 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
370 break; 527 break;
528 }
371 case kExprI32GeS: 529 case kExprI32GeS:
372 case kExprI64GeS: 530 case kExprI64GeS: {
531 auto *TmpDest = makeVariable(IceType_i1);
373 Control()->appendInst( 532 Control()->appendInst(
374 InstIcmp::create(Func, InstIcmp::Sge, Dest, Left, Right)); 533 InstIcmp::create(Func, InstIcmp::Sge, TmpDest, Left, Right));
534 Control()->appendInst(
535 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
536 }
375 case kExprI32GtS: 537 case kExprI32GtS:
376 case kExprI64GtS: 538 case kExprI64GtS: {
539 auto *TmpDest = makeVariable(IceType_i1);
377 Control()->appendInst( 540 Control()->appendInst(
378 InstIcmp::create(Func, InstIcmp::Sgt, Dest, Left, Right)); 541 InstIcmp::create(Func, InstIcmp::Sgt, TmpDest, Left, Right));
542 Control()->appendInst(
543 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
379 break; 544 break;
545 }
380 case kExprI32GtU: 546 case kExprI32GtU:
381 case kExprI64GtU: 547 case kExprI64GtU: {
548 auto *TmpDest = makeVariable(IceType_i1);
382 Control()->appendInst( 549 Control()->appendInst(
383 InstIcmp::create(Func, InstIcmp::Ugt, Dest, Left, Right)); 550 InstIcmp::create(Func, InstIcmp::Ugt, TmpDest, Left, Right));
551 Control()->appendInst(
552 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
384 break; 553 break;
554 }
555 case kExprF32Ne:
556 case kExprF64Ne: {
557 auto *TmpDest = makeVariable(IceType_i1);
558 Control()->appendInst(
559 InstFcmp::create(Func, InstFcmp::Une, TmpDest, Left, Right));
560 Control()->appendInst(
561 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
562 break;
563 }
564 case kExprF32Le:
565 case kExprF64Le: {
566 auto *TmpDest = makeVariable(IceType_i1);
567 Control()->appendInst(
568 InstFcmp::create(Func, InstFcmp::Ule, TmpDest, Left, Right));
569 Control()->appendInst(
570 InstCast::create(Func, InstCast::Zext, Dest, TmpDest));
571 break;
572 }
385 default: 573 default:
386 LOG(out << "Unknown binop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); 574 LOG(out << "Unknown binop: " << WasmOpcodes::OpcodeName(Opcode) << "\n");
387 llvm::report_fatal_error("Uncovered or invalid binop."); 575 llvm::report_fatal_error("Uncovered or invalid binop.");
388 return OperandNode(nullptr); 576 return OperandNode(nullptr);
389 } 577 }
390 LOG(out << Dest << "\n"); 578 LOG(out << Dest << "\n");
391 return OperandNode(Dest); 579 return OperandNode(Dest);
392 } 580 }
393 Node Unop(wasm::WasmOpcode Opcode, Node Input) { 581 Node Unop(wasm::WasmOpcode Opcode, Node Input) {
394 LOG(out << "Unop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Input 582 LOG(out << "Unop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Input
395 << ") = "); 583 << ") = ");
396 Ice::Variable *Dest = nullptr; 584 Ice::Variable *Dest = nullptr;
397 switch (Opcode) { 585 switch (Opcode) {
586 case kExprI32Eqz: {
587 Dest = makeVariable(IceType_i32);
588 auto *Tmp = makeVariable(IceType_i1);
589 Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input,
590 Ctx->getConstantInt32(0)));
591 Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp));
592 break;
593 }
594 case kExprI64Eqz: {
595 Dest = makeVariable(IceType_i32);
596 auto *Tmp = makeVariable(IceType_i1);
597 Control()->appendInst(InstIcmp::create(Func, InstIcmp::Eq, Tmp, Input,
598 Ctx->getConstantInt64(0)));
599 Control()->appendInst(InstCast::create(Func, InstCast::Zext, Dest, Tmp));
600 break;
601 }
398 case kExprF32Neg: { 602 case kExprF32Neg: {
399 Dest = makeVariable(IceType_f32); 603 Dest = makeVariable(IceType_f32);
400 Control()->appendInst(InstArithmetic::create( 604 Control()->appendInst(InstArithmetic::create(
401 Func, InstArithmetic::Fsub, Dest, Ctx->getConstantFloat(0), Input)); 605 Func, InstArithmetic::Fsub, Dest, Ctx->getConstantFloat(0), Input));
402 break; 606 break;
403 } 607 }
404 case kExprF64Neg: { 608 case kExprF64Neg: {
405 Dest = makeVariable(IceType_f64); 609 Dest = makeVariable(IceType_f64);
406 Control()->appendInst(InstArithmetic::create( 610 Control()->appendInst(InstArithmetic::create(
407 Func, InstArithmetic::Fsub, Dest, Ctx->getConstantDouble(0), Input)); 611 Func, InstArithmetic::Fsub, Dest, Ctx->getConstantDouble(0), Input));
408 break; 612 break;
409 } 613 }
410 case kExprI64UConvertI32: 614 case kExprI64UConvertI32:
411 Dest = makeVariable(IceType_i64); 615 Dest = makeVariable(IceType_i64);
412 Control()->appendInst( 616 Control()->appendInst(
413 InstCast::create(Func, InstCast::Zext, Dest, Input)); 617 InstCast::create(Func, InstCast::Zext, Dest, Input));
414 break; 618 break;
619 case kExprI64SConvertI32:
620 Dest = makeVariable(IceType_i64);
621 Control()->appendInst(
622 InstCast::create(Func, InstCast::Sext, Dest, Input));
623 break;
624 case kExprI32ConvertI64:
625 Dest = makeVariable(IceType_i32);
626 Control()->appendInst(
627 InstCast::create(Func, InstCast::Trunc, Dest, Input));
628 break;
629 case kExprF64SConvertI32:
630 Dest = makeVariable(IceType_f64);
631 Control()->appendInst(
632 InstCast::create(Func, InstCast::Sitofp, Dest, Input));
633 break;
415 default: 634 default:
416 LOG(out << "Unknown unop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); 635 LOG(out << "Unknown unop: " << WasmOpcodes::OpcodeName(Opcode) << "\n");
417 llvm::report_fatal_error("Uncovered or invalid unop."); 636 llvm::report_fatal_error("Uncovered or invalid unop.");
418 return OperandNode(nullptr); 637 return OperandNode(nullptr);
419 } 638 }
420 LOG(out << Dest << "\n"); 639 LOG(out << Dest << "\n");
421 return OperandNode(Dest); 640 return OperandNode(Dest);
422 } 641 }
423 unsigned InputCount(CfgNode *Node) const { return Node->getInEdges().size(); } 642 uint32_t InputCount(CfgNode *Node) const { return Node->getInEdges().size(); }
424 bool IsPhiWithMerge(Node Phi, Node Merge) const { 643 bool IsPhiWithMerge(Node Phi, Node Merge) const {
425 LOG(out << "IsPhiWithMerge(" << Phi << ", " << Merge << ")" 644 LOG(out << "IsPhiWithMerge(" << Phi << ", " << Merge << ")"
426 << "\n"); 645 << "\n");
427 if (Phi && Phi.isOperand()) { 646 if (Phi && Phi.isOperand()) {
428 LOG(out << " ...is operand" 647 LOG(out << " ...is operand"
429 << "\n"); 648 << "\n");
430 if (auto *Inst = getDefiningInst(Phi)) { 649 if (getDefiningInst(Phi)) {
431 LOG(out << " ...has defining instruction" 650 LOG(out << " ...has defining instruction"
432 << "\n"); 651 << "\n");
433 LOG(out << getDefNode(Phi) << "\n"); 652 LOG(out << getDefNode(Phi) << "\n");
434 LOG(out << " ..." << (getDefNode(Phi) == Merge) << "\n"); 653 LOG(out << " ..." << (getDefNode(Phi) == Merge) << "\n");
435 return getDefNode(Phi) == Merge; 654 return getDefNode(Phi) == Merge;
436 } 655 }
437 } 656 }
438 return false; 657 return false;
439 } 658 }
440 void AppendToMerge(CfgNode *Merge, CfgNode *From) const { 659 void AppendToMerge(CfgNode *Merge, CfgNode *From) const {
441 From->appendInst(InstBr::create(Func, Merge)); 660 From->appendInst(InstBr::create(Func, Merge));
442 } 661 }
443 void AppendToPhi(Node Merge, Node Phi, Node From) { 662 void AppendToPhi(Node Merge, Node Phi, Node From) {
444 LOG(out << "AppendToPhi(" << Merge << ", " << Phi << ", " << From << ")" 663 LOG(out << "AppendToPhi(" << Merge << ", " << Phi << ", " << From << ")"
445 << "\n"); 664 << "\n");
446 auto *Inst = getDefiningInst(Phi); 665 auto *Inst = getDefiningInst(Phi);
666 assert(Inst->getDest()->getType() == From.toOperand()->getType());
447 Inst->addArgument(From, getDefNode(From)); 667 Inst->addArgument(From, getDefNode(From));
448 } 668 }
449 669
450 //----------------------------------------------------------------------- 670 //-----------------------------------------------------------------------
451 // Operations that read and/or write {control} and {effect}. 671 // Operations that read and/or write {control} and {effect}.
452 //----------------------------------------------------------------------- 672 //-----------------------------------------------------------------------
453 Node Branch(Node Cond, Node *TrueNode, Node *FalseNode) { 673 Node Branch(Node Cond, Node *TrueNode, Node *FalseNode) {
454 // true_node and false_node appear to be out parameters. 674 // true_node and false_node appear to be out parameters.
455 LOG(out << "Branch(" << Cond << ", "); 675 LOG(out << "Branch(" << Cond << ", ");
456 676
457 // save control here because true_node appears to alias control. 677 // save control here because true_node appears to alias control.
458 auto *Ctrl = Control(); 678 auto *Ctrl = Control();
459 679
460 *TrueNode = OperandNode(Func->makeNode()); 680 *TrueNode = OperandNode(Func->makeNode());
461 *FalseNode = OperandNode(Func->makeNode()); 681 *FalseNode = OperandNode(Func->makeNode());
462 682
463 LOG(out << *TrueNode << ", " << *FalseNode << ")" 683 LOG(out << *TrueNode << ", " << *FalseNode << ")"
464 << "\n"); 684 << "\n");
465 685
466 Ctrl->appendInst(InstBr::create(Func, Cond, *TrueNode, *FalseNode)); 686 auto *CondBool = makeVariable(IceType_i1);
687 Ctrl->appendInst(InstIcmp::create(Func, InstIcmp::Ne, CondBool, Cond,
688 Ctx->getConstantInt32(0)));
689
690 Ctrl->appendInst(InstBr::create(Func, CondBool, *TrueNode, *FalseNode));
467 return OperandNode(nullptr); 691 return OperandNode(nullptr);
468 } 692 }
469 Node Switch(unsigned Count, Node Key) { llvm::report_fatal_error("Switch"); } 693 InstSwitch *CurrentSwitch = nullptr;
470 Node IfValue(int32_t Value, Node Sw) { llvm::report_fatal_error("IfValue"); } 694 CfgNode *SwitchNode = nullptr;
471 Node IfDefault(Node Sw) { llvm::report_fatal_error("IfDefault"); } 695 SizeT SwitchIndex = 0;
472 Node Return(unsigned Count, Node *Vals) { 696 Node Switch(uint32_t Count, Node Key) {
697 LOG(out << "Switch(" << Count << ", " << Key << ")\n");
698
699 assert(!CurrentSwitch);
700
701 auto *Default = Func->makeNode();
702 // Count - 1 because the decoder counts the default label but Subzero does
703 // not.
704 CurrentSwitch = InstSwitch::create(Func, Count - 1, Key, Default);
705 SwitchIndex = 0;
706 SwitchNode = Control();
707 // We don't actually append the switch to the CfgNode here because not all
708 // the branches are ready.
709 return Node(nullptr);
710 }
711 Node IfValue(int32_t Value, Node) {
712 LOG(out << "IfValue(" << Value << ") [Index = " << SwitchIndex << "]\n");
713 assert(CurrentSwitch);
714 auto *Target = Func->makeNode();
715 CurrentSwitch->addBranch(SwitchIndex++, Value, Target);
716 return Node(Target);
717 }
718 Node IfDefault(Node) {
719 LOG(out << "IfDefault(...) [Index = " << SwitchIndex << "]\n");
720 assert(CurrentSwitch);
721 assert(CurrentSwitch->getLabelDefault());
722 // Now we append the switch, since this should be the last edge.
723 assert(SwitchIndex == CurrentSwitch->getNumCases());
724 SwitchNode->appendInst(CurrentSwitch);
725 SwitchNode = nullptr;
726 auto Default = Node(CurrentSwitch->getLabelDefault());
727 CurrentSwitch = nullptr;
728 return Default;
729 }
730 Node Return(uint32_t Count, Node *Vals) {
473 assert(1 >= Count); 731 assert(1 >= Count);
474 LOG(out << "Return("); 732 LOG(out << "Return(");
475 if (Count > 0) 733 if (Count > 0)
476 LOG(out << Vals[0]); 734 LOG(out << Vals[0]);
477 LOG(out << ")" 735 LOG(out << ")"
478 << "\n"); 736 << "\n");
479 auto *Instr = 737 auto *Instr =
480 1 == Count ? InstRet::create(Func, Vals[0]) : InstRet::create(Func); 738 1 == Count ? InstRet::create(Func, Vals[0]) : InstRet::create(Func);
481 Control()->appendInst(Instr); 739 Control()->appendInst(Instr);
482 Control()->setHasReturn(); 740 Control()->setHasReturn();
(...skipping 21 matching lines...) Expand all
504 << "\n"); 762 << "\n");
505 assert(Module->IsValidFunction(Index)); 763 assert(Module->IsValidFunction(Index));
506 const auto *Module = this->Module->module; 764 const auto *Module = this->Module->module;
507 assert(Module); 765 assert(Module);
508 const auto &Target = Module->functions[Index]; 766 const auto &Target = Module->functions[Index];
509 const auto *Sig = Target.sig; 767 const auto *Sig = Target.sig;
510 assert(Sig); 768 assert(Sig);
511 const auto NumArgs = Sig->parameter_count(); 769 const auto NumArgs = Sig->parameter_count();
512 LOG(out << " number of args: " << NumArgs << "\n"); 770 LOG(out << " number of args: " << NumArgs << "\n");
513 771
514 const auto TargetName = 772 const auto TargetName = getFunctionName(Module, Index);
515 Ctx->getGlobalString(Module->GetName(Target.name_offset));
516 LOG(out << " target name: " << TargetName << "\n"); 773 LOG(out << " target name: " << TargetName << "\n");
517 774
518 assert(Sig->return_count() <= 1); 775 assert(Sig->return_count() <= 1);
519 776
520 auto *TargetOperand = Ctx->getConstantSym(0, TargetName); 777 auto TargetOperand =
778 Ctx->getConstantSym(0, Ctx->getGlobalString(TargetName));
521 779
522 auto *Dest = Sig->return_count() > 0 780 auto *Dest = Sig->return_count() > 0
523 ? makeVariable(toIceType(Sig->GetReturn())) 781 ? makeVariable(toIceType(Sig->GetReturn()))
524 : nullptr; 782 : nullptr;
525 auto *Call = InstCall::create(Func, NumArgs, Dest, TargetOperand, 783 auto *Call = InstCall::create(Func, NumArgs, Dest, TargetOperand,
526 false /* HasTailCall */); 784 false /* HasTailCall */);
527 for (int i = 0; i < NumArgs; ++i) { 785 for (uint32_t i = 0; i < NumArgs; ++i) {
528 // The builder reserves the first argument for the code object. 786 // The builder reserves the first argument for the code object.
529 LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n"); 787 LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n");
530 Call->addArg(Args[i + 1]); 788 Call->addArg(Args[i + 1]);
531 } 789 }
532 790
533 Control()->appendInst(Call); 791 Control()->appendInst(Call);
534 LOG(out << "Call Result = " << Node(Dest) << "\n"); 792 LOG(out << "Call Result = " << Node(Dest) << "\n");
535 return OperandNode(Dest); 793 return OperandNode(Dest);
536 } 794 }
537 Node CallImport(uint32_t Index, Node *Args) { 795 Node CallImport(uint32_t Index, Node *Args) {
538 LOG(out << "CallImport(" << Index << ")" 796 LOG(out << "CallImport(" << Index << ")"
539 << "\n"); 797 << "\n");
540 const auto *Module = this->Module->module; 798 const auto *Module = this->Module->module;
541 assert(Module); 799 assert(Module);
542 const auto *Sig = this->Module->GetImportSignature(Index); 800 const auto *Sig = this->Module->GetImportSignature(Index);
543 assert(Sig); 801 assert(Sig);
544 const auto NumArgs = Sig->parameter_count(); 802 const auto NumArgs = Sig->parameter_count();
545 LOG(out << " number of args: " << NumArgs << "\n"); 803 LOG(out << " number of args: " << NumArgs << "\n");
546 804
547 const auto &Target = Module->import_table[Index]; 805 const auto &Target = Module->import_table[Index];
548 const auto TargetName = 806 const auto ModuleName = toStdString(
549 Ctx->getGlobalString(Module->GetName(Target.function_name_offset)); 807 Module->GetName(Target.module_name_offset, Target.module_name_length));
808 const auto FnName = toStdString(Module->GetName(
809 Target.function_name_offset, Target.function_name_length));
810
811 const auto TargetName = Ctx->getGlobalString(ModuleName + "$$" + FnName);
550 LOG(out << " target name: " << TargetName << "\n"); 812 LOG(out << " target name: " << TargetName << "\n");
551 813
552 assert(Sig->return_count() <= 1); 814 assert(Sig->return_count() <= 1);
553 815
554 auto *TargetOperand = Ctx->getConstantSym(0, TargetName); 816 auto TargetOperand = Ctx->getConstantExternSym(TargetName);
555 817
556 auto *Dest = Sig->return_count() > 0 818 auto *Dest = Sig->return_count() > 0
557 ? makeVariable(toIceType(Sig->GetReturn())) 819 ? makeVariable(toIceType(Sig->GetReturn()))
558 : nullptr; 820 : nullptr;
559 constexpr bool NoTailCall = false; 821 constexpr bool NoTailCall = false;
560 auto *Call = 822 auto *Call =
561 InstCall::create(Func, NumArgs, Dest, TargetOperand, NoTailCall); 823 InstCall::create(Func, NumArgs, Dest, TargetOperand, NoTailCall);
562 for (int i = 0; i < NumArgs; ++i) { 824 for (uint32_t i = 0; i < NumArgs; ++i) {
563 // The builder reserves the first argument for the code object. 825 // The builder reserves the first argument for the code object.
564 LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n"); 826 LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n");
827 assert(Args[i + 1].toOperand()->getType() == toIceType(Sig->GetParam(i)));
565 Call->addArg(Args[i + 1]); 828 Call->addArg(Args[i + 1]);
566 } 829 }
567 830
568 Control()->appendInst(Call); 831 Control()->appendInst(Call);
569 LOG(out << "Call Result = " << Node(Dest) << "\n"); 832 LOG(out << "Call Result = " << Node(Dest) << "\n");
570 return OperandNode(Dest); 833 return OperandNode(Dest);
571 } 834 }
572 Node CallIndirect(uint32_t Index, Node *Args) { 835 Node CallIndirect(uint32_t SigIndex, Node *Args) {
573 llvm::report_fatal_error("CallIndirect"); 836 LOG(out << "CallIndirect(" << SigIndex << ")\n");
837 // TODO(eholk): Compile to something better than a switch.
838 const auto *Module = this->Module->module;
839 assert(Module);
840 const auto &IndirectTable = Module->function_table;
841
842 // TODO(eholk): This should probably actually call abort instead.
843 auto *Abort = Func->makeNode();
844 Abort->appendInst(InstUnreachable::create(Func));
845
846 assert(Args[0].toOperand());
847
848 auto *Switch = InstSwitch::create(Func, IndirectTable.size(),
849 Args[0].toOperand(), Abort);
850 assert(Abort);
851
852 const bool HasReturn = Module->signatures[SigIndex]->return_count() != 0;
853 const Ice::Type DestTy =
854 HasReturn ? toIceType(Module->signatures[SigIndex]->GetReturn())
855 : IceType_void;
856
857 auto *Dest = HasReturn ? makeVariable(DestTy) : nullptr;
858
859 auto *ExitNode = Func->makeNode();
860 auto *PhiInst =
861 HasReturn ? InstPhi::create(Func, IndirectTable.size(), Dest) : nullptr;
862
863 for (uint32_t Index = 0; Index < IndirectTable.size(); ++Index) {
864 const auto &Target = Module->functions[IndirectTable[Index]];
865
866 if (SigIndex == Target.sig_index) {
867 auto *CallNode = Func->makeNode();
868 auto *SavedControl = Control();
869 *ControlPtr = OperandNode(CallNode);
870 auto *Tmp = CallDirect(Target.func_index, Args).toOperand();
871 *ControlPtr = OperandNode(SavedControl);
872 if (PhiInst) {
873 PhiInst->addArgument(Tmp, CallNode);
874 }
875 CallNode->appendInst(InstBr::create(Func, ExitNode));
876 Switch->addBranch(Index, Index, CallNode);
877 } else {
878 Switch->addBranch(Index, Index, Abort);
879 }
880 }
881
882 if (PhiInst) {
883 ExitNode->appendInst(PhiInst);
884 }
885
886 Control()->appendInst(Switch);
887 *ControlPtr = OperandNode(ExitNode);
888 return OperandNode(Dest);
574 } 889 }
575 Node Invert(Node Node) { llvm::report_fatal_error("Invert"); } 890 Node Invert(Node Node) {
576 Node FunctionTable() { llvm::report_fatal_error("FunctionTable"); } 891 (void)Node;
892 llvm::report_fatal_error("Invert");
893 }
577 894
578 //----------------------------------------------------------------------- 895 //-----------------------------------------------------------------------
579 // Operations that concern the linear memory. 896 // Operations that concern the linear memory.
580 //----------------------------------------------------------------------- 897 //-----------------------------------------------------------------------
581 Node MemSize(uint32_t Offset) { llvm::report_fatal_error("MemSize"); } 898 Node MemSize(uint32_t Offset) {
582 Node LoadGlobal(uint32_t Index) { llvm::report_fatal_error("LoadGlobal"); } 899 (void)Offset;
900 llvm::report_fatal_error("MemSize");
901 }
902 Node LoadGlobal(uint32_t Index) {
903 (void)Index;
904 llvm::report_fatal_error("LoadGlobal");
905 }
583 Node StoreGlobal(uint32_t Index, Node Val) { 906 Node StoreGlobal(uint32_t Index, Node Val) {
907 (void)Index;
908 (void)Val;
584 llvm::report_fatal_error("StoreGlobal"); 909 llvm::report_fatal_error("StoreGlobal");
585 } 910 }
911
912 Operand *sanitizeAddress(Operand *Base, uint32_t Offset) {
913 SizeT MemSize = Module->module->min_mem_pages * WASM_PAGE_SIZE;
914 SizeT MemMask = MemSize - 1;
915
916 bool ConstZeroBase = false;
917
918 // first, add the index and the offset together.
919 if (auto *ConstBase = llvm::dyn_cast<ConstantInteger32>(Base)) {
920 uint32_t RealOffset = Offset + ConstBase->getValue();
921 RealOffset &= MemMask;
922 Base = Ctx->getConstantInt32(RealOffset);
923 ConstZeroBase = (0 == RealOffset);
924 } else if (0 != Offset) {
925 auto *Addr = makeVariable(IceType_i32);
926 auto *OffsetConstant = Ctx->getConstantInt32(Offset);
927 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
928 Addr, Base, OffsetConstant));
929
930 Base = Addr;
931 }
932
933 if (!llvm::dyn_cast<ConstantInteger32>(Base)) {
934 auto ClampedAddr = makeVariable(IceType_i32);
935 Control()->appendInst(
936 InstArithmetic::create(Func, InstArithmetic::And, ClampedAddr, Base,
937 Ctx->getConstantInt32(MemSize - 1)));
938 Base = ClampedAddr;
939 }
940
941 Ice::Operand *RealAddr = nullptr;
942 auto MemBase = Ctx->getConstantSym(0, Ctx->getGlobalString("WASM_MEMORY"));
943 if (!ConstZeroBase) {
944 auto RealAddrV = Func->makeVariable(IceType_i32);
945 Control()->appendInst(InstArithmetic::create(
946 Func, InstArithmetic::Add, RealAddrV, Base, MemBase));
947
948 RealAddr = RealAddrV;
949 } else {
950 RealAddr = MemBase;
951 }
952 return RealAddr;
953 }
954
586 Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index, 955 Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index,
587 uint32_t Offset) { 956 uint32_t Offset) {
588 LOG(out << "LoadMem(" << Index << "[" << Offset << "]) = "); 957 LOG(out << "LoadMem(" << Index << "[" << Offset << "]) = ");
589 958
590 // first, add the index and the offset together. 959 auto *RealAddr = sanitizeAddress(Index, Offset);
591 auto *OffsetConstant = Ctx->getConstantInt32(Offset);
592 auto *Addr = makeVariable(IceType_i32);
593 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
594 Addr, Index, OffsetConstant));
595 960
596 // then load the memory
597 auto *LoadResult = makeVariable(toIceType(MemType)); 961 auto *LoadResult = makeVariable(toIceType(MemType));
598 Control()->appendInst(InstLoad::create(Func, LoadResult, Addr)); 962 Control()->appendInst(InstLoad::create(Func, LoadResult, RealAddr));
599 963
600 // and cast, if needed 964 // and cast, if needed
601 Ice::Variable *Result = nullptr; 965 Ice::Variable *Result = nullptr;
602 if (toIceType(Type) != toIceType(MemType)) { 966 if (toIceType(Type) != toIceType(MemType)) {
603 Result = makeVariable(toIceType(Type)); 967 auto DestType = toIceType(Type);
968 Result = makeVariable(DestType);
604 // TODO(eholk): handle signs correctly. 969 // TODO(eholk): handle signs correctly.
605 Control()->appendInst( 970 if (isScalarIntegerType(DestType)) {
606 InstCast::create(Func, InstCast::Sext, Result, LoadResult)); 971 if (MemType.IsSigned()) {
972 Control()->appendInst(
973 InstCast::create(Func, InstCast::Sext, Result, LoadResult));
974 } else {
975 Control()->appendInst(
976 InstCast::create(Func, InstCast::Zext, Result, LoadResult));
977 }
978 } else if (isScalarFloatingType(DestType)) {
979 Control()->appendInst(
980 InstCast::create(Func, InstCast::Sitofp, Result, LoadResult));
981 } else {
982 llvm::report_fatal_error("Unsupported type for memory load");
983 }
607 } else { 984 } else {
608 Result = LoadResult; 985 Result = LoadResult;
609 } 986 }
610 987
611 LOG(out << Result << "\n"); 988 LOG(out << Result << "\n");
612 return OperandNode(Result); 989 return OperandNode(Result);
613 } 990 }
614 void StoreMem(MachineType Type, Node Index, uint32_t Offset, Node Val) { 991 void StoreMem(MachineType Type, Node Index, uint32_t Offset, Node Val) {
615 LOG(out << "StoreMem(" << Index << "[" << Offset << "] = " << Val << ")" 992 LOG(out << "StoreMem(" << Index << "[" << Offset << "] = " << Val << ")"
616 << "\n"); 993 << "\n");
617 994
618 // TODO(eholk): surely there is a better way to do this. 995 auto *RealAddr = sanitizeAddress(Index, Offset);
619
620 // first, add the index and the offset together.
621 auto *OffsetConstant = Ctx->getConstantInt32(Offset);
622 auto *Addr = makeVariable(IceType_i32);
623 Control()->appendInst(InstArithmetic::create(Func, InstArithmetic::Add,
624 Addr, Index, OffsetConstant));
625 996
626 // cast the value to the right type, if needed 997 // cast the value to the right type, if needed
627 Operand *StoreVal = nullptr; 998 Operand *StoreVal = nullptr;
628 if (toIceType(Type) != Val.toOperand()->getType()) { 999 if (toIceType(Type) != Val.toOperand()->getType()) {
629 auto *LocalStoreVal = makeVariable(toIceType(Type)); 1000 auto *LocalStoreVal = makeVariable(toIceType(Type));
630 Control()->appendInst( 1001 Control()->appendInst(
631 InstCast::create(Func, InstCast::Trunc, LocalStoreVal, Val)); 1002 InstCast::create(Func, InstCast::Trunc, LocalStoreVal, Val));
632 StoreVal = LocalStoreVal; 1003 StoreVal = LocalStoreVal;
633 } else { 1004 } else {
634 StoreVal = Val; 1005 StoreVal = Val;
635 } 1006 }
636 1007
637 // then store the memory 1008 // then store the memory
638 Control()->appendInst(InstStore::create(Func, StoreVal, Addr)); 1009 Control()->appendInst(InstStore::create(Func, StoreVal, RealAddr));
639 } 1010 }
640 1011
641 static void PrintDebugName(Node node) { 1012 static void PrintDebugName(OperandNode Node) {
1013 (void)Node;
642 llvm::report_fatal_error("PrintDebugName"); 1014 llvm::report_fatal_error("PrintDebugName");
643 } 1015 }
644 1016
645 CfgNode *Control() { 1017 CfgNode *Control() {
646 return ControlPtr ? ControlPtr->toCfgNode() : Func->getEntryNode(); 1018 return ControlPtr ? ControlPtr->toCfgNode() : Func->getEntryNode();
647 } 1019 }
648 Node Effect() { return *EffectPtr; } 1020 Node Effect() { return *EffectPtr; }
649 1021
650 void set_module(wasm::ModuleEnv *Module) { this->Module = Module; } 1022 void set_module(wasm::ModuleEnv *Module) { this->Module = Module; }
651 1023
(...skipping 46 matching lines...) Expand 10 before | Expand all | Expand 10 after
698 } 1070 }
699 1071
700 template <typename F = std::function<void(Ostream &)>> void log(F Fn) const { 1072 template <typename F = std::function<void(Ostream &)>> void log(F Fn) const {
701 if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) { 1073 if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) {
702 Fn(Ctx->getStrDump()); 1074 Fn(Ctx->getStrDump());
703 Ctx->getStrDump().flush(); 1075 Ctx->getStrDump().flush();
704 } 1076 }
705 } 1077 }
706 }; 1078 };
707 1079
708 std::string fnNameFromId(uint32_t Id) {
709 return std::string("fn") + to_string(Id);
710 }
711
712 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, 1080 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone,
713 FunctionEnv *Env, 1081 FunctionBody &Body) {
714 const byte *Base,
715 const byte *Start,
716 const byte *End) {
717 OstreamLocker L1(Ctx); 1082 OstreamLocker L1(Ctx);
718 auto Func = Cfg::create(Ctx, getNextSequenceNumber()); 1083 auto Func = Cfg::create(Ctx, getNextSequenceNumber());
719 Ice::CfgLocalAllocatorScope L2(Func.get()); 1084 Ice::CfgLocalAllocatorScope L2(Func.get());
720 1085
721 // TODO: parse the function signature... 1086 // TODO(eholk): parse the function signature...
1087
1088 Func->setEntryNode(Func->makeNode());
722 1089
723 IceBuilder Builder(Func.get()); 1090 IceBuilder Builder(Func.get());
724 LR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder); 1091 SR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder, Body);
725 1092
726 LOG(out << getFlags().getDefaultGlobalPrefix() << "\n"); 1093 LOG(out << getFlags().getDefaultGlobalPrefix() << "\n");
727 Decoder.Decode(Env, Base, Start, End); 1094 Decoder.Decode();
728 1095
729 // We don't always know where the incoming branches are in phi nodes, so this 1096 // We don't always know where the incoming branches are in phi nodes, so this
730 // function finds them. 1097 // function finds them.
731 Func->fixPhiNodes(); 1098 Func->fixPhiNodes();
732 1099
1100 Func->computeInOutEdges();
1101
733 return Func; 1102 return Func;
734 } 1103 }
735 1104
736 WasmTranslator::WasmTranslator(GlobalContext *Ctx) 1105 WasmTranslator::WasmTranslator(GlobalContext *Ctx)
737 : Translator(Ctx), BufferSize(24 << 10), Buffer(new uint8_t[24 << 10]) { 1106 : Translator(Ctx), Buffer(new uint8_t[24 << 10]), BufferSize(24 << 10) {
738 // TODO(eholk): compute the correct buffer size. This uses 24k by default, 1107 // TODO(eholk): compute the correct buffer size. This uses 24k by default,
739 // which has been big enough for testing but is not a general solution. 1108 // which has been big enough for testing but is not a general solution.
740 } 1109 }
741 1110
742 void WasmTranslator::translate( 1111 void WasmTranslator::translate(
743 const std::string &IRFilename, 1112 const std::string &IRFilename,
744 std::unique_ptr<llvm::DataStreamer> InputStream) { 1113 std::unique_ptr<llvm::DataStreamer> InputStream) {
745 LOG(out << "Initializing v8/wasm stuff..." 1114 LOG(out << "Initializing v8/wasm stuff..."
746 << "\n"); 1115 << "\n");
747 Zone Zone; 1116 Zone Zone;
748 ZoneScope _(&Zone); 1117 ZoneScope _(&Zone);
749 1118
750 SizeT BytesRead = InputStream->GetBytes(Buffer.get(), BufferSize); 1119 SizeT BytesRead = InputStream->GetBytes(Buffer.get(), BufferSize);
751 LOG(out << "Read " << BytesRead << " bytes" 1120 LOG(out << "Read " << BytesRead << " bytes"
752 << "\n"); 1121 << "\n");
753 1122
754 LOG(out << "Decoding module " << IRFilename << "\n"); 1123 LOG(out << "Decoding module " << IRFilename << "\n");
755 1124
756 constexpr v8::internal::Isolate *NoIsolate = nullptr; 1125 constexpr v8::internal::Isolate *NoIsolate = nullptr;
757 auto Result = DecodeWasmModule(NoIsolate, &Zone, Buffer.get(), 1126 auto Result = DecodeWasmModule(NoIsolate, &Zone, Buffer.get(),
758 Buffer.get() + BytesRead, false, kWasmOrigin); 1127 Buffer.get() + BytesRead, false, kWasmOrigin);
759 1128
760 auto Module = Result.val; 1129 auto Module = Result.val;
761 1130
762 LOG(out << "Module info:" 1131 LOG(out << "Module info:"
763 << "\n"); 1132 << "\n");
1133 LOG(out << " min_mem_pages: " << Module->min_mem_pages << "\n");
1134 LOG(out << " max_mem_pages: " << Module->max_mem_pages << "\n");
764 LOG(out << " number of globals: " << Module->globals.size() << "\n"); 1135 LOG(out << " number of globals: " << Module->globals.size() << "\n");
765 LOG(out << " number of signatures: " << Module->signatures.size() 1136 LOG(out << " number of signatures: " << Module->signatures.size()
766 << "\n"); 1137 << "\n");
767 LOG(out << " number of functions: " << Module->functions.size() << "\n"); 1138 LOG(out << " number of functions: " << Module->functions.size() << "\n");
768 LOG(out << " number of data_segments: " << Module->data_segments.size() 1139 LOG(out << " number of data_segments: " << Module->data_segments.size()
769 << "\n"); 1140 << "\n");
770 LOG(out << " function table size: " << Module->function_table.size() 1141 LOG(out << " function table size: " << Module->function_table.size()
771 << "\n"); 1142 << "\n");
1143 LOG(out << " import table size: " << Module->import_table.size()
1144 << "\n");
1145 LOG(out << " export table size: " << Module->export_table.size()
1146 << "\n");
772 1147
773 ModuleEnv ModuleEnv; 1148 LOG(out << "\n"
774 ModuleEnv.module = Module; 1149 << "Data segment information:"
1150 << "\n");
1151 uint32_t Id = 0;
1152 for (const auto Seg : Module->data_segments) {
1153 LOG(out << Id << ": (" << Seg.source_offset << ", " << Seg.source_size
1154 << ") => " << Seg.dest_addr);
1155 if (Seg.init) {
1156 LOG(out << " init\n");
1157 } else {
1158 LOG(out << "\n");
1159 }
1160 Id++;
1161 }
1162
1163 LOG(out << "\n"
1164 << "Import information:"
1165 << "\n");
1166 for (const auto Import : Module->import_table) {
1167 auto ModuleName = toStdString(
1168 Module->GetName(Import.module_name_offset, Import.module_name_length));
1169 auto FnName = toStdString(Module->GetName(Import.function_name_offset,
1170 Import.function_name_length));
1171 LOG(out << " " << Import.sig_index << ": " << ModuleName << "::" << FnName
1172 << "\n");
1173 }
1174
1175 LOG(out << "\n"
1176 << "Export information:"
1177 << "\n");
1178 for (const auto Export : Module->export_table) {
1179 LOG(out << " " << Export.func_index << ": "
1180 << toStdString(
1181 Module->GetName(Export.name_offset, Export.name_length))
1182 << " (" << Export.name_offset << ", " << Export.name_length << ")");
1183 LOG(out << "\n");
1184 }
775 1185
776 LOG(out << "\n" 1186 LOG(out << "\n"
777 << "Function information:" 1187 << "Function information:"
778 << "\n"); 1188 << "\n");
779 for (const auto F : Module->functions) { 1189 for (const auto F : Module->functions) {
780 LOG(out << " " << F.name_offset << ": " << Module->GetName(F.name_offset)); 1190 LOG(out << " " << F.func_index << ": "
1191 << toStdString(Module->GetName(F.name_offset, F.name_length))
1192 << " (" << F.name_offset << ", " << F.name_length << ")");
781 if (F.exported) 1193 if (F.exported)
782 LOG(out << " export"); 1194 LOG(out << " export");
783 if (F.external) 1195 if (F.external)
784 LOG(out << " extern"); 1196 LOG(out << " extern");
785 LOG(out << "\n"); 1197 LOG(out << "\n");
786 } 1198 }
787 1199
788 FunctionEnv Fenv; 1200 LOG(out << "\n"
789 Fenv.module = &ModuleEnv; 1201 << "Indirect table:"
1202 << "\n");
1203 for (uint32_t F : Module->function_table) {
1204 LOG(out << " " << F << ": " << getFunctionName(Module, F) << "\n");
1205 }
1206
1207 ModuleEnv ModuleEnv;
1208 ModuleEnv.module = Module;
1209
1210 FunctionBody Body;
1211 Body.module = &ModuleEnv;
790 1212
791 LOG(out << "Translating " << IRFilename << "\n"); 1213 LOG(out << "Translating " << IRFilename << "\n");
792 1214
1215 {
1216 unique_ptr<VariableDeclarationList> Globals =
1217 makeUnique<VariableDeclarationList>();
1218
1219 // Global variables, etc go here.
1220 auto *WasmMemory = VariableDeclaration::createExternal(Globals.get());
1221 WasmMemory->setName(Ctx->getGlobalString("WASM_MEMORY"));
1222
1223 // Fill in the segments
1224 SizeT WritePtr = 0;
1225 for (const auto Seg : Module->data_segments) {
1226 // fill in gaps with zero.
1227 if (Seg.dest_addr > WritePtr) {
1228 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
1229 Globals.get(), Seg.dest_addr - WritePtr));
1230 WritePtr = Seg.dest_addr;
1231 }
1232
1233 // Add the data
1234 WasmMemory->addInitializer(VariableDeclaration::DataInitializer::create(
1235 Globals.get(), reinterpret_cast<const char *>(Module->module_start) +
1236 Seg.source_offset,
1237 Seg.source_size));
1238
1239 WritePtr += Seg.source_size;
1240 }
1241
1242 // Pad the rest with zeros
1243 SizeT DataSize = Module->min_mem_pages * WASM_PAGE_SIZE;
1244 if (WritePtr < DataSize) {
1245 WasmMemory->addInitializer(VariableDeclaration::ZeroInitializer::create(
1246 Globals.get(), DataSize - WritePtr));
1247 }
1248
1249 Globals->push_back(WasmMemory);
1250
1251 lowerGlobals(std::move(Globals));
1252 }
1253
793 // Translate each function. 1254 // Translate each function.
794 uint32_t Id = 0;
795 for (const auto Fn : Module->functions) { 1255 for (const auto Fn : Module->functions) {
796 std::string NewName = fnNameFromId(Id++); 1256 const auto FnName = getFunctionName(Module, Fn.func_index);
797 LOG(out << " " << Fn.name_offset << ": " << Module->GetName(Fn.name_offset)
798 << " -> " << NewName << "...");
799 1257
800 Fenv.sig = Fn.sig; 1258 LOG(out << " " << Fn.func_index << ": " << FnName << "...");
801 Fenv.local_i32_count = Fn.local_i32_count;
802 Fenv.local_i64_count = Fn.local_i64_count;
803 Fenv.local_f32_count = Fn.local_f32_count;
804 Fenv.local_f64_count = Fn.local_f64_count;
805 Fenv.SumLocals();
806 1259
807 auto Func = translateFunction(&Zone, &Fenv, Buffer.get(), 1260 Body.sig = Fn.sig;
808 Buffer.get() + Fn.code_start_offset, 1261 Body.base = Buffer.get();
809 Buffer.get() + Fn.code_end_offset); 1262 Body.start = Buffer.get() + Fn.code_start_offset;
810 Func->setFunctionName(Ctx->getGlobalString(NewName)); 1263 Body.end = Buffer.get() + Fn.code_end_offset;
1264
1265 auto Func = translateFunction(&Zone, Body);
1266 Func->setFunctionName(Ctx->getGlobalString(FnName));
811 1267
812 Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func))); 1268 Ctx->optQueueBlockingPush(makeUnique<CfgOptWorkItem>(std::move(Func)));
813 LOG(out << "done.\n"); 1269 LOG(out << "done.\n");
814 } 1270 }
815 1271
816 return; 1272 return;
817 } 1273 }
818 1274
819 #endif // ALLOW_WASM 1275 #endif // ALLOW_WASM
OLDNEW
« fetch-torture-tests.sh ('K') | « src/WasmTranslator.h ('k') | wasm-tests/hello-printf.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698