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 |