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

Side by Side Diff: src/compiler/wasm-compiler.cc

Issue 1928513002: Implement UnalignedLoad and UnalignedStore in WASM using LoadByte/Shift/Or and StoreByte/Shift/And. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: Renamed UnalignedAccessConfig to AlignmentRequirements Created 4 years, 7 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 // 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 2573 matching lines...) Expand 10 before | Expand all | Expand 10 after
2584 size_t limit = size - offset - memsize; 2584 size_t limit = size - offset - memsize;
2585 CHECK(limit <= kMaxUInt32); 2585 CHECK(limit <= kMaxUInt32);
2586 cond = graph()->NewNode( 2586 cond = graph()->NewNode(
2587 jsgraph()->machine()->Uint32LessThanOrEqual(), index, 2587 jsgraph()->machine()->Uint32LessThanOrEqual(), index,
2588 jsgraph()->Int32Constant(static_cast<uint32_t>(limit))); 2588 jsgraph()->Int32Constant(static_cast<uint32_t>(limit)));
2589 } 2589 }
2590 2590
2591 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); 2591 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position);
2592 } 2592 }
2593 2593
2594 Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type,
2595 MachineType memtype, Node* index,
2596 uint32_t offset,
2597 uint32_t alignment) {
2598 Node* result;
2599 Node* load;
2600 bool extendTo64Bit = false;
2601
2602 wasm::WasmOpcode shiftOpcode;
2603 wasm::WasmOpcode orOpcode;
2604 Node* shiftConst;
2605
2606 auto determineType = [](bool signExtend, uint32_t alignment) -> MachineType {
titzer 2016/05/11 15:22:35 Can we lift this out to a helper method instead of
2607 switch (alignment) {
2608 case 0:
2609 return signExtend ? MachineType::Int8() : MachineType::Uint8();
2610 case 1:
2611 return signExtend ? MachineType::Int16() : MachineType::Uint16();
2612 case 2:
2613 return signExtend ? MachineType::Int32() : MachineType::Uint32();
2614 default:
2615 UNREACHABLE();
2616 }
2617 };
2618
2619 auto calculateOffset = [this](Node* baseOffset, int numberOfBytes, int stride,
2620 int current) -> Node* {
2621 int offset;
2622
2623 #if defined(V8_TARGET_LITTLE_ENDIAN)
2624 offset = numberOfBytes - stride - current;
2625 #elif defined(V8_TARGET_BIG_ENDIAN)
2626 offset = current;
2627 #else
2628 #error Unsupported endianness
2629 #endif
2630
2631 if (offset == 0) {
2632 return baseOffset;
2633 } else {
2634 return Binop(wasm::kExprI32Add, baseOffset,
2635 jsgraph()->Int32Constant(offset));
2636 }
2637 };
2638
2639 bool signExtend = memtype.IsSigned();
2640
2641 bool isFloat = IsFloatingPoint(memtype.representation());
2642 int stride =
2643 1 << ElementSizeLog2Of(determineType(false, alignment).representation());
2644 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation());
2645 int numberOfLoads = numberOfBytes / stride;
2646
2647 DCHECK(numberOfBytes % stride == 0);
2648 DCHECK(numberOfLoads >= 2);
2649
2650 switch (type) {
2651 case wasm::kAstI64:
2652 case wasm::kAstF64:
2653 shiftOpcode = wasm::kExprI64Shl;
2654 orOpcode = wasm::kExprI64Ior;
2655 result = jsgraph()->Int64Constant(0);
2656 shiftConst = jsgraph()->Int64Constant(8 * stride);
2657 extendTo64Bit = true;
2658 break;
2659 case wasm::kAstI32:
2660 case wasm::kAstF32:
2661 shiftOpcode = wasm::kExprI32Shl;
2662 orOpcode = wasm::kExprI32Ior;
2663 result = jsgraph()->Int32Constant(0);
2664 shiftConst = jsgraph()->Int32Constant(8 * stride);
2665 break;
2666 default:
2667 UNREACHABLE();
2668 }
2669
2670 Node* baseOffset = MemBuffer(offset);
2671
2672 for (int i = 0; i < numberOfBytes; i += stride) {
2673 result = Binop(shiftOpcode, result, shiftConst);
2674 load = graph()->NewNode(
2675 jsgraph()->machine()->Load(determineType(signExtend, alignment)),
2676 calculateOffset(baseOffset, numberOfBytes, stride, i), index, *effect_,
2677 *control_);
2678 *effect_ = load;
2679 if (extendTo64Bit) {
2680 if (signExtend) {
2681 load =
2682 graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
2683 } else {
2684 load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(),
2685 load);
2686 }
2687 }
2688 signExtend = false;
2689 result = Binop(orOpcode, result, load);
2690 }
2691
2692 // Convert to float
2693 if (isFloat) {
2694 switch (type) {
2695 case wasm::kAstF32:
2696 result = Unop(wasm::kExprF32ReinterpretI32, result);
2697 break;
2698 case wasm::kAstF64:
2699 result = Unop(wasm::kExprF64ReinterpretI64, result);
2700 break;
2701 default:
2702 UNREACHABLE();
2703 }
2704 }
2705
2706 return result;
2707 }
2708
2594 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, 2709 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype,
2595 Node* index, uint32_t offset, 2710 Node* index, uint32_t offset,
2711 uint32_t alignment,
2596 wasm::WasmCodePosition position) { 2712 wasm::WasmCodePosition position) {
2597 Node* load; 2713 Node* load;
2714 bool skip = false;
2598 2715
2599 if (module_ && module_->asm_js()) { 2716 if (module_ && module_->asm_js()) {
2600 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). 2717 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish).
2601 DCHECK_EQ(0, offset); 2718 DCHECK_EQ(0, offset);
2602 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype); 2719 const Operator* op = jsgraph()->machine()->CheckedLoad(memtype);
2603 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, 2720 load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_,
2604 *control_); 2721 *control_);
2605 } else { 2722 } else {
2606 // WASM semantics throw on OOB. Introduce explicit bounds check. 2723 // WASM semantics throw on OOB. Introduce explicit bounds check.
2607 BoundsCheckMem(memtype, index, offset, position); 2724 BoundsCheckMem(memtype, index, offset, position);
2608 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), 2725 bool aligned = alignment >= ElementSizeLog2Of(memtype.representation());
2609 MemBuffer(offset), index, *effect_, *control_); 2726
2727 if (aligned ||
2728 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) {
2729 load = graph()->NewNode(jsgraph()->machine()->Load(memtype),
2730 MemBuffer(offset), index, *effect_, *control_);
2731 } else {
2732 load = BuildUnalignedLoad(type, memtype, index, offset, alignment);
2733 skip = true;
2734 }
2610 } 2735 }
2611 2736
2612 *effect_ = load; 2737 if (!skip) {
titzer 2016/05/11 15:22:35 Can you lift this up into the branch instead of us
2738 *effect_ = load;
2739 }
2613 2740
2614 if (type == wasm::kAstI64 && 2741 if (type == wasm::kAstI64 &&
2615 ElementSizeLog2Of(memtype.representation()) < 3) { 2742 ElementSizeLog2Of(memtype.representation()) < 3) {
2616 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. 2743 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes.
2617 if (memtype.IsSigned()) { 2744 if (memtype.IsSigned()) {
2618 // sign extend 2745 // sign extend
2619 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); 2746 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load);
2620 } else { 2747 } else {
2621 // zero extend 2748 // zero extend
2622 load = 2749 load =
2623 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); 2750 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load);
2624 } 2751 }
2625 } 2752 }
2626 2753
2627 return load; 2754 return load;
2628 } 2755 }
2629 2756
2757 Node* WasmGraphBuilder::BuildUnalignedStore(MachineType memtype, Node* index,
2758 uint32_t offset, uint32_t alignment,
2759 Node* val) {
2760 Node* store;
2761 Node* newValue;
2762
2763 wasm::WasmOpcode shiftOpcode;
2764
2765 Node* shiftConst;
2766 bool extendTo64Bit = false;
2767
2768 auto determineType = [](uint32_t alignment) -> MachineType {
2769 switch (alignment) {
2770 case 0:
2771 return MachineType::Uint8();
2772 case 1:
2773 return MachineType::Uint16();
2774 case 2:
2775 return MachineType::Uint32();
2776 default:
2777 UNREACHABLE();
2778 }
2779 };
2780
2781 auto calculateOffset = [this](Node* baseOffset, int numberOfBytes, int stride,
2782 int current) -> Node* {
2783 int offset;
2784 #if defined(V8_TARGET_LITTLE_ENDIAN)
2785 offset = current;
2786 #elif defined(V8_TARGET_BIG_ENDIAN)
2787 offset = numberOfBytes - stride - current;
2788 #else
2789 #error Unsupported endianness
2790 #endif
2791 if (offset == 0) {
2792 return baseOffset;
2793 } else {
2794 return Binop(wasm::kExprI32Add, baseOffset,
2795 jsgraph()->Int32Constant(offset));
2796 }
2797 };
2798
2799 bool isFloat = IsFloatingPoint(memtype.representation());
2800 int stride =
2801 1 << ElementSizeLog2Of(determineType(alignment).representation());
2802 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation());
2803 int numberOfLoads = numberOfBytes / stride;
2804
2805 DCHECK(numberOfBytes % stride == 0);
2806 DCHECK(numberOfLoads >= 2);
2807
2808 StoreRepresentation rep(determineType(alignment).representation(),
2809 kNoWriteBarrier);
2810
2811 if (ElementSizeLog2Of(memtype.representation()) <= 2) {
2812 shiftOpcode = wasm::kExprI32ShrU;
2813 shiftConst = jsgraph()->Int32Constant(8 * stride);
2814 } else {
2815 shiftOpcode = wasm::kExprI64ShrU;
2816 shiftConst = jsgraph()->Int64Constant(8 * stride);
2817 extendTo64Bit = true;
2818 }
2819
2820 newValue = val;
2821 if (isFloat) {
2822 switch (memtype.representation()) {
2823 case MachineRepresentation::kFloat64:
2824 newValue = Unop(wasm::kExprI64ReinterpretF64, val);
2825 break;
2826 case MachineRepresentation::kFloat32:
2827 newValue = Unop(wasm::kExprI32ReinterpretF32, val);
2828 break;
2829 default:
2830 UNREACHABLE();
2831 }
2832 }
2833
2834 Node* baseOffset = MemBuffer(offset);
2835
2836 for (int i = 0; i < numberOfBytes - stride; i += stride) {
2837 store = graph()->NewNode(
2838 jsgraph()->machine()->Store(rep),
2839 calculateOffset(baseOffset, numberOfBytes, stride, i), index,
2840 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue,
2841 *effect_, *control_);
2842 newValue = Binop(shiftOpcode, newValue, shiftConst);
2843 *effect_ = store;
2844 }
2845 store = graph()->NewNode(
2846 jsgraph()->machine()->Store(rep),
2847 calculateOffset(baseOffset, numberOfBytes, stride,
2848 numberOfBytes - stride),
2849 index,
2850 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue,
2851 *effect_, *control_);
2852 *effect_ = store;
2853 return val;
2854 }
2855
2630 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, 2856 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index,
2631 uint32_t offset, Node* val, 2857 uint32_t offset, uint32_t alignment, Node* val,
2632 wasm::WasmCodePosition position) { 2858 wasm::WasmCodePosition position) {
2633 Node* store; 2859 Node* store;
2860 bool skip = false;
2634 if (module_ && module_->asm_js()) { 2861 if (module_ && module_->asm_js()) {
2635 // asm.js semantics use CheckedStore (i.e. ignore OOB writes). 2862 // asm.js semantics use CheckedStore (i.e. ignore OOB writes).
2636 DCHECK_EQ(0, offset); 2863 DCHECK_EQ(0, offset);
2637 const Operator* op = 2864 const Operator* op =
2638 jsgraph()->machine()->CheckedStore(memtype.representation()); 2865 jsgraph()->machine()->CheckedStore(memtype.representation());
2639 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_, 2866 store = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), val, *effect_,
2640 *control_); 2867 *control_);
2641 } else { 2868 } else {
2642 // WASM semantics throw on OOB. Introduce explicit bounds check. 2869 // WASM semantics throw on OOB. Introduce explicit bounds check.
2643 BoundsCheckMem(memtype, index, offset, position); 2870 BoundsCheckMem(memtype, index, offset, position);
2644 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); 2871 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
2645 store = 2872 bool aligned = alignment >= ElementSizeLog2Of(memtype.representation());
2646 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), 2873
2647 index, val, *effect_, *control_); 2874 if (aligned ||
2875 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) {
2876 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier);
2877 store =
2878 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset),
2879 index, val, *effect_, *control_);
2880 } else {
2881 store = BuildUnalignedStore(memtype, index, offset, alignment, val);
2882 skip = true;
2883 }
2648 } 2884 }
2649 *effect_ = store; 2885
2886 if (!skip) {
2887 *effect_ = store;
2888 }
2889
2650 return store; 2890 return store;
2651 } 2891 }
2652 2892
2653 2893
2654 void WasmGraphBuilder::PrintDebugName(Node* node) { 2894 void WasmGraphBuilder::PrintDebugName(Node* node) {
2655 PrintF("#%d:%s", node->id(), node->op()->mnemonic()); 2895 PrintF("#%d:%s", node->id(), node->op()->mnemonic());
2656 } 2896 }
2657 2897
2658 2898
2659 Node* WasmGraphBuilder::String(const char* string) { 2899 Node* WasmGraphBuilder::String(const char* string) {
(...skipping 210 matching lines...) Expand 10 before | Expand all | Expand 10 after
2870 double* decode_ms) { 3110 double* decode_ms) {
2871 base::ElapsedTimer decode_timer; 3111 base::ElapsedTimer decode_timer;
2872 if (FLAG_trace_wasm_decode_time) { 3112 if (FLAG_trace_wasm_decode_time) {
2873 decode_timer.Start(); 3113 decode_timer.Start();
2874 } 3114 }
2875 // Create a TF graph during decoding. 3115 // Create a TF graph during decoding.
2876 Graph* graph = new (zone) Graph(zone); 3116 Graph* graph = new (zone) Graph(zone);
2877 CommonOperatorBuilder* common = new (zone) CommonOperatorBuilder(zone); 3117 CommonOperatorBuilder* common = new (zone) CommonOperatorBuilder(zone);
2878 MachineOperatorBuilder* machine = new (zone) MachineOperatorBuilder( 3118 MachineOperatorBuilder* machine = new (zone) MachineOperatorBuilder(
2879 zone, MachineType::PointerRepresentation(), 3119 zone, MachineType::PointerRepresentation(),
2880 InstructionSelector::SupportedMachineOperatorFlags()); 3120 InstructionSelector::SupportedMachineOperatorFlags(),
3121 InstructionSelector::AlignmentConfiguration());
2881 JSGraph* jsgraph = 3122 JSGraph* jsgraph =
2882 new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine); 3123 new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine);
2883 SourcePositionTable* source_position_table = 3124 SourcePositionTable* source_position_table =
2884 new (zone) SourcePositionTable(graph); 3125 new (zone) SourcePositionTable(graph);
2885 WasmGraphBuilder builder(zone, jsgraph, function->sig, source_position_table); 3126 WasmGraphBuilder builder(zone, jsgraph, function->sig, source_position_table);
2886 wasm::FunctionBody body = { 3127 wasm::FunctionBody body = {
2887 module_env, function->sig, module_env->module->module_start, 3128 module_env, function->sig, module_env->module->module_start,
2888 module_env->module->module_start + function->code_start_offset, 3129 module_env->module->module_start + function->code_start_offset,
2889 module_env->module->module_start + function->code_end_offset}; 3130 module_env->module->module_start + function->code_end_offset};
2890 wasm::TreeResult result = 3131 wasm::TreeResult result =
(...skipping 186 matching lines...) Expand 10 before | Expand all | Expand 10 after
3077 const wasm::WasmFunction* function) { 3318 const wasm::WasmFunction* function) {
3078 WasmCompilationUnit* unit = 3319 WasmCompilationUnit* unit =
3079 CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0); 3320 CreateWasmCompilationUnit(thrower, isolate, module_env, function, 0);
3080 ExecuteCompilation(unit); 3321 ExecuteCompilation(unit);
3081 return FinishCompilation(unit); 3322 return FinishCompilation(unit);
3082 } 3323 }
3083 3324
3084 } // namespace compiler 3325 } // namespace compiler
3085 } // namespace internal 3326 } // namespace internal
3086 } // namespace v8 3327 } // namespace v8
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698