| Index: src/compiler/wasm-compiler.cc
|
| diff --git a/src/compiler/wasm-compiler.cc b/src/compiler/wasm-compiler.cc
|
| index 96557b8386b17eb98318e7682503f2d6c16315a9..a6e3cfb6c2867fa43cb825c23f001e433a6138fe 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 {
|
| + 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) {
|
| + *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::UnalignedAccessConfiguration());
|
| JSGraph* jsgraph =
|
| new (zone) JSGraph(isolate, graph, common, nullptr, nullptr, machine);
|
| SourcePositionTable* source_position_table =
|
|
|