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 2929 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2940 } | 2940 } |
2941 } | 2941 } |
2942 | 2942 |
2943 Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index, | 2943 Node* cond = graph()->NewNode(jsgraph()->machine()->Uint32LessThan(), index, |
2944 jsgraph()->RelocatableInt32Constant( | 2944 jsgraph()->RelocatableInt32Constant( |
2945 static_cast<uint32_t>(effective_size), | 2945 static_cast<uint32_t>(effective_size), |
2946 RelocInfo::WASM_MEMORY_SIZE_REFERENCE)); | 2946 RelocInfo::WASM_MEMORY_SIZE_REFERENCE)); |
2947 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); | 2947 trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); |
2948 } | 2948 } |
2949 | 2949 |
2950 MachineType WasmGraphBuilder::GetTypeForUnalignedAccess(uint32_t alignment, | |
2951 bool signExtend) { | |
2952 switch (alignment) { | |
2953 case 0: | |
2954 return signExtend ? MachineType::Int8() : MachineType::Uint8(); | |
2955 case 1: | |
2956 return signExtend ? MachineType::Int16() : MachineType::Uint16(); | |
2957 case 2: | |
2958 return signExtend ? MachineType::Int32() : MachineType::Uint32(); | |
2959 default: | |
2960 UNREACHABLE(); | |
2961 return MachineType::None(); | |
2962 } | |
2963 } | |
2964 | |
2965 Node* WasmGraphBuilder::GetUnalignedLoadOffsetNode(Node* baseOffset, | |
2966 int numberOfBytes, | |
2967 int stride, int current) { | |
2968 int offset; | |
2969 wasm::WasmOpcode addOpcode; | |
2970 | |
2971 #if defined(V8_TARGET_LITTLE_ENDIAN) | |
2972 offset = numberOfBytes - stride - current; | |
2973 #elif defined(V8_TARGET_BIG_ENDIAN) | |
2974 offset = current; | |
2975 #else | |
2976 #error Unsupported endianness | |
2977 #endif | |
2978 | |
2979 #if WASM_64 | |
2980 addOpcode = wasm::kExprI64Add; | |
2981 #else | |
2982 addOpcode = wasm::kExprI32Add; | |
2983 #endif | |
2984 | |
2985 if (offset == 0) { | |
2986 return baseOffset; | |
2987 } else { | |
2988 return Binop(addOpcode, baseOffset, jsgraph()->Int32Constant(offset)); | |
2989 } | |
2990 } | |
2991 | |
2992 Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type, | |
2993 MachineType memtype, Node* index, | |
2994 uint32_t offset, | |
2995 uint32_t alignment) { | |
2996 Node* result; | |
2997 Node* load; | |
2998 bool extendTo64Bit = false; | |
2999 | |
3000 wasm::WasmOpcode shiftOpcode; | |
3001 wasm::WasmOpcode orOpcode; | |
3002 Node* shiftConst; | |
3003 | |
3004 bool signExtend = memtype.IsSigned(); | |
3005 | |
3006 bool isFloat = IsFloatingPoint(memtype.representation()); | |
3007 int stride = | |
3008 1 << ElementSizeLog2Of( | |
3009 GetTypeForUnalignedAccess(alignment, false).representation()); | |
3010 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); | |
3011 DCHECK(numberOfBytes % stride == 0); | |
3012 | |
3013 switch (type) { | |
3014 case wasm::kAstI64: | |
3015 case wasm::kAstF64: | |
3016 shiftOpcode = wasm::kExprI64Shl; | |
3017 orOpcode = wasm::kExprI64Ior; | |
3018 result = jsgraph()->Int64Constant(0); | |
3019 shiftConst = jsgraph()->Int64Constant(8 * stride); | |
3020 extendTo64Bit = true; | |
3021 break; | |
3022 case wasm::kAstI32: | |
3023 case wasm::kAstF32: | |
3024 shiftOpcode = wasm::kExprI32Shl; | |
3025 orOpcode = wasm::kExprI32Ior; | |
3026 result = jsgraph()->Int32Constant(0); | |
3027 shiftConst = jsgraph()->Int32Constant(8 * stride); | |
3028 break; | |
3029 default: | |
3030 UNREACHABLE(); | |
3031 } | |
3032 | |
3033 Node* baseOffset = MemBuffer(offset); | |
3034 | |
3035 for (int i = 0; i < numberOfBytes; i += stride) { | |
3036 result = Binop(shiftOpcode, result, shiftConst); | |
3037 load = graph()->NewNode( | |
3038 jsgraph()->machine()->Load( | |
3039 GetTypeForUnalignedAccess(alignment, signExtend)), | |
3040 GetUnalignedLoadOffsetNode(baseOffset, numberOfBytes, stride, i), index, | |
3041 *effect_, *control_); | |
3042 *effect_ = load; | |
3043 if (extendTo64Bit) { | |
3044 if (signExtend) { | |
3045 load = | |
3046 graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | |
3047 } else { | |
3048 load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), | |
3049 load); | |
3050 } | |
3051 } | |
3052 signExtend = false; | |
3053 result = Binop(orOpcode, result, load); | |
3054 } | |
3055 | |
3056 // Convert to float | |
3057 if (isFloat) { | |
3058 switch (type) { | |
3059 case wasm::kAstF32: | |
3060 result = Unop(wasm::kExprF32ReinterpretI32, result); | |
3061 break; | |
3062 case wasm::kAstF64: | |
3063 result = Unop(wasm::kExprF64ReinterpretI64, result); | |
3064 break; | |
3065 default: | |
3066 UNREACHABLE(); | |
3067 } | |
3068 } | |
3069 | |
3070 return result; | |
3071 } | |
3072 | 2950 |
3073 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, | 2951 Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
3074 Node* index, uint32_t offset, | 2952 Node* index, uint32_t offset, |
3075 uint32_t alignment, | 2953 uint32_t alignment, |
3076 wasm::WasmCodePosition position) { | 2954 wasm::WasmCodePosition position) { |
3077 Node* load; | 2955 Node* load; |
3078 | 2956 |
3079 // WASM semantics throw on OOB. Introduce explicit bounds check. | 2957 // WASM semantics throw on OOB. Introduce explicit bounds check. |
3080 BoundsCheckMem(memtype, index, offset, position); | 2958 BoundsCheckMem(memtype, index, offset, position); |
3081 bool aligned = static_cast<int>(alignment) >= | 2959 bool aligned = static_cast<int>(alignment) >= |
3082 ElementSizeLog2Of(memtype.representation()); | 2960 ElementSizeLog2Of(memtype.representation()); |
3083 | 2961 |
3084 if (aligned || | 2962 if (aligned || |
3085 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) { | 2963 jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) { |
3086 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), | 2964 load = graph()->NewNode(jsgraph()->machine()->Load(memtype), |
3087 MemBuffer(offset), index, *effect_, *control_); | 2965 MemBuffer(offset), index, *effect_, *control_); |
3088 *effect_ = load; | |
3089 } else { | 2966 } else { |
3090 load = BuildUnalignedLoad(type, memtype, index, offset, alignment); | 2967 load = graph()->NewNode(jsgraph()->machine()->UnalignedLoad(memtype), |
| 2968 MemBuffer(offset), index, *effect_, *control_); |
3091 } | 2969 } |
| 2970 |
| 2971 *effect_ = load; |
| 2972 |
3092 #if defined(V8_TARGET_BIG_ENDIAN) | 2973 #if defined(V8_TARGET_BIG_ENDIAN) |
3093 // TODO(john.yan) Implement byte swap turbofan operator | 2974 // TODO(john.yan) Implement byte swap turbofan operator |
3094 // and use it if available for better performance | 2975 // and use it if available for better performance |
3095 load = BuildChangeEndianness(load, memtype, type); | 2976 load = BuildChangeEndianness(load, memtype, type); |
3096 #endif | 2977 #endif |
3097 | 2978 |
3098 if (type == wasm::kAstI64 && | 2979 if (type == wasm::kAstI64 && |
3099 ElementSizeLog2Of(memtype.representation()) < 3) { | 2980 ElementSizeLog2Of(memtype.representation()) < 3) { |
3100 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. | 2981 // TODO(titzer): TF zeroes the upper bits of 64-bit loads for subword sizes. |
3101 if (memtype.IsSigned()) { | 2982 if (memtype.IsSigned()) { |
3102 // sign extend | 2983 // sign extend |
3103 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); | 2984 load = graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); |
3104 } else { | 2985 } else { |
3105 // zero extend | 2986 // zero extend |
3106 load = | 2987 load = |
3107 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); | 2988 graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), load); |
3108 } | 2989 } |
3109 } | 2990 } |
3110 | 2991 |
3111 return load; | 2992 return load; |
3112 } | 2993 } |
3113 | 2994 |
3114 Node* WasmGraphBuilder::GetUnalignedStoreOffsetNode(Node* baseOffset, | |
3115 int numberOfBytes, | |
3116 int stride, int current) { | |
3117 int offset; | |
3118 wasm::WasmOpcode addOpcode; | |
3119 | |
3120 #if defined(V8_TARGET_LITTLE_ENDIAN) | |
3121 offset = current; | |
3122 #elif defined(V8_TARGET_BIG_ENDIAN) | |
3123 offset = numberOfBytes - stride - current; | |
3124 #else | |
3125 #error Unsupported endianness | |
3126 #endif | |
3127 | |
3128 #if WASM_64 | |
3129 addOpcode = wasm::kExprI64Add; | |
3130 #else | |
3131 addOpcode = wasm::kExprI32Add; | |
3132 #endif | |
3133 | |
3134 if (offset == 0) { | |
3135 return baseOffset; | |
3136 } else { | |
3137 return Binop(addOpcode, baseOffset, jsgraph()->Int32Constant(offset)); | |
3138 } | |
3139 } | |
3140 | |
3141 Node* WasmGraphBuilder::BuildUnalignedStore(MachineType memtype, Node* index, | |
3142 uint32_t offset, uint32_t alignment, | |
3143 Node* val) { | |
3144 Node* store; | |
3145 Node* newValue; | |
3146 | |
3147 wasm::WasmOpcode shiftOpcode; | |
3148 | |
3149 Node* shiftConst; | |
3150 bool extendTo64Bit = false; | |
3151 bool isFloat = IsFloatingPoint(memtype.representation()); | |
3152 int stride = 1 << ElementSizeLog2Of( | |
3153 GetTypeForUnalignedAccess(alignment).representation()); | |
3154 int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); | |
3155 DCHECK(numberOfBytes % stride == 0); | |
3156 | |
3157 StoreRepresentation rep(GetTypeForUnalignedAccess(alignment).representation(), | |
3158 kNoWriteBarrier); | |
3159 | |
3160 if (ElementSizeLog2Of(memtype.representation()) <= 2) { | |
3161 shiftOpcode = wasm::kExprI32ShrU; | |
3162 shiftConst = jsgraph()->Int32Constant(8 * stride); | |
3163 } else { | |
3164 shiftOpcode = wasm::kExprI64ShrU; | |
3165 shiftConst = jsgraph()->Int64Constant(8 * stride); | |
3166 extendTo64Bit = true; | |
3167 } | |
3168 | |
3169 newValue = val; | |
3170 if (isFloat) { | |
3171 switch (memtype.representation()) { | |
3172 case MachineRepresentation::kFloat64: | |
3173 newValue = Unop(wasm::kExprI64ReinterpretF64, val); | |
3174 break; | |
3175 case MachineRepresentation::kFloat32: | |
3176 newValue = Unop(wasm::kExprI32ReinterpretF32, val); | |
3177 break; | |
3178 default: | |
3179 UNREACHABLE(); | |
3180 } | |
3181 } | |
3182 | |
3183 Node* baseOffset = MemBuffer(offset); | |
3184 | |
3185 for (int i = 0; i < numberOfBytes - stride; i += stride) { | |
3186 store = graph()->NewNode( | |
3187 jsgraph()->machine()->Store(rep), | |
3188 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, i), | |
3189 index, | |
3190 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, | |
3191 *effect_, *control_); | |
3192 newValue = Binop(shiftOpcode, newValue, shiftConst); | |
3193 *effect_ = store; | |
3194 } | |
3195 store = graph()->NewNode( | |
3196 jsgraph()->machine()->Store(rep), | |
3197 GetUnalignedStoreOffsetNode(baseOffset, numberOfBytes, stride, | |
3198 numberOfBytes - stride), | |
3199 index, | |
3200 extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, | |
3201 *effect_, *control_); | |
3202 *effect_ = store; | |
3203 return val; | |
3204 } | |
3205 | 2995 |
3206 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, | 2996 Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, |
3207 uint32_t offset, uint32_t alignment, Node* val, | 2997 uint32_t offset, uint32_t alignment, Node* val, |
3208 wasm::WasmCodePosition position) { | 2998 wasm::WasmCodePosition position) { |
3209 Node* store; | 2999 Node* store; |
3210 | 3000 |
3211 // WASM semantics throw on OOB. Introduce explicit bounds check. | 3001 // WASM semantics throw on OOB. Introduce explicit bounds check. |
3212 BoundsCheckMem(memtype, index, offset, position); | 3002 BoundsCheckMem(memtype, index, offset, position); |
3213 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | 3003 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
3214 bool aligned = static_cast<int>(alignment) >= | 3004 bool aligned = static_cast<int>(alignment) >= |
3215 ElementSizeLog2Of(memtype.representation()); | 3005 ElementSizeLog2Of(memtype.representation()); |
3216 | 3006 |
3217 #if defined(V8_TARGET_BIG_ENDIAN) | 3007 #if defined(V8_TARGET_BIG_ENDIAN) |
3218 // TODO(john.yan) Implement byte swap turbofan operator | 3008 // TODO(john.yan) Implement byte swap turbofan operator |
3219 // and use it if available for better performance | 3009 // and use it if available for better performance |
3220 val = BuildChangeEndianness(val, memtype); | 3010 val = BuildChangeEndianness(val, memtype); |
3221 #endif | 3011 #endif |
3222 | 3012 |
3223 if (aligned || | 3013 if (aligned || |
3224 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { | 3014 jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { |
3225 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); | 3015 StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
3226 store = | 3016 store = |
3227 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), | 3017 graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), |
3228 index, val, *effect_, *control_); | 3018 index, val, *effect_, *control_); |
3229 *effect_ = store; | |
3230 } else { | 3019 } else { |
3231 store = BuildUnalignedStore(memtype, index, offset, alignment, val); | 3020 UnalignedStoreRepresentation rep(memtype.representation()); |
| 3021 store = |
| 3022 graph()->NewNode(jsgraph()->machine()->UnalignedStore(rep), |
| 3023 MemBuffer(offset), index, val, *effect_, *control_); |
3232 } | 3024 } |
3233 | 3025 |
| 3026 *effect_ = store; |
| 3027 |
3234 return store; | 3028 return store; |
3235 } | 3029 } |
3236 | 3030 |
3237 Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { | 3031 Node* WasmGraphBuilder::BuildAsmjsLoadMem(MachineType type, Node* index) { |
3238 // TODO(turbofan): fold bounds checks for constant asm.js loads. | 3032 // TODO(turbofan): fold bounds checks for constant asm.js loads. |
3239 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). | 3033 // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). |
3240 const Operator* op = jsgraph()->machine()->CheckedLoad(type); | 3034 const Operator* op = jsgraph()->machine()->CheckedLoad(type); |
3241 Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, | 3035 Node* load = graph()->NewNode(op, MemBuffer(0), index, MemSize(0), *effect_, |
3242 *control_); | 3036 *control_); |
3243 *effect_ = load; | 3037 *effect_ = load; |
(...skipping 304 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3548 : thrower_(thrower), | 3342 : thrower_(thrower), |
3549 isolate_(isolate), | 3343 isolate_(isolate), |
3550 module_env_(module_env), | 3344 module_env_(module_env), |
3551 function_(function), | 3345 function_(function), |
3552 graph_zone_(new Zone(isolate->allocator())), | 3346 graph_zone_(new Zone(isolate->allocator())), |
3553 jsgraph_(new (graph_zone()) JSGraph( | 3347 jsgraph_(new (graph_zone()) JSGraph( |
3554 isolate, new (graph_zone()) Graph(graph_zone()), | 3348 isolate, new (graph_zone()) Graph(graph_zone()), |
3555 new (graph_zone()) CommonOperatorBuilder(graph_zone()), nullptr, | 3349 new (graph_zone()) CommonOperatorBuilder(graph_zone()), nullptr, |
3556 nullptr, new (graph_zone()) MachineOperatorBuilder( | 3350 nullptr, new (graph_zone()) MachineOperatorBuilder( |
3557 graph_zone(), MachineType::PointerRepresentation(), | 3351 graph_zone(), MachineType::PointerRepresentation(), |
3558 InstructionSelector::SupportedMachineOperatorFlags()))), | 3352 InstructionSelector::SupportedMachineOperatorFlags(), |
| 3353 InstructionSelector::AlignmentRequirements()))), |
3559 compilation_zone_(isolate->allocator()), | 3354 compilation_zone_(isolate->allocator()), |
3560 info_(function->name_length != 0 | 3355 info_(function->name_length != 0 |
3561 ? module_env->module->GetNameOrNull(function->name_offset, | 3356 ? module_env->module->GetNameOrNull(function->name_offset, |
3562 function->name_length) | 3357 function->name_length) |
3563 : ArrayVector("wasm"), | 3358 : ArrayVector("wasm"), |
3564 isolate, &compilation_zone_, | 3359 isolate, &compilation_zone_, |
3565 Code::ComputeFlags(Code::WASM_FUNCTION)), | 3360 Code::ComputeFlags(Code::WASM_FUNCTION)), |
3566 job_(), | 3361 job_(), |
3567 index_(index), | 3362 index_(index), |
3568 ok_(true) { | 3363 ok_(true) { |
(...skipping 100 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3669 function_->code_start_offset), | 3464 function_->code_start_offset), |
3670 compile_ms); | 3465 compile_ms); |
3671 } | 3466 } |
3672 | 3467 |
3673 return code; | 3468 return code; |
3674 } | 3469 } |
3675 | 3470 |
3676 } // namespace compiler | 3471 } // namespace compiler |
3677 } // namespace internal | 3472 } // namespace internal |
3678 } // namespace v8 | 3473 } // namespace v8 |
OLD | NEW |