Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 the V8 project authors. All rights reserved. | 1 // Copyright 2015 the V8 project authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "src/compiler/wasm-compiler.h" | 5 #include "src/compiler/wasm-compiler.h" |
| 6 | 6 |
| 7 #include "src/isolate-inl.h" | 7 #include "src/isolate-inl.h" |
| 8 | 8 |
| 9 #include "src/base/platform/elapsed-timer.h" | 9 #include "src/base/platform/elapsed-timer.h" |
| 10 #include "src/base/platform/platform.h" | 10 #include "src/base/platform/platform.h" |
| (...skipping 2362 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2373 size_t limit = size - offset - memsize; | 2373 size_t limit = size - offset - memsize; |
| 2374 CHECK(limit <= kMaxUInt32); | 2374 CHECK(limit <= kMaxUInt32); |
| 2375 cond = graph()->NewNode( | 2375 cond = graph()->NewNode( |
| 2376 jsgraph()->machine()->Uint32LessThanOrEqual(), index, | 2376 jsgraph()->machine()->Uint32LessThanOrEqual(), index, |
| 2377 jsgraph()->Int32Constant(static_cast<uint32_t>(limit))); | 2377 jsgraph()->Int32Constant(static_cast<uint32_t>(limit))); |
| 2378 } | 2378 } |
| 2379 | 2379 |
| 2380 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond); | 2380 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond); |
| 2381 } | 2381 } |
| 2382 | 2382 |
| 2383 Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type, | |
| 2384 MachineType memtype, Node* index, | |
| 2385 uint32_t offset) { | |
| 2386 Node* result; | |
| 2387 Node* load; | |
| 2388 bool extendTo64Bit = false; | |
| 2389 | |
| 2390 wasm::WasmOpcode shiftOpcode; | |
| 2391 wasm::WasmOpcode orOpcode; | |
| 2392 Node* constEight; | |
| 2393 | |
| 2394 switch (type) { | |
| 2395 case wasm::kAstI64: | |
| 2396 case wasm::kAstF64: | |
| 2397 shiftOpcode = wasm::kExprI64Shl; | |
| 2398 orOpcode = wasm::kExprI64Ior; | |
| 2399 result = jsgraph()->Int64Constant(0); | |
| 2400 constEight = jsgraph()->Int64Constant(8); | |
| 2401 extendTo64Bit = true; | |
| 2402 break; | |
| 2403 case wasm::kAstI32: | |
| 2404 case wasm::kAstF32: | |
| 2405 shiftOpcode = wasm::kExprI32Shl; | |
| 2406 orOpcode = wasm::kExprI32Ior; | |
| 2407 result = jsgraph()->Int32Constant(0); | |
| 2408 constEight = jsgraph()->Int32Constant(8); | |
| 2409 break; | |
| 2410 default: | |
| 2411 UNREACHABLE(); | |
| 2412 } | |
| 2413 | |
| 2414 bool signExtend = memtype.IsSigned(); | |
| 2415 | |
| 2416 bool isFloat = IsFloatingPoint(memtype.representation()); | |
| 2417 int numberOfLoads = 1 << ElementSizeLog2Of(memtype.representation()); | |
| 2418 | |
| 2419 for (int i = 0; i < numberOfLoads; i++) { | |
|
titzer
2016/04/20 12:59:26
This is good enough for a first cut, since it does
| |
| 2420 result = Binop(shiftOpcode, result, constEight); | |
| 2421 load = graph()->NewNode( | |
| 2422 jsgraph()->machine()->Load(signExtend ? MachineType::Int8() | |
| 2423 : MachineType::Uint8()), | |
| 2424 MemBuffer(offset + numberOfLoads - 1 - i), index, *effect_, *control_); | |
| 2425 index->Print(); | |
| 2426 *effect_ = load; | |
| 2427 if (extendTo64Bit) { | |
| 2428 if (signExtend) { | |
| 2429 load = | |
| 2430 graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | |
| 2431 } else { | |
| 2432 load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), | |
| 2433 load); | |
| 2434 } | |
| 2435 } | |
| 2436 signExtend = false; | |
| 2437 result = Binop(orOpcode, result, load); | |
| 2438 } | |
| 2439 | |
| 2440 // Convert to float | |
| 2441 if (isFloat) { | |
| 2442 switch (type) { | |
| 2443 case wasm::kAstF32: | |
| 2444 result = Unop(wasm::kExprF32ReinterpretI32, result); | |
| 2445 break; | |
| 2446 case wasm::kAstF64: | |
| 2447 result = Unop(wasm::kExprF64ReinterpretI64, result); | |
| 2448 break; | |
| 2449 default: | |
| 2450 UNREACHABLE(); | |
| 2451 } | |
| 2452 } | |
| 2453 | |
| 2454 return result; | |
| 2455 } | |
| 2383 | 2456 |
| 2384 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, | 2457 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
| 2385 Node* index, uint32_t offset) { | 2458 Node* index, uint32_t offset, |
| 2459 uint32_t alignment) { | |
| 2386 Node* load; | 2460 Node* load; |
| 2461 bool skip = false; | |
| 2387 | 2462 |
| 2388 if (module_ && module_->asm_js()) { | 2463 if (module_ && module_->asm_js()) { |
| 2389 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). | 2464 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). |
| 2390 DCHECK_EQ(0, offset); | 2465 DCHECK_EQ(0, offset); |
| 2391 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype); | 2466 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype); |
| 2392 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, | 2467 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, |
| 2393 *control_); | 2468 *control_); |
| 2394 } else { | 2469 } else { |
| 2395 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2470 // WASM semantics throw on OOB. Introduce explicit bounds check. |
| 2396 BoundsCheckMem(memtype, index, offset); | 2471 BoundsCheckMem(memtype, index, offset); |
| 2397 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), | 2472 // load = |
| 2398 MemBuffer(offset), index, *effect_, *control_); | 2473 // graph()->NewNode(jsgraph()->machine()->UnalignedLoad(memtype).op(), |
| 2474 // MemBuffer(offset), index, *effect_, *control_); | |
| 2475 bool aligned = alignment >= ElementSizeLog2Of(memtype.representation()); | |
|
titzer
2016/04/20 12:59:26
It's probably best to have a machine()->UnalignedL
| |
| 2476 if (aligned || | |
| 2477 !jsgraph()->machine()->UnalignedLoad(memtype).IsSupported()) { | |
| 2478 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), | |
| 2479 MemBuffer(offset), index, *effect_, *control_); | |
| 2480 } else { | |
| 2481 load = BuildUnalignedLoad(type, memtype, index, offset); | |
| 2482 skip = true; | |
| 2483 } | |
| 2399 } | 2484 } |
| 2400 | 2485 |
| 2401 *effect_ = load; | 2486 if (!skip) { |
| 2487 *effect_ = load; | |
| 2488 } | |
| 2402 | 2489 |
| 2403 if (type == wasm::kAstI64 && | 2490 if (type == wasm::kAstI64 && |
| 2404 ElementSizeLog2Of(memtype.representation()) < 3) { | 2491 ElementSizeLog2Of(memtype.representation()) < 3) { |
| 2405 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. | 2492 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. |
| 2406 if (memtype.IsSigned()) { | 2493 if (memtype.IsSigned()) { |
| 2407 // sign extend | 2494 // sign extend |
| 2408 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | 2495 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); |
| 2409 } else { | 2496 } else { |
| 2410 // zero extend | 2497 // zero extend |
| 2411 load = | 2498 load = |
| 2412 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); | 2499 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); |
| 2413 } | 2500 } |
| 2414 } | 2501 } |
| 2415 | 2502 |
| 2416 return load; | 2503 return load; |
| 2417 } | 2504 } |
| 2418 | 2505 |
| 2506 Node* WasmGraphBuilder::BuildUnalignedStore(MachineType memtype, Node* index, | |
| 2507 uint32_t offset, uint32_t alignment, | |
| 2508 Node* val) { | |
| 2509 Node* store; | |
| 2510 Node* newValue; | |
| 2511 | |
| 2512 wasm::WasmOpcode shiftOpcode; | |
| 2513 | |
| 2514 Node* constEight; | |
| 2515 Node* mask; | |
| 2516 bool extendTo64Bit = false; | |
| 2517 | |
| 2518 if (ElementSizeLog2Of(memtype.representation()) <= 2) { | |
| 2519 shiftOpcode = wasm::kExprI32ShrU; | |
| 2520 constEight = jsgraph()->Int32Constant(8); | |
| 2521 mask = jsgraph()->Int32Constant(0x000000ff); | |
| 2522 } else { | |
| 2523 shiftOpcode = wasm::kExprI64ShrU; | |
| 2524 constEight = jsgraph()->Int64Constant(8); | |
| 2525 mask = jsgraph()->Int64Constant(0x00000000000000ff); | |
| 2526 extendTo64Bit = true; | |
| 2527 } | |
| 2528 | |
| 2529 bool isFloat = IsFloatingPoint(memtype.representation()); | |
| 2530 int numberOfLoads = 1 << ElementSizeLog2Of(memtype.representation()); | |
| 2531 | |
| 2532 StoreRepresentation rep(MachineType::Uint8().representation(), | |
| 2533 kNoWriteBarrier); | |
| 2534 | |
| 2535 newValue = val; | |
| 2536 if (isFloat) { | |
| 2537 switch (memtype.representation()) { | |
| 2538 case MachineRepresentation::kFloat64: | |
| 2539 newValue = Unop(wasm::kExprI64ReinterpretF64, val); | |
| 2540 break; | |
| 2541 case MachineRepresentation::kFloat32: | |
| 2542 newValue = Unop(wasm::kExprI32ReinterpretF32, val); | |
| 2543 break; | |
| 2544 default: | |
| 2545 UNREACHABLE(); | |
| 2546 } | |
| 2547 } | |
| 2548 | |
| 2549 DCHECK(numberOfLoads >= 2); | |
| 2550 for (int i = 0; i < numberOfLoads - 1; i++) { | |
| 2551 store = graph()->NewNode( | |
| 2552 jsgraph()->machine()->Store(rep), MemBuffer(offset + i), index, | |
| 2553 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, | |
| 2554 *effect_, *control_); | |
| 2555 newValue = Binop(shiftOpcode, newValue, constEight); | |
| 2556 *effect_ = store; | |
| 2557 } | |
| 2558 store = graph()->NewNode( | |
| 2559 jsgraph()->machine()->Store(rep), MemBuffer(offset + numberOfLoads - 1), | |
| 2560 index, | |
| 2561 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, | |
| 2562 *effect_, *control_); | |
| 2563 *effect_ = store; | |
| 2564 return val; | |
| 2565 } | |
| 2419 | 2566 |
| 2420 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, | 2567 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, |
| 2421 uint32_t offset, Node* val) { | 2568 uint32_t offset, uint32_t alignment, |
| 2569 Node* val) { | |
| 2422 Node* store; | 2570 Node* store; |
| 2571 bool skip = false; | |
| 2423 if (module_ && module_->asm_js()) { | 2572 if (module_ && module_->asm_js()) { |
| 2424 // asm.js semantics use CheckedStore (i.e. ignore OOB writes). | 2573 // asm.js semantics use CheckedStore (i.e. ignore OOB writes). |
| 2425 DCHECK_EQ(0, offset); | 2574 DCHECK_EQ(0, offset); |
| 2426 const Operator* op = | 2575 const Operator* op = |
| 2427 jsgraph()->machine()->CheckedStore(memtype.representation()); | 2576 jsgraph()->machine()->CheckedStore(memtype.representation()); |
| 2428 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_, | 2577 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_, |
| 2429 *control_); | 2578 *control_); |
| 2430 } else { | 2579 } else { |
| 2431 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2580 // WASM semantics throw on OOB. Introduce explicit bounds check. |
| 2432 BoundsCheckMem(memtype, index, offset); | 2581 BoundsCheckMem(memtype, index, offset); |
| 2433 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | 2582 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
| 2434 store = | 2583 bool aligned = alignment >= ElementSizeLog2Of(memtype.representation()); |
| 2435 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), | 2584 |
| 2436 index, val, *effect_, *control_); | 2585 if (aligned || |
| 2586 !jsgraph() | |
| 2587 ->machine() | |
| 2588 ->UnalignedStore(memtype.representation()) | |
| 2589 .IsSupported()) { | |
| 2590 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | |
| 2591 store = | |
| 2592 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), | |
| 2593 index, val, *effect_, *control_); | |
| 2594 } else { | |
| 2595 store = BuildUnalignedStore(memtype, index, offset, alignment, val); | |
| 2596 skip = true; | |
| 2597 } | |
| 2437 } | 2598 } |
| 2438 *effect_ = store; | 2599 if (!skip) { |
| 2600 *effect_ = store; | |
| 2601 } | |
| 2602 | |
| 2439 return store; | 2603 return store; |
| 2440 } | 2604 } |
| 2441 | 2605 |
| 2442 | 2606 |
| 2443 void WasmGraphBuilder::PrintDebugName(Node* node) { | 2607 void WasmGraphBuilder::PrintDebugName(Node* node) { |
| 2444 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); | 2608 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); |
| 2445 } | 2609 } |
| 2446 | 2610 |
| 2447 | 2611 |
| 2448 Node* WasmGraphBuilder::String(const char* string) { | 2612 Node* WasmGraphBuilder::String(const char* string) { |
| (...skipping 331 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 2780 static_cast<int>(function.code_end_offset - function.code_start_offset), | 2944 static_cast<int>(function.code_end_offset - function.code_start_offset), |
| 2781 decode_ms, static_cast<int>(graph.NodeCount()), compile_ms); | 2945 decode_ms, static_cast<int>(graph.NodeCount()), compile_ms); |
| 2782 } | 2946 } |
| 2783 return code; | 2947 return code; |
| 2784 } | 2948 } |
| 2785 | 2949 |
| 2786 | 2950 |
| 2787 } // namespace compiler | 2951 } // namespace compiler |
| 2788 } // namespace internal | 2952 } // namespace internal |
| 2789 } // namespace v8 | 2953 } // namespace v8 |
| OLD | NEW |