Chromium Code Reviews| Index: src/compiler/wasm-compiler.cc |
| diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc |
| index 96557b8386b17eb98318e7682503f2d6c16315a9..07f861bb7f2b08afd0e5300bfe844f577ae0c5fa 100644 |
| --- a/src/compiler/wasm-compiler.cc |
| +++ b/src/compiler/wasm-compiler.cc |
| @@ -2591,10 +2591,127 @@ void WasmGraphBuilder::BoundsCheckMem(MachineType memtype, Node* index, |
| trap_->AddTrapIfFalse(wasm::kTrapMemOutOfBounds, cond, position); |
| } |
| +Node* WasmGraphBuilder::BuildUnalignedLoad(wasm::LocalType type, |
| + MachineType memtype, Node* index, |
| + uint32_t offset, |
| + uint32_t alignment) { |
| + Node* result; |
| + Node* load; |
| + bool extendTo64Bit = false; |
| + |
| + wasm::WasmOpcode shiftOpcode; |
| + wasm::WasmOpcode orOpcode; |
| + Node* shiftConst; |
| + |
| + 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
|
| + switch (alignment) { |
| + case 0: |
| + return signExtend ? MachineType::Int8() : MachineType::Uint8(); |
| + case 1: |
| + return signExtend ? MachineType::Int16() : MachineType::Uint16(); |
| + case 2: |
| + return signExtend ? MachineType::Int32() : MachineType::Uint32(); |
| + default: |
| + UNREACHABLE(); |
| + } |
| + }; |
| + |
| + auto calculateOffset = [this](Node* baseOffset, int numberOfBytes, int stride, |
| + int current) -> Node* { |
| + int offset; |
| + |
| +#if defined(V8_TARGET_LITTLE_ENDIAN) |
| + offset = numberOfBytes - stride - current; |
| +#elif defined(V8_TARGET_BIG_ENDIAN) |
| + offset = current; |
| +#else |
| +#error Unsupported endianness |
| +#endif |
| + |
| + if (offset == 0) { |
| + return baseOffset; |
| + } else { |
| + return Binop(wasm::kExprI32Add, baseOffset, |
| + jsgraph()->Int32Constant(offset)); |
| + } |
| + }; |
| + |
| + bool signExtend = memtype.IsSigned(); |
| + |
| + bool isFloat = IsFloatingPoint(memtype.representation()); |
| + int stride = |
| + 1 << ElementSizeLog2Of(determineType(false, alignment).representation()); |
| + int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); |
| + int numberOfLoads = numberOfBytes / stride; |
| + |
| + DCHECK(numberOfBytes % stride == 0); |
| + DCHECK(numberOfLoads >= 2); |
| + |
| + switch (type) { |
| + case wasm::kAstI64: |
| + case wasm::kAstF64: |
| + shiftOpcode = wasm::kExprI64Shl; |
| + orOpcode = wasm::kExprI64Ior; |
| + result = jsgraph()->Int64Constant(0); |
| + shiftConst = jsgraph()->Int64Constant(8 * stride); |
| + extendTo64Bit = true; |
| + break; |
| + case wasm::kAstI32: |
| + case wasm::kAstF32: |
| + shiftOpcode = wasm::kExprI32Shl; |
| + orOpcode = wasm::kExprI32Ior; |
| + result = jsgraph()->Int32Constant(0); |
| + shiftConst = jsgraph()->Int32Constant(8 * stride); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + |
| + Node* baseOffset = MemBuffer(offset); |
| + |
| + for (int i = 0; i < numberOfBytes; i += stride) { |
| + result = Binop(shiftOpcode, result, shiftConst); |
| + load = graph()->NewNode( |
| + jsgraph()->machine()->Load(determineType(signExtend, alignment)), |
| + calculateOffset(baseOffset, numberOfBytes, stride, i), index, *effect_, |
| + *control_); |
| + *effect_ = load; |
| + if (extendTo64Bit) { |
| + if (signExtend) { |
| + load = |
| + graph()->NewNode(jsgraph()->machine()->ChangeInt32ToInt64(), load); |
| + } else { |
| + load = graph()->NewNode(jsgraph()->machine()->ChangeUint32ToUint64(), |
| + load); |
| + } |
| + } |
| + signExtend = false; |
| + result = Binop(orOpcode, result, load); |
| + } |
| + |
| + // Convert to float |
| + if (isFloat) { |
| + switch (type) { |
| + case wasm::kAstF32: |
| + result = Unop(wasm::kExprF32ReinterpretI32, result); |
| + break; |
| + case wasm::kAstF64: |
| + result = Unop(wasm::kExprF64ReinterpretI64, result); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + } |
| + |
| + return result; |
| +} |
| + |
| Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
| Node* index, uint32_t offset, |
| + uint32_t alignment, |
| wasm::WasmCodePosition position) { |
| Node* load; |
| + bool skip = false; |
| if (module_ && module_->asm_js()) { |
| // asm.js semantics use CheckedLoad (i.e. OOB reads return 0ish). |
| @@ -2605,11 +2722,21 @@ Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
| } else { |
| // WASM semantics throw on OOB. Introduce explicit bounds check. |
| BoundsCheckMem(memtype, index, offset, position); |
| - load = graph()->NewNode(jsgraph()->machine()->Load(memtype), |
| - MemBuffer(offset), index, *effect_, *control_); |
| + bool aligned = alignment >= ElementSizeLog2Of(memtype.representation()); |
| + |
| + if (aligned || |
| + jsgraph()->machine()->UnalignedLoadSupported(memtype, alignment)) { |
| + load = graph()->NewNode(jsgraph()->machine()->Load(memtype), |
| + MemBuffer(offset), index, *effect_, *control_); |
| + } else { |
| + load = BuildUnalignedLoad(type, memtype, index, offset, alignment); |
| + skip = true; |
| + } |
| } |
| - *effect_ = load; |
| + if (!skip) { |
|
titzer
2016/05/11 15:22:35
Can you lift this up into the branch instead of us
|
| + *effect_ = load; |
| + } |
| if (type == wasm::kAstI64 && |
| ElementSizeLog2Of(memtype.representation()) < 3) { |
| @@ -2627,10 +2754,110 @@ Node* WasmGraphBuilder::LoadMem(wasm::LocalType type, MachineType memtype, |
| return load; |
| } |
| +Node* WasmGraphBuilder::BuildUnalignedStore(MachineType memtype, Node* index, |
| + uint32_t offset, uint32_t alignment, |
| + Node* val) { |
| + Node* store; |
| + Node* newValue; |
| + |
| + wasm::WasmOpcode shiftOpcode; |
| + |
| + Node* shiftConst; |
| + bool extendTo64Bit = false; |
| + |
| + auto determineType = [](uint32_t alignment) -> MachineType { |
| + switch (alignment) { |
| + case 0: |
| + return MachineType::Uint8(); |
| + case 1: |
| + return MachineType::Uint16(); |
| + case 2: |
| + return MachineType::Uint32(); |
| + default: |
| + UNREACHABLE(); |
| + } |
| + }; |
| + |
| + auto calculateOffset = [this](Node* baseOffset, int numberOfBytes, int stride, |
| + int current) -> Node* { |
| + int offset; |
| +#if defined(V8_TARGET_LITTLE_ENDIAN) |
| + offset = current; |
| +#elif defined(V8_TARGET_BIG_ENDIAN) |
| + offset = numberOfBytes - stride - current; |
| +#else |
| +#error Unsupported endianness |
| +#endif |
| + if (offset == 0) { |
| + return baseOffset; |
| + } else { |
| + return Binop(wasm::kExprI32Add, baseOffset, |
| + jsgraph()->Int32Constant(offset)); |
| + } |
| + }; |
| + |
| + bool isFloat = IsFloatingPoint(memtype.representation()); |
| + int stride = |
| + 1 << ElementSizeLog2Of(determineType(alignment).representation()); |
| + int numberOfBytes = 1 << ElementSizeLog2Of(memtype.representation()); |
| + int numberOfLoads = numberOfBytes / stride; |
| + |
| + DCHECK(numberOfBytes % stride == 0); |
| + DCHECK(numberOfLoads >= 2); |
| + |
| + StoreRepresentation rep(determineType(alignment).representation(), |
| + kNoWriteBarrier); |
| + |
| + if (ElementSizeLog2Of(memtype.representation()) <= 2) { |
| + shiftOpcode = wasm::kExprI32ShrU; |
| + shiftConst = jsgraph()->Int32Constant(8 * stride); |
| + } else { |
| + shiftOpcode = wasm::kExprI64ShrU; |
| + shiftConst = jsgraph()->Int64Constant(8 * stride); |
| + extendTo64Bit = true; |
| + } |
| + |
| + newValue = val; |
| + if (isFloat) { |
| + switch (memtype.representation()) { |
| + case MachineRepresentation::kFloat64: |
| + newValue = Unop(wasm::kExprI64ReinterpretF64, val); |
| + break; |
| + case MachineRepresentation::kFloat32: |
| + newValue = Unop(wasm::kExprI32ReinterpretF32, val); |
| + break; |
| + default: |
| + UNREACHABLE(); |
| + } |
| + } |
| + |
| + Node* baseOffset = MemBuffer(offset); |
| + |
| + for (int i = 0; i < numberOfBytes - stride; i += stride) { |
| + store = graph()->NewNode( |
| + jsgraph()->machine()->Store(rep), |
| + calculateOffset(baseOffset, numberOfBytes, stride, i), index, |
| + extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, |
| + *effect_, *control_); |
| + newValue = Binop(shiftOpcode, newValue, shiftConst); |
| + *effect_ = store; |
| + } |
| + store = graph()->NewNode( |
| + jsgraph()->machine()->Store(rep), |
| + calculateOffset(baseOffset, numberOfBytes, stride, |
| + numberOfBytes - stride), |
| + index, |
| + extendTo64Bit ? Unop(wasm::kExprI32ConvertI64, newValue) : newValue, |
| + *effect_, *control_); |
| + *effect_ = store; |
| + return val; |
| +} |
| + |
| Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, |
| - uint32_t offset, Node* val, |
| + uint32_t offset, uint32_t alignment, Node* val, |
| wasm::WasmCodePosition position) { |
| Node* store; |
| + bool skip = false; |
| if (module_ && module_->asm_js()) { |
| // asm.js semantics use CheckedStore (i.e. ignore OOB writes). |
| DCHECK_EQ(0, offset); |
| @@ -2642,11 +2869,24 @@ Node* WasmGraphBuilder::StoreMem(MachineType memtype, Node* index, |
| // WASM semantics throw on OOB. Introduce explicit bounds check. |
| BoundsCheckMem(memtype, index, offset, position); |
| StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
| - store = |
| - graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), |
| - index, val, *effect_, *control_); |
| + bool aligned = alignment >= ElementSizeLog2Of(memtype.representation()); |
| + |
| + if (aligned || |
| + jsgraph()->machine()->UnalignedStoreSupported(memtype, alignment)) { |
| + StoreRepresentation rep(memtype.representation(), kNoWriteBarrier); |
| + store = |
| + graph()->NewNode(jsgraph()->machine()->Store(rep), MemBuffer(offset), |
| + index, val, *effect_, *control_); |
| + } else { |
| + store = BuildUnalignedStore(memtype, index, offset, alignment, val); |
| + skip = true; |
| + } |
| } |
| - *effect_ = store; |
| + |
| + if (!skip) { |
| + *effect_ = store; |
| + } |
| + |
| return store; |
| } |
| @@ -2877,7 +3117,8 @@ std::pair<JSGraph*, SourcePositionTable*> BuildGraphForWasmFunction( |
| CommonOperatorBuilder* common = new (zone) CommonOperatorBuilder(zone); |
| MachineOperatorBuilder* machine = new (zone) MachineOperatorBuilder( |
| zone, MachineType::PointerRepresentation(), |
| - InstructionSelector::SupportedMachineOperatorFlags()); |
| + InstructionSelector::SupportedMachineOperatorFlags(), |
| + InstructionSelector::AlignmentConfiguration()); |
| JSGraph* jsgraph = |
| new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine); |
| SourcePositionTable* source_position_table = |