OLD | NEW |
---|---|
(Empty) | |
1 #include "WasmTranslator.h" | |
JF
2016/03/28 18:17:13
Copyright.
Eric Holk
2016/03/29 19:54:09
Done.
| |
2 | |
3 #include "IceGlobalInits.h" | |
4 #include "IceCfgNode.h" | |
5 | |
6 #include "src/wasm/module-decoder.h" | |
7 #include "src/wasm/wasm-opcodes.h" | |
8 | |
9 #include "src/zone.h" | |
10 | |
11 using namespace std; | |
12 using namespace Ice; | |
13 using namespace v8; | |
14 using namespace v8::internal; | |
15 using namespace v8::internal::wasm; | |
16 using v8::internal::wasm::DecodeWasmModule; | |
17 | |
18 #include "src/wasm/ast-decoder-impl.h" | |
19 | |
20 Ice::Type toIceType(v8::internal::MachineType) { | |
21 // TODO(eholk): actually convert this. | |
22 return IceType_i32; | |
23 } | |
24 | |
25 Ice::Type toIceType(wasm::LocalType Type) { | |
26 | |
27 switch (Type) { | |
28 default: | |
29 assert(false && "unexpected enum value"); | |
30 case MachineRepresentation::kNone: | |
31 assert(false && "kNone type not supported"); | |
32 case MachineRepresentation::kBit: | |
33 return IceType_i1; | |
34 case MachineRepresentation::kWord8: | |
35 return IceType_i8; | |
36 case MachineRepresentation::kWord16: | |
37 return IceType_i16; | |
38 case MachineRepresentation::kWord32: | |
39 return IceType_i32; | |
40 case MachineRepresentation::kWord64: | |
41 return IceType_i64; | |
42 case MachineRepresentation::kFloat32: | |
43 return IceType_f32; | |
44 case MachineRepresentation::kFloat64: | |
45 return IceType_f64; | |
46 case MachineRepresentation::kSimd128: | |
47 assert(false && "ambiguous SIMD type"); | |
48 case MachineRepresentation::kTagged: | |
49 assert(false && "kTagged type not supported"); | |
JF
2016/03/28 18:17:13
llvm_unreachable for the few asserts above.
Eric Holk
2016/03/29 19:54:10
Done.
| |
50 } | |
51 } | |
52 | |
53 /** | |
54 This class wraps either and Operand or a CfgNode. | |
John
2016/03/28 18:44:09
an Operand
Eric Holk
2016/03/29 19:54:09
Done.
| |
55 | |
56 Turbofan's sea of nodes representation only has nodes for values, control | |
57 flow, etc. In Subzero these concepts are all separate. This class let's V8's | |
58 Wasm decoder treat Subzero objects as though they are all the same. | |
59 */ | |
60 class OperandNode { | |
61 static constexpr uintptr_t NODE_FLAG = 1; | |
62 static constexpr uintptr_t UNDEF_PTR = (uintptr_t)-1; | |
63 | |
64 public: | |
65 uintptr_t Data; | |
66 | |
67 OperandNode() : Data(UNDEF_PTR) {} | |
68 OperandNode(Operand *Operand) : Data((uintptr_t)Operand) {} | |
69 OperandNode(CfgNode *Node) : Data((uintptr_t)Node | NODE_FLAG) {} | |
70 OperandNode(nullptr_t) : Data(UNDEF_PTR) {} | |
71 | |
72 operator Operand *() const { | |
John
2016/03/28 18:44:07
explicit?
Eric Holk
2016/03/29 19:54:09
I'd rather not. The goal was to make something tha
| |
73 if (UNDEF_PTR == Data) { | |
74 return nullptr; | |
75 } | |
76 assert(isOperand()); | |
77 return (Operand *)Data; | |
John
2016/03/28 18:44:07
reinterpret_cast<Operand *>(Data);
Eric Holk
2016/03/29 19:54:10
Done.
| |
78 } | |
79 | |
80 operator CfgNode *() const { | |
81 if (UNDEF_PTR == Data) { | |
82 return nullptr; | |
83 } | |
84 assert(isCfgNode()); | |
85 return (CfgNode *)(Data & ~NODE_FLAG); | |
86 } | |
87 | |
88 operator bool() const { return (Data != UNDEF_PTR) && Data; } | |
John
2016/03/28 18:44:10
explicit operator? -- I personally do not like imp
Eric Holk
2016/03/29 19:54:09
Done.
| |
89 bool operator!=(const OperandNode &Rhs) const { | |
John
2016/03/28 18:44:07
why not:
bool operator==() { return Data == Rhs.D
Eric Holk
2016/03/29 19:54:12
It's probably cleaner to have operator== and then
| |
90 return (UNDEF_PTR == Data && Rhs.Data != UNDEF_PTR && Rhs.Data) || | |
91 (UNDEF_PTR == Rhs.Data && Data != UNDEF_PTR && Data) || | |
92 Data != Rhs.Data; | |
93 } | |
94 | |
95 bool isOperand() const { return !(Data & NODE_FLAG); } | |
96 bool isCfgNode() const { return Data & NODE_FLAG; } | |
97 }; | |
98 | |
99 Ostream &operator<<(Ostream &Out, const OperandNode &Op) { | |
100 if (Op.isOperand()) { | |
101 auto Oper = (Operand *)Op; | |
John
2016/03/28 18:44:09
static_cast -- or even better, Op.getOperand();
| |
102 Out << "(Operand*)" << Oper; | |
103 } else if (Op.isCfgNode()) { | |
104 auto Node = (CfgNode *)Op; | |
105 Out << "(CfgNode*)" << Node; | |
106 } else { | |
107 Out << "nullptr"; | |
108 } | |
109 return Out; | |
110 } | |
111 | |
112 constexpr bool isComparison(wasm::WasmOpcode Opcode) { | |
113 switch (Opcode) { | |
114 case kExprI32Ne: | |
115 case kExprI64Ne: | |
116 case kExprI32Eq: | |
117 case kExprI64Eq: | |
118 case kExprI32LtS: | |
119 case kExprI64LtS: | |
120 case kExprI32LtU: | |
121 case kExprI64LtU: | |
122 case kExprI32GeS: | |
123 case kExprI64GeS: | |
124 case kExprI32GtS: | |
125 case kExprI64GtS: | |
126 case kExprI32GtU: | |
127 case kExprI64GtU: | |
128 return true; | |
129 default: | |
130 return false; | |
131 } | |
132 } | |
133 | |
134 #define LOG(Expr) log([&](Ostream & out) { Expr; }) | |
John
2016/03/28 18:44:10
default capture by reference -- even on a define -
Eric Holk
2016/03/29 19:54:11
Yeah... I don't super love this either. I don't re
| |
135 | |
136 class IceBuilder { | |
137 using Node = OperandNode; | |
138 | |
John
2016/03/28 18:44:10
Move the following to the end of the class declara
Eric Holk
2016/03/29 19:54:09
Done and Done.
| |
139 wasm::ModuleEnv *module_; | |
John
2016/03/28 18:44:08
Module
| |
140 Node *control_; | |
141 Node *effect_; | |
142 | |
143 class Cfg *Cfg; | |
144 GlobalContext *Ctx; | |
145 | |
146 SizeT NextArg = 0; | |
147 | |
148 template <typename F = std::function<void(Ostream &)>> void log(F Fn) { | |
149 if (BuildDefs::dump() && (Ctx->getFlags().getVerbose() & IceV_Wasm)) { | |
150 Fn(Ctx->getStrDump()); | |
John
2016/03/28 18:44:09
don't you want to lock the ostream before invoking
Eric Holk
2016/03/29 19:54:12
Done, and also in WasmTranslator.h
| |
151 Ctx->getStrDump().flush(); | |
152 } | |
153 } | |
154 | |
155 public: | |
156 IceBuilder(class Cfg *Cfg) | |
157 : Cfg(Cfg), Ctx(Cfg->getContext()), control_(nullptr) {} | |
John
2016/03/28 18:44:08
I would love member to be named all lower case, wi
Eric Holk
2016/03/29 19:54:10
Done.
| |
158 | |
159 Node *Buffer(size_t Count) { | |
John
2016/03/28 18:44:08
allocateBuffer -- the name Buffer() does not reall
Eric Holk
2016/03/29 19:54:11
This name was dictated by the WasmBuilder from V8.
| |
160 LOG(out << "Buffer(" << Count << ")\n"); | |
161 return Cfg->allocateArrayOf<Node>(Count); | |
162 } | |
163 | |
164 Node Error() { llvm_unreachable("Error"); } | |
165 Node Start(unsigned params) { | |
166 LOG(out << "Start(" << params << ") = "); | |
167 auto Entry = Cfg->makeNode(); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:10
I left the * off because I remember your pointer r
| |
168 Cfg->setEntryNode(Entry); | |
169 LOG(out << Node(Entry) << "\n"); | |
170 return Entry; | |
171 } | |
172 Node Param(unsigned Index, wasm::LocalType Type) { | |
173 LOG(out << "Param(" << Index << ") = "); | |
174 auto Arg = Cfg->makeVariable(toIceType(Type)); | |
John
2016/03/28 18:44:08
auto *
Eric Holk
2016/03/29 19:54:09
Done.
| |
175 assert(Index == NextArg); | |
176 Cfg->addArg(Arg); | |
177 Arg->setDefNode(Cfg->getEntryNode()); | |
178 NextArg++; | |
179 LOG(out << Node(Arg) << "\n"); | |
180 return Arg; | |
181 } | |
182 CfgNode *Loop(CfgNode *Entry) { | |
183 Node Loop = Cfg->makeNode(); | |
John
2016/03/28 18:44:08
auto *
Eric Holk
2016/03/29 19:54:09
Done.
| |
184 LOG(out << "Loop(" << Entry << ") = " << Loop << "\n"); | |
185 Entry->appendInst(InstBr::create(Cfg, Loop)); | |
186 return Loop; | |
187 } | |
188 void Terminate(Node Effect, Node Control) { | |
189 // TODO(eholk): this is almost certainly wrong | |
190 LOG(out << "Terminate(" << Effect << ", " << Control << ")" | |
191 << "\n"); | |
192 } | |
193 Node Merge(unsigned Count, Node *Controls) { | |
194 LOG(out << "Merge(" << Count); | |
195 for (auto i = 0; i < Count; ++i) { | |
196 LOG(out << ", " << Controls[i]); | |
197 } | |
198 LOG(out << ") = "); | |
199 | |
200 auto MergedNode = Cfg->makeNode(); | |
John
2016/03/28 18:44:07
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
201 | |
202 for (auto i = 0; i < Count; ++i) { | |
203 CfgNode *Control = Controls[i]; | |
204 Control->appendInst(InstBr::create(Cfg, MergedNode)); | |
205 } | |
206 LOG(out << (OperandNode)MergedNode << "\n"); | |
207 return MergedNode; | |
208 } | |
209 Node Phi(wasm::LocalType Type, unsigned Count, Node *Vals, Node Control) { | |
210 LOG(out << "Phi(" << Count << ", " << Control); | |
211 for (int i = 0; i < Count; ++i) { | |
212 LOG(out << ", " << Vals[i]); | |
213 } | |
214 LOG(out << ") = "); | |
215 | |
216 const auto InEdges = ((CfgNode *)Control)->getInEdges(); | |
John
2016/03/28 18:44:10
static_cast<>
Eric Holk
2016/03/29 19:54:11
Done.
| |
217 assert(Count == InEdges.size()); | |
218 | |
219 assert(Count > 0); | |
220 | |
221 auto Dest = Cfg->makeVariable(((Operand *)Vals[0])->getType()); | |
John
2016/03/28 18:44:08
auto *
Eric Holk
2016/03/29 19:54:11
Done. I also added a static_cast.
| |
222 | |
223 // Multiply by 10 in case more things get added later. | |
224 | |
225 // TODO(eholk): find a better way besides multiplying by some arbitrary | |
226 // constant. | |
227 auto Phi = InstPhi::create(Cfg, Count * 10, Dest); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:09
Done.
| |
228 for (int i = 0; i < Count; ++i) { | |
229 auto Op = (Operand *)Vals[i]; | |
John
2016/03/28 18:44:08
static_cast<>
Eric Holk
2016/03/29 19:54:10
Done.
| |
230 assert(Op); | |
231 Phi->addArgument(Op, InEdges[i]); | |
232 } | |
233 ((CfgNode *)Control)->appendInst(Phi); | |
John
2016/03/28 18:44:08
static_cast<>
Eric Holk
2016/03/29 19:54:11
Done.
| |
234 LOG(out << Node(Dest) << "\n"); | |
235 return Dest; | |
236 } | |
237 Node EffectPhi(unsigned Count, Node *Effects, Node Control) { | |
238 // TODO(eholk): this function is almost certainly wrong. | |
239 LOG(out << "EffectPhi(" << Count << ", " << Control << "):\n"); | |
240 for (auto i = 0; i < Count; ++i) { | |
John
2016/03/28 18:44:09
no auto for integral types?...
Eric Holk
2016/03/29 19:54:11
Ok.
| |
241 LOG(out << " " << Effects[i] << "\n"); | |
242 } | |
243 return nullptr; | |
244 } | |
245 Node Int32Constant(int32_t Value) { | |
246 LOG(out << "Int32Constant(" << Value << ") = "); | |
247 auto Const = Ctx->getConstantInt32(Value); | |
John
2016/03/28 18:44:10
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
248 assert(Const); | |
249 assert(Control()); | |
250 Const->setDefNode(Control()); | |
251 LOG(out << Node(Const) << "\n"); | |
252 return Const; | |
253 } | |
254 Node Int64Constant(int64_t Value) { | |
255 LOG(out << "Int64Constant(" << Value << ") = "); | |
256 auto Const = Ctx->getConstantInt64(Value); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:12
Done.
| |
257 assert(Const); | |
258 Const->setDefNode(Control()); | |
259 LOG(out << Node(Const) << "\n"); | |
260 return Const; | |
261 } | |
262 Node Float32Constant(float Value) { | |
263 LOG(out << "Float32Constant(" << Value << ") = "); | |
264 auto Const = Ctx->getConstantFloat(Value); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:12
Done.
| |
265 assert(Const); | |
266 Const->setDefNode(Control()); | |
267 LOG(out << Node(Const) << "\n"); | |
268 return Const; | |
269 } | |
270 Node Float64Constant(double Value) { | |
271 LOG(out << "Float64Constant(" << Value << ") = "); | |
272 auto Const = Ctx->getConstantDouble(Value); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:12
Done.
| |
273 assert(Const); | |
274 Const->setDefNode(Control()); | |
275 LOG(out << Node(Const) << "\n"); | |
276 return Const; | |
277 } | |
278 Node Binop(wasm::WasmOpcode Opcode, Node Left, Node Right) { | |
279 LOG(out << "Binop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Left | |
280 << ", " << Right << ") = "); | |
281 Ice::Variable *Dest = Cfg->makeVariable( | |
John
2016/03/28 18:44:08
auto *
Eric Holk
2016/03/29 19:54:09
Done.
| |
282 isComparison(Opcode) ? IceType_i1 : ((Operand *)Left)->getType()); | |
John
2016/03/28 18:44:08
static_cast<>
Eric Holk
2016/03/29 19:54:11
Done.
| |
283 switch (Opcode) { | |
284 case kExprI32Add: | |
285 case kExprI64Add: | |
286 Control()->appendInst( | |
287 InstArithmetic::create(Cfg, InstArithmetic::Add, Dest, Left, Right)); | |
288 break; | |
289 case kExprI32Sub: | |
290 case kExprI64Sub: | |
291 Control()->appendInst( | |
292 InstArithmetic::create(Cfg, InstArithmetic::Sub, Dest, Left, Right)); | |
293 break; | |
294 case kExprI32Mul: | |
295 case kExprI64Mul: | |
296 Control()->appendInst( | |
297 InstArithmetic::create(Cfg, InstArithmetic::Mul, Dest, Left, Right)); | |
298 break; | |
299 case kExprI32DivU: | |
300 case kExprI64DivU: | |
301 Control()->appendInst( | |
302 InstArithmetic::create(Cfg, InstArithmetic::Udiv, Dest, Left, Right)); | |
303 break; | |
304 case kExprI32RemU: | |
305 case kExprI64RemU: | |
306 Control()->appendInst( | |
307 InstArithmetic::create(Cfg, InstArithmetic::Urem, Dest, Left, Right)); | |
308 break; | |
309 case kExprI32Ior: | |
310 case kExprI64Ior: | |
311 Control()->appendInst( | |
312 InstArithmetic::create(Cfg, InstArithmetic::Or, Dest, Left, Right)); | |
313 break; | |
314 case kExprI32Xor: | |
315 case kExprI64Xor: | |
316 Control()->appendInst( | |
317 InstArithmetic::create(Cfg, InstArithmetic::Xor, Dest, Left, Right)); | |
318 break; | |
319 case kExprI32Shl: | |
320 case kExprI64Shl: | |
321 Control()->appendInst( | |
322 InstArithmetic::create(Cfg, InstArithmetic::Shl, Dest, Left, Right)); | |
323 break; | |
324 case kExprI32ShrU: | |
325 case kExprI64ShrU: | |
326 case kExprI32ShrS: | |
327 case kExprI64ShrS: | |
328 Control()->appendInst( | |
329 InstArithmetic::create(Cfg, InstArithmetic::Ashr, Dest, Left, Right)); | |
330 break; | |
331 case kExprI32And: | |
332 case kExprI64And: | |
333 Control()->appendInst( | |
334 InstArithmetic::create(Cfg, InstArithmetic::And, Dest, Left, Right)); | |
335 break; | |
336 case kExprI32Ne: | |
337 case kExprI64Ne: | |
338 Control()->appendInst( | |
339 InstIcmp::create(Cfg, InstIcmp::Ne, Dest, Left, Right)); | |
340 break; | |
341 case kExprI32Eq: | |
342 case kExprI64Eq: | |
343 Control()->appendInst( | |
344 InstIcmp::create(Cfg, InstIcmp::Eq, Dest, Left, Right)); | |
345 break; | |
346 case kExprI32LtS: | |
347 case kExprI64LtS: | |
348 Control()->appendInst( | |
349 InstIcmp::create(Cfg, InstIcmp::Slt, Dest, Left, Right)); | |
350 break; | |
351 case kExprI32LtU: | |
352 case kExprI64LtU: | |
353 Control()->appendInst( | |
354 InstIcmp::create(Cfg, InstIcmp::Ult, Dest, Left, Right)); | |
355 break; | |
356 case kExprI32GeS: | |
357 case kExprI64GeS: | |
358 Control()->appendInst( | |
359 InstIcmp::create(Cfg, InstIcmp::Sge, Dest, Left, Right)); | |
360 case kExprI32GtS: | |
361 case kExprI64GtS: | |
362 Control()->appendInst( | |
363 InstIcmp::create(Cfg, InstIcmp::Sgt, Dest, Left, Right)); | |
364 break; | |
365 case kExprI32GtU: | |
366 case kExprI64GtU: | |
367 Control()->appendInst( | |
368 InstIcmp::create(Cfg, InstIcmp::Ugt, Dest, Left, Right)); | |
369 break; | |
370 default: | |
371 LOG(out << "Unknown binop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); | |
372 assert(false && "Uncovered or invalid binop."); | |
373 return nullptr; | |
374 } | |
375 LOG(out << Dest << "\n"); | |
376 assert(Dest->getDefNode()); | |
377 return Dest; | |
378 } | |
379 Node Unop(wasm::WasmOpcode Opcode, Node Input) { | |
380 LOG(out << "Unop(" << WasmOpcodes::OpcodeName(Opcode) << ", " << Input | |
381 << ") = "); | |
382 Ice::Variable *Dest = nullptr; | |
383 switch (Opcode) { | |
384 case kExprF32Neg: { | |
385 Dest = Cfg->makeVariable(IceType_f32); | |
386 auto Zero = Cfg->makeVariable(IceType_f32); | |
John
2016/03/28 18:44:10
auto *
| |
387 Control()->appendInst(InstAssign::create(Cfg, Zero, Ctx->getConstantFloat( 0))); | |
John
2016/03/28 18:44:08
80 col
Eric Holk
2016/03/29 19:54:11
Done.
| |
388 Control()->appendInst(InstArithmetic::create(Cfg, InstArithmetic::Fsub, De st, Zero, Input)); | |
John
2016/03/28 18:44:08
80 col
Eric Holk
2016/03/29 19:54:10
Done.
| |
389 break; | |
390 } | |
391 case kExprF64Neg: { | |
392 Dest = Cfg->makeVariable(IceType_f64); | |
393 auto Zero = Cfg->makeVariable(IceType_f64); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:10
Done.
| |
394 Control()->appendInst(InstAssign::create(Cfg, Zero, Ctx->getConstantDouble (0))); | |
John
2016/03/28 18:44:09
80 col
Eric Holk
2016/03/29 19:54:10
Done.
| |
395 Control()->appendInst(InstArithmetic::create(Cfg, InstArithmetic::Fsub, De st, Zero, Input)); | |
John
2016/03/28 18:44:08
80 col
Eric Holk
2016/03/29 19:54:09
Done.
| |
396 break; | |
397 } | |
398 case kExprI64UConvertI32: | |
399 Dest = Cfg->makeVariable(IceType_i64); | |
400 Control()->appendInst(InstCast::create(Cfg, InstCast::Zext, Dest, Input)); | |
401 break; | |
402 default: | |
403 LOG(out << "Unknown unop: " << WasmOpcodes::OpcodeName(Opcode) << "\n"); | |
404 assert(false && "Uncovered or invalid unop."); | |
405 return nullptr; | |
406 } | |
407 LOG(out << Dest << "\n"); | |
408 return Dest; | |
409 } | |
410 unsigned InputCount(CfgNode *Node) { return Node->getInEdges().size(); } | |
John
2016/03/28 18:44:07
this should not be a member class -- it is really
Eric Holk
2016/03/29 19:54:09
This is a function called from V8, so we have to m
| |
411 bool IsPhiWithMerge(Node Phi, Node Merge) { | |
412 LOG(out << "IsPhiWithMerge(" << Phi << ", " << Merge << ")" | |
413 << "\n"); | |
414 if (Phi && Phi.isOperand()) { | |
415 LOG(out << " ...is operand" | |
416 << "\n"); | |
417 if (auto RealPhi = llvm::dyn_cast<Ice::Variable>((Operand *)Phi)) { | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
418 LOG(out << " ...is variable" | |
419 << "\n"); | |
420 if (auto Inst = RealPhi->getDefiningInst()) { | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
421 LOG(out << " ...has defining instruction" | |
422 << "\n"); | |
423 | |
424 if (Inst->getKind() != Inst::Phi) | |
425 return false; | |
426 LOG(out << " ...is phi" | |
427 << "\n"); | |
428 | |
429 LOG(out << " ..." << (Inst->getCfgNode() == Merge) << "\n"); | |
430 return Inst->getCfgNode() == Merge; | |
431 } | |
432 } | |
433 } | |
434 return false; | |
435 } | |
436 void AppendToMerge(CfgNode *Merge, CfgNode *From) { | |
John
2016/03/28 18:44:09
AppendToMerge is a funny name; you're not really a
Eric Holk
2016/03/29 19:54:10
It's from V8 again. The idea is there is a merge n
| |
437 From->appendInst(InstBr::create(Cfg, Merge)); | |
438 } | |
439 void AppendToPhi(Node Merge, Node Phi, Node From) { | |
440 LOG(out << "AppendToPhi(" << Merge << ", " << Phi << ", " << From << ")" | |
441 << "\n"); | |
442 auto Var = llvm::cast<Ice::Variable>((Operand *)Phi); | |
John
2016/03/28 18:44:08
auto *
Eric Holk
2016/03/29 19:54:12
Done.
| |
443 assert(Var->getDefiningInst()->getKind() == Inst::Phi); | |
444 auto Inst = llvm::cast<InstPhi>(Var->getDefiningInst()); | |
John
2016/03/28 18:44:10
auto *
Eric Holk
2016/03/29 19:54:09
Done.
| |
445 auto FromVar = llvm::cast<Ice::Variable>((Operand *)From); | |
John
2016/03/28 18:44:07
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
446 Inst->addArgument(From, FromVar->getDefiningInst()->getCfgNode()); | |
447 } | |
448 | |
449 //----------------------------------------------------------------------- | |
450 // Operations that read and/or write {control} and {effect}. | |
451 //----------------------------------------------------------------------- | |
452 nullptr_t Branch(Node Cond, Node *TrueNode, Node *FalseNode) { | |
John
2016/03/28 18:44:08
void instead?
Eric Holk
2016/03/29 19:54:09
I tried, but V8 expects this function to return a
| |
453 // true_node and false_node appear to be out parameters. | |
454 LOG(out << "Branch(" << Cond << ", "); | |
455 | |
456 // save control here because true_node appears to alias control. | |
457 auto Ctrl = Control(); | |
John
2016/03/28 18:44:07
auto *?
Eric Holk
2016/03/29 19:54:09
Done.
| |
458 | |
459 *TrueNode = Cfg->makeNode(); | |
460 *FalseNode = Cfg->makeNode(); | |
461 | |
462 LOG(out << *TrueNode << ", " << *FalseNode << ")" | |
463 << "\n"); | |
464 | |
465 Ctrl->appendInst(InstBr::create(Cfg, Cond, *TrueNode, *FalseNode)); | |
466 return nullptr; | |
467 } | |
468 Node Switch(unsigned Count, Node Key) { llvm_unreachable("Switch"); } | |
469 Node IfValue(int32_t Value, Node Sw) { llvm_unreachable("IfValue"); } | |
470 Node IfDefault(Node Sw) { llvm_unreachable("IfDefault"); } | |
471 Node Return(unsigned Count, Node *Vals) { | |
472 assert(1 >= Count); | |
473 LOG(out << "Return("); | |
474 if (Count > 0) | |
475 LOG(out << Vals[0]); | |
476 LOG(out << ")" | |
477 << "\n"); | |
478 auto Instr = | |
John
2016/03/28 18:44:10
auto *
Eric Holk
2016/03/29 19:54:09
Done.
| |
479 1 == Count ? InstRet::create(Cfg, Vals[0]) : InstRet::create(Cfg); | |
480 Control()->appendInst(Instr); | |
481 Control()->setHasReturn(); | |
482 LOG(out << Node(nullptr) << "\n"); | |
483 return nullptr; | |
484 } | |
485 Node ReturnVoid() { | |
486 LOG(out << "ReturnVoid() = "); | |
487 auto Instr = InstRet::create(Cfg); | |
John
2016/03/28 18:44:10
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
488 Control()->appendInst(Instr); | |
489 Control()->setHasReturn(); | |
490 LOG(out << Node(nullptr) << "\n"); | |
491 return nullptr; | |
492 } | |
493 Node Unreachable() { | |
494 LOG(out << "Unreachable() = "); | |
495 auto Instr = InstUnreachable::create(Cfg); | |
John
2016/03/28 18:44:10
auto *
Eric Holk
2016/03/29 19:54:10
Done.
| |
496 Control()->appendInst(Instr); | |
497 LOG(out << Node(nullptr) << "\n"); | |
498 return nullptr; | |
499 } | |
500 | |
501 Node CallDirect(uint32_t Index, Node *Args) { | |
502 LOG(out << "CallDirect(" << Index << ")" | |
503 << "\n"); | |
504 assert(module_->IsValidFunction(Index)); | |
505 const auto Module = module_->module; | |
506 assert(Module); | |
507 const auto &Target = Module->functions[Index]; | |
508 const auto Sig = Target.sig; | |
John
2016/03/28 18:44:07
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
509 assert(Sig); | |
510 const auto NumArgs = Sig->parameter_count(); | |
511 LOG(out << " number of args: " << NumArgs << "\n"); | |
512 | |
513 const auto TargetName = Module->GetName(Target.name_offset); | |
John
2016/03/28 18:44:07
std::string?
Eric Holk
2016/03/29 19:54:11
Done.
| |
514 LOG(out << " target name: " << TargetName << "\n"); | |
515 | |
516 assert(Sig->return_count() <= 1); | |
517 | |
518 auto TargetOperand = Ctx->getConstantSym(0, TargetName); | |
John
2016/03/28 18:44:09
auto *
| |
519 | |
520 auto Dest = Sig->return_count() > 0 | |
John
2016/03/28 18:44:08
auto *
| |
521 ? Cfg->makeVariable(toIceType(Sig->GetReturn())) | |
522 : nullptr; | |
523 auto Call = InstCall::create(Cfg, NumArgs, Dest, TargetOperand, | |
John
2016/03/28 18:44:08
auto *
Eric Holk
2016/03/29 19:54:12
Done.
| |
524 false /* HasTailCall */); | |
525 for (int i = 0; i < NumArgs; ++i) { | |
526 // The builder reserves the first argument for the code object. | |
527 LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n"); | |
528 Call->addArg(Args[i + 1]); | |
529 } | |
530 | |
531 Control()->appendInst(Call); | |
532 LOG(out << "Call Result = " << Node(Dest) << "\n"); | |
533 return Dest; | |
534 } | |
535 Node CallImport(uint32_t Index, Node *Args) { | |
536 LOG(out << "CallImport(" << Index << ")" | |
537 << "\n"); | |
538 // assert(module_->IsValidFunction(index)); | |
539 const auto Module = module_->module; | |
540 assert(Module); | |
541 const auto Sig = module_->GetImportSignature(Index); | |
John
2016/03/28 18:44:10
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
542 assert(Sig); | |
543 const auto NumArgs = Sig->parameter_count(); | |
544 LOG(out << " number of args: " << NumArgs << "\n"); | |
545 | |
546 const auto &Target = Module->import_table[Index]; | |
547 const auto TargetName = Module->GetName(Target.function_name_offset); | |
548 LOG(out << " target name: " << TargetName << "\n"); | |
549 | |
550 assert(Sig->return_count() <= 1); | |
551 | |
552 auto TargetOperand = Ctx->getConstantSym(0, TargetName); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:11
Done.
| |
553 | |
554 auto Dest = Sig->return_count() > 0 | |
John
2016/03/28 18:44:08
auto *
Eric Holk
2016/03/29 19:54:12
Done.
| |
555 ? Cfg->makeVariable(toIceType(Sig->GetReturn())) | |
556 : nullptr; | |
557 auto Call = InstCall::create(Cfg, NumArgs, Dest, TargetOperand, | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:10
Done.
| |
558 false /* HasTailCall */); | |
559 for (int i = 0; i < NumArgs; ++i) { | |
560 // The builder reserves the first argument for the code object. | |
561 LOG(out << " args[" << i << "] = " << Args[i + 1] << "\n"); | |
562 Call->addArg(Args[i + 1]); | |
563 } | |
564 | |
565 Control()->appendInst(Call); | |
566 LOG(out << "Call Result = " << Node(Dest) << "\n"); | |
567 return Dest; | |
568 } | |
569 Node CallIndirect(uint32_t Index, Node *Args) { | |
570 llvm_unreachable("CallIndirect"); | |
571 } | |
572 Node Invert(Node Node) { llvm_unreachable("Invert"); } | |
573 Node FunctionTable() { llvm_unreachable("FunctionTable"); } | |
574 | |
575 //----------------------------------------------------------------------- | |
576 // Operations that concern the linear memory. | |
577 //----------------------------------------------------------------------- | |
578 Node MemSize(uint32_t Offset) { llvm_unreachable("MemSize"); } | |
579 Node LoadGlobal(uint32_t Index) { llvm_unreachable("LoadGlobal"); } | |
580 Node StoreGlobal(uint32_t Index, Node Val) { | |
581 llvm_unreachable("StoreGlobal"); | |
582 } | |
583 Node LoadMem(wasm::LocalType Type, MachineType MemType, Node Index, | |
584 uint32_t Offset) { | |
585 LOG(out << "LoadMem(" << Index << "[" << Offset << "]) = "); | |
586 | |
587 // TODO(eholk): surely there is a better way to do this. | |
588 | |
589 // first, add the index and the offset together. | |
590 auto OffsetConstant = Ctx->getConstantInt32(Offset); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:10
Done.
| |
591 auto Addr = Cfg->makeVariable(IceType_i32); | |
John
2016/03/28 18:44:08
auto *
Eric Holk
2016/03/29 19:54:12
Done.
| |
592 Control()->appendInst(InstArithmetic::create(Cfg, InstArithmetic::Add, Addr, | |
593 Index, OffsetConstant)); | |
594 | |
595 // then load the memory | |
596 auto LoadResult = Cfg->makeVariable(toIceType(MemType)); | |
John
2016/03/28 18:44:10
auto *
Eric Holk
2016/03/29 19:54:09
Done.
| |
597 Control()->appendInst(InstLoad::create(Cfg, LoadResult, Addr)); | |
598 | |
599 // and cast, if needed | |
600 Ice::Variable *Result = nullptr; | |
601 if (toIceType(Type) != toIceType(MemType)) { | |
602 Result = Cfg->makeVariable(toIceType(Type)); | |
603 // TODO(eholk): handle signs correctly. | |
604 Control()->appendInst( | |
605 InstCast::create(Cfg, InstCast::Sext, Result, LoadResult)); | |
606 } else { | |
607 Result = LoadResult; | |
608 } | |
609 | |
610 LOG(out << Result << "\n"); | |
611 return Result; | |
612 } | |
613 void StoreMem(MachineType Type, Node Index, uint32_t Offset, Node Val) { | |
614 LOG(out << "StoreMem(" << Index << "[" << Offset << "] = " << Val << ")" | |
615 << "\n"); | |
616 | |
617 // TODO(eholk): surely there is a better way to do this. | |
618 | |
619 // first, add the index and the offset together. | |
620 auto OffsetConstant = Ctx->getConstantInt32(Offset); | |
John
2016/03/28 18:44:07
auto *
Eric Holk
2016/03/29 19:54:10
Done.
| |
621 auto Addr = Cfg->makeVariable(IceType_i32); | |
John
2016/03/28 18:44:10
auto *
Eric Holk
2016/03/29 19:54:09
Done.
| |
622 Control()->appendInst(InstArithmetic::create(Cfg, InstArithmetic::Add, Addr, | |
623 Index, OffsetConstant)); | |
624 | |
625 // cast the value to the right type, if needed | |
626 Operand *StoreVal = nullptr; | |
627 if (toIceType(Type) != ((Operand *)Val)->getType()) { | |
628 auto LocalStoreVal = Cfg->makeVariable(toIceType(Type)); | |
John
2016/03/28 18:44:09
auto *
Eric Holk
2016/03/29 19:54:10
Done.
| |
629 Control()->appendInst( | |
630 InstCast::create(Cfg, InstCast::Trunc, LocalStoreVal, Val)); | |
631 StoreVal = LocalStoreVal; | |
632 } else { | |
633 StoreVal = Val; | |
634 } | |
635 | |
636 // then store the memory | |
637 Control()->appendInst(InstStore::create(Cfg, StoreVal, Addr)); | |
638 } | |
639 | |
640 static void PrintDebugName(Node node) { llvm_unreachable("PrintDebugName"); } | |
641 | |
642 CfgNode *Control() { | |
643 return control_ ? (CfgNode *)*control_ : Cfg->getEntryNode(); | |
John
2016/03/28 18:44:08
static_cast<>
| |
644 } | |
645 Node Effect() { return *effect_; } | |
646 | |
647 void set_module(wasm::ModuleEnv *Module) { this->module_ = Module; } | |
John
2016/03/28 18:44:10
setModule
Eric Holk
2016/03/29 19:54:09
This name is set by V8, so I can't change it.
| |
648 | |
649 void set_control_ptr(Node *Control) { this->control_ = Control; } | |
John
2016/03/28 18:44:09
setControlPtr
Eric Holk
2016/03/29 19:54:11
This name is set by V8, so I can't change it.
| |
650 | |
651 void set_effect_ptr(Node *Effect) { this->effect_ = Effect; } | |
John
2016/03/28 18:44:08
setEffectPtr
Eric Holk
2016/03/29 19:54:10
This name is set by V8, so I can't change it.
| |
652 }; | |
653 | |
654 IceString fnNameFromId(uint32_t Id) { return IceString("fn") + to_string(Id); } | |
655 | |
656 std::unique_ptr<Cfg> WasmTranslator::translateFunction(Zone *Zone, | |
657 FunctionEnv *Env, | |
658 const byte *Base, | |
659 const byte *Start, | |
660 const byte *End) { | |
661 auto Cfg = Cfg::create(Ctx, getNextSequenceNumber()); | |
662 Ice::CfgLocalAllocatorScope _(Cfg.get()); | |
663 | |
664 // TODO: parse the function signature... | |
665 | |
666 IceBuilder Builder(Cfg.get()); | |
667 LR_WasmDecoder<OperandNode, IceBuilder> Decoder(Zone, &Builder); | |
668 | |
669 LOG(out << Ctx->getFlags().getDefaultGlobalPrefix() << "\n"); | |
670 Decoder.Decode(Env, Base, Start, End); | |
671 | |
672 // We don't always know where the incoming branches are in phi nodes, so this | |
673 // function finds them. | |
674 Cfg->fixPhiNodes(); | |
675 | |
676 return Cfg; | |
677 } | |
678 | |
679 constexpr auto BUFFER_SIZE = 24 << 10; // 24k, bigger than the test cases I have | |
680 // so far. | |
681 uint8_t Buffer[BUFFER_SIZE]; | |
JF
2016/03/28 18:17:13
Can you allocate this instead?
Eric Holk
2016/03/29 19:54:12
Done.
| |
682 | |
683 void WasmTranslator::translate( | |
684 const std::string &IRFilename, | |
685 std::unique_ptr<llvm::DataStreamer> &&InputStream) { | |
686 LOG(out << "Initializing v8/wasm stuff..." | |
687 << "\n"); | |
688 Zone Zone; | |
689 ZoneScope _(&Zone); | |
690 | |
691 auto BytesRead = InputStream->GetBytes(Buffer, sizeof(Buffer)); | |
John
2016/03/28 18:44:08
integral type? don't use auto?
Eric Holk
2016/03/29 19:54:10
Done.
| |
692 LOG(out << "Read " << BytesRead << " bytes" | |
693 << "\n"); | |
694 | |
695 LOG(out << "Decoding module " << IRFilename << "\n"); | |
696 | |
697 auto Result = | |
698 DecodeWasmModule(nullptr /* DecodeWasmModule ignores the Isolate | |
699 * parameter, so we just pass a null | |
700 * one rather than go through the | |
701 * hullabaloo of making one. */, &Zone, | |
702 Buffer, Buffer + BytesRead, false, kWasmOrigin); | |
703 | |
704 auto Module = Result.val; | |
705 | |
706 LOG(out << "Module info:" | |
707 << "\n"); | |
708 LOG(out << " number of globals: " << Module->globals.size() << "\n"); | |
709 LOG(out << " number of signatures: " << Module->signatures.size() | |
710 << "\n"); | |
711 LOG(out << " number of functions: " << Module->functions.size() << "\n"); | |
712 LOG(out << " number of data_segments: " << Module->data_segments.size() | |
713 << "\n"); | |
714 LOG(out << " function table size: " << Module->function_table.size() | |
715 << "\n"); | |
716 | |
717 ModuleEnv ModuleEnv; | |
718 ModuleEnv.module = Module; | |
719 | |
720 LOG(out << "\n" | |
721 << "Function information:" | |
722 << "\n"); | |
723 for (const auto F : Module->functions) { | |
724 LOG(out << " " << F.name_offset << ": " << Module->GetName(F.name_offset)); | |
725 if (F.exported) | |
726 LOG(out << " export"); | |
727 if (F.external) | |
728 LOG(out << " extern"); | |
729 LOG(out << "\n"); | |
730 } | |
731 | |
732 FunctionEnv Fenv; | |
733 Fenv.module = &ModuleEnv; | |
734 | |
735 LOG(out << "Translating " << IRFilename << "\n"); | |
736 | |
737 // Translate each function. | |
738 uint32_t Id = 0; | |
739 for (const auto Fn : Module->functions) { | |
740 auto NewName = fnNameFromId(Id++); | |
John
2016/03/28 18:44:07
std::string?
Eric Holk
2016/03/29 19:54:11
Done.
| |
741 LOG(out << " " << Fn.name_offset << ": " << Module->GetName(Fn.name_offset) | |
742 << " -> " << NewName << "..."); | |
743 | |
744 Fenv.sig = Fn.sig; | |
745 Fenv.local_i32_count = Fn.local_i32_count; | |
746 Fenv.local_i64_count = Fn.local_i64_count; | |
747 Fenv.local_f32_count = Fn.local_f32_count; | |
748 Fenv.local_f64_count = Fn.local_f64_count; | |
749 Fenv.SumLocals(); | |
750 | |
751 auto Cfg = | |
John
2016/03/28 18:44:07
auto *
Eric Holk
2016/03/29 19:54:09
translateFunction returns a std::unique_ptr, so au
| |
752 translateFunction(&Zone, &Fenv, Buffer, Buffer + Fn.code_start_offset, | |
753 Buffer + Fn.code_end_offset); | |
754 // auto FnName = module->GetName(Fn.name_offset); | |
755 Cfg->setFunctionName(NewName); | |
756 | |
757 Ctx->optQueueBlockingPush(std::move(Cfg)); | |
758 LOG(out << "done." | |
759 << "\n"); | |
760 } | |
761 | |
762 return; | |
763 } | |
OLD | NEW |