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 = |