| Index: src/compiler/simplified-lowering.cc
|
| diff --git a/src/compiler/simplified-lowering.cc b/src/compiler/simplified-lowering.cc
|
| index 8d770c0f9ffb97df479d7d0caa0f1871150cecac..5ce23b5064cb522bfe1ea91d161d9f2a0d707961 100644
|
| --- a/src/compiler/simplified-lowering.cc
|
| +++ b/src/compiler/simplified-lowering.cc
|
| @@ -764,30 +764,51 @@ class RepresentationSelector {
|
| ElementAccess access = ElementAccessOf(node->op());
|
| ProcessInput(node, 0, changer_->TypeForBasePointer(access));
|
| ProcessInput(node, 1, kMachInt32); // element index
|
| - ProcessInput(node, 2, kMachInt32); // length
|
| - ProcessRemainingInputs(node, 3);
|
| - // Tagged overrides everything if we have to do a typed array bounds
|
| - // check, because we may need to return undefined then.
|
| - MachineType output_type =
|
| - (access.bounds_check == kTypedArrayBoundsCheck &&
|
| - (use & kRepTagged))
|
| - ? kMachAnyTagged
|
| - : access.machine_type;
|
| - SetOutput(node, output_type);
|
| - if (lower()) lowering->DoLoadElement(node, output_type);
|
| + ProcessRemainingInputs(node, 2);
|
| + SetOutput(node, access.machine_type);
|
| + if (lower()) lowering->DoLoadElement(node);
|
| break;
|
| }
|
| case IrOpcode::kStoreElement: {
|
| ElementAccess access = ElementAccessOf(node->op());
|
| ProcessInput(node, 0, changer_->TypeForBasePointer(access));
|
| ProcessInput(node, 1, kMachInt32); // element index
|
| - ProcessInput(node, 2, kMachInt32); // length
|
| - ProcessInput(node, 3, access.machine_type);
|
| - ProcessRemainingInputs(node, 4);
|
| + ProcessInput(node, 2, access.machine_type);
|
| + ProcessRemainingInputs(node, 3);
|
| SetOutput(node, 0);
|
| if (lower()) lowering->DoStoreElement(node);
|
| break;
|
| }
|
| + case IrOpcode::kLoadBuffer: {
|
| + BufferAccess const access = BufferAccessOf(node->op());
|
| + ProcessInput(node, 0, kMachPtr); // buffer
|
| + ProcessInput(node, 1, kMachInt32); // offset
|
| + ProcessInput(node, 2, kMachUint32); // length
|
| + ProcessRemainingInputs(node, 3);
|
| + // Tagged overrides everything, because we may need to return undefined.
|
| + MachineType const output_type =
|
| + (use & kRepTagged) ? kMachAnyTagged : access.machine_type();
|
| + SetOutput(node, output_type);
|
| + if (lower()) lowering->DoLoadBuffer(node, output_type);
|
| + break;
|
| + }
|
| + case IrOpcode::kStoreBuffer: {
|
| + BufferAccess const access = BufferAccessOf(node->op());
|
| + ProcessInput(node, 0, kMachPtr); // buffer
|
| + ProcessInput(node, 1, kMachInt32); // offset
|
| + ProcessInput(node, 2, kMachUint32); // length
|
| + ProcessInput(node, 3, access.machine_type()); // value
|
| + ProcessRemainingInputs(node, 4);
|
| + SetOutput(node, 0);
|
| + if (lower()) lowering->DoStoreBuffer(node);
|
| + break;
|
| + }
|
| + case IrOpcode::kBoundsCheck: {
|
| + ProcessInput(node, 0, kRepWord32);
|
| + ProcessInput(node, 1, kMachUint32);
|
| + SetOutput(node, kMachUint32);
|
| + break;
|
| + }
|
| case IrOpcode::kObjectIsSmi: {
|
| ProcessInput(node, 0, kMachAnyTagged);
|
| SetOutput(node, kRepBit | kTypeBool);
|
| @@ -1031,8 +1052,7 @@ Node* SimplifiedLowering::IsTagged(Node* node) {
|
|
|
|
|
| void SimplifiedLowering::LowerAllNodes() {
|
| - SimplifiedOperatorBuilder simplified(graph()->zone());
|
| - RepresentationChanger changer(jsgraph(), &simplified,
|
| + RepresentationChanger changer(jsgraph(), simplified(),
|
| graph()->zone()->isolate());
|
| RepresentationSelector selector(jsgraph(), zone(), &changer);
|
| selector.Run(this);
|
| @@ -1091,7 +1111,7 @@ void SimplifiedLowering::DoStoreField(Node* node) {
|
|
|
|
|
| Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
|
| - Node* const key) {
|
| + Node* key) {
|
| Node* index = key;
|
| const int element_size_shift = ElementSizeLog2Of(access.machine_type);
|
| if (element_size_shift) {
|
| @@ -1104,155 +1124,156 @@ Node* SimplifiedLowering::ComputeIndex(const ElementAccess& access,
|
| jsgraph()->Int32Constant(fixed_offset));
|
| }
|
| if (machine()->Is64()) {
|
| - // TODO(turbofan): This is probably only correct for typed arrays, and only
|
| - // if the typed arrays are at most 2GiB in size, which happens to match
|
| - // exactly our current situation.
|
| - index = graph()->NewNode(machine()->ChangeUint32ToUint64(), index);
|
| + index = graph()->NewNode(machine()->ChangeInt32ToInt64(), index);
|
| }
|
| return index;
|
| }
|
|
|
|
|
| -namespace {
|
| -
|
| -intptr_t AddressForOutOfBoundsLoad(MachineType type) {
|
| - switch (RepresentationOf(type)) {
|
| - case kRepFloat32: {
|
| - static const float dummy = std::numeric_limits<float>::quiet_NaN();
|
| - return bit_cast<intptr_t>(&dummy);
|
| - }
|
| - case kRepFloat64: {
|
| - static const double dummy = std::numeric_limits<double>::quiet_NaN();
|
| - return bit_cast<intptr_t>(&dummy);
|
| - }
|
| - case kRepBit:
|
| - case kRepWord8:
|
| - case kRepWord16:
|
| - case kRepWord32: {
|
| - static const int32_t dummy = 0;
|
| - return bit_cast<intptr_t>(&dummy);
|
| - }
|
| - default:
|
| - break;
|
| +Node* SimplifiedLowering::ComputeOffset(const BufferAccess& access,
|
| + Node* offset) {
|
| + int const element_size = ElementSizeOf(access.machine_type());
|
| + DCHECK_LE(1, element_size);
|
| + if (element_size > 1) {
|
| + offset = graph()->NewNode(machine()->Word32And(), offset,
|
| + jsgraph()->Int32Constant(~(element_size - 1)));
|
| }
|
| - UNREACHABLE();
|
| - return 0;
|
| + if (machine()->Is64()) {
|
| + // TODO(turbofan): This is probably only correct for typed arrays, and only
|
| + // if the typed arrays are at most 2GiB in size, which happens to match
|
| + // exactly our current situation.
|
| + offset = graph()->NewNode(machine()->ChangeUint32ToUint64(), offset);
|
| + }
|
| + return offset;
|
| }
|
|
|
|
|
| -intptr_t AddressForOutOfBoundsStore() {
|
| - static volatile double dummy = 0;
|
| - return bit_cast<intptr_t>(&dummy);
|
| +void SimplifiedLowering::DoLoadElement(Node* node) {
|
| + const ElementAccess& access = ElementAccessOf(node->op());
|
| + Node* key = node->InputAt(1);
|
| + Node* index = ComputeIndex(access, key);
|
| + node->set_op(machine()->Load(access.machine_type));
|
| + node->ReplaceInput(1, index);
|
| }
|
|
|
| -} // namespace
|
|
|
| -
|
| -void SimplifiedLowering::DoLoadElement(Node* node, MachineType output_type) {
|
| +void SimplifiedLowering::DoStoreElement(Node* node) {
|
| const ElementAccess& access = ElementAccessOf(node->op());
|
| - const Operator* op = machine()->Load(access.machine_type);
|
| Node* key = node->InputAt(1);
|
| Node* index = ComputeIndex(access, key);
|
| + node->set_op(machine()->Store(StoreRepresentation(
|
| + access.machine_type,
|
| + ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
|
| + access.type))));
|
| + node->ReplaceInput(1, index);
|
| +}
|
| +
|
| +
|
| +void SimplifiedLowering::DoLoadBuffer(Node* node, MachineType output_type) {
|
| + BufferAccess const access = BufferAccessOf(node->op());
|
| + Node* buffer = node->InputAt(0);
|
| + Node* offset = node->InputAt(1);
|
| + Node* length = node->InputAt(2);
|
| Node* effect = node->InputAt(3);
|
| - if (access.bounds_check == kNoBoundsCheck) {
|
| - DCHECK_EQ(access.machine_type, output_type);
|
| - node->set_op(op);
|
| - node->ReplaceInput(1, index);
|
| - node->ReplaceInput(2, effect);
|
| - node->ReplaceInput(3, graph()->start());
|
| - } else {
|
| - DCHECK_EQ(kTypedArrayBoundsCheck, access.bounds_check);
|
| -
|
| - Node* base = node->InputAt(0);
|
| - Node* length = node->InputAt(2);
|
| - Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, length);
|
| -
|
| - IntPtrMatcher mbase(base);
|
| - if (mbase.HasValue() && (output_type & kRepTagged) == 0) {
|
| - Node* select = graph()->NewNode(
|
| - common()->Select(kMachIntPtr, BranchHint::kTrue), check, index,
|
| - jsgraph()->IntPtrConstant(AddressForOutOfBoundsLoad(output_type) -
|
| - mbase.Value()));
|
| -
|
| - node->set_op(op);
|
| - node->ReplaceInput(1, select);
|
| - node->ReplaceInput(2, effect);
|
| - node->ReplaceInput(3, graph()->start());
|
| + Node* control = node->InputAt(4);
|
| + size_t const element_size = ElementSizeOf(access.machine_type());
|
| + if (output_type & kRepTagged || access.guard_size() < element_size) {
|
| + Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length);
|
| + Node* branch =
|
| + graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
|
| +
|
| + Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
| + Node* vtrue =
|
| + graph()->NewNode(machine()->Load(access.machine_type()), buffer,
|
| + ComputeOffset(access, offset), effect, if_true);
|
| + Node* etrue = vtrue;
|
| + if (output_type & kRepTagged) {
|
| + // TODO(turbofan): This is ugly as hell!
|
| + RepresentationChanger changer(jsgraph(), simplified(),
|
| + graph()->zone()->isolate());
|
| + vtrue = changer.GetTaggedRepresentationFor(vtrue, access.machine_type());
|
| + }
|
| +
|
| + Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
| + Node* vfalse;
|
| + // TODO(bmeurer): Refactor this into a separate method.
|
| + if (output_type & kRepTagged) {
|
| + DCHECK_EQ(0, access.machine_type() & kRepTagged);
|
| + vfalse = jsgraph()->UndefinedConstant();
|
| + } else if (output_type & kRepFloat32) {
|
| + vfalse =
|
| + jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
|
| + } else if (output_type & kRepFloat64) {
|
| + vfalse =
|
| + jsgraph()->Float64Constant(std::numeric_limits<double>::quiet_NaN());
|
| } else {
|
| - Diamond d(graph(), common(), check, BranchHint::kTrue);
|
| -
|
| - Node* load = graph()->NewNode(op, base, index, effect, d.if_true);
|
| - Node* result = load;
|
| - if (output_type & kRepTagged) {
|
| - // TODO(turbofan): This is ugly as hell!
|
| - SimplifiedOperatorBuilder simplified(graph()->zone());
|
| - RepresentationChanger changer(jsgraph(), &simplified,
|
| - graph()->zone()->isolate());
|
| - result =
|
| - changer.GetTaggedRepresentationFor(result, access.machine_type);
|
| - }
|
| + vfalse = jsgraph()->Int32Constant(0);
|
| + }
|
| + Node* efalse = effect;
|
|
|
| - Node* undefined;
|
| - if (output_type & kRepTagged) {
|
| - DCHECK_EQ(0, access.machine_type & kRepTagged);
|
| - undefined = jsgraph()->UndefinedConstant();
|
| - } else if (output_type & kRepFloat32) {
|
| - undefined =
|
| - jsgraph()->Float32Constant(std::numeric_limits<float>::quiet_NaN());
|
| - } else if (output_type & kRepFloat64) {
|
| - undefined = jsgraph()->Float64Constant(
|
| - std::numeric_limits<double>::quiet_NaN());
|
| - } else {
|
| - undefined = jsgraph()->Int32Constant(0);
|
| - }
|
| + Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
| + Node* ephi = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, merge);
|
|
|
| - // Replace effect uses of node with the effect phi.
|
| - NodeProperties::ReplaceWithValue(node, node, d.EffectPhi(load, effect));
|
| + // Replace effect uses of {node} with the EffectPhi {ephi}.
|
| + NodeProperties::ReplaceWithValue(node, node, ephi);
|
|
|
| - d.OverwriteWithPhi(node, output_type, result, undefined);
|
| - }
|
| + // Turn the {node} into a Phi.
|
| + node->set_op(common()->Phi(output_type, 2));
|
| + node->ReplaceInput(0, vtrue);
|
| + node->ReplaceInput(1, vfalse);
|
| + node->ReplaceInput(2, merge);
|
| + node->TrimInputCount(3);
|
| + } else {
|
| + offset = graph()->NewNode(
|
| + simplified()->BoundsCheck(access.guard_size() - element_size), offset,
|
| + length);
|
| + node->set_op(machine()->Load(access.machine_type()));
|
| + DCHECK_EQ(buffer, node->InputAt(0));
|
| + node->ReplaceInput(1, ComputeOffset(access, offset));
|
| + node->RemoveInput(2);
|
| }
|
| }
|
|
|
|
|
| -void SimplifiedLowering::DoStoreElement(Node* node) {
|
| - const ElementAccess& access = ElementAccessOf(node->op());
|
| - const Operator* op = machine()->Store(StoreRepresentation(
|
| - access.machine_type,
|
| - ComputeWriteBarrierKind(access.base_is_tagged, access.machine_type,
|
| - access.type)));
|
| - Node* key = node->InputAt(1);
|
| - Node* index = ComputeIndex(access, key);
|
| - if (access.bounds_check == kNoBoundsCheck) {
|
| - node->set_op(op);
|
| - node->ReplaceInput(1, index);
|
| - node->RemoveInput(2);
|
| +void SimplifiedLowering::DoStoreBuffer(Node* node) {
|
| + BufferAccess const access = BufferAccessOf(node->op());
|
| + Node* buffer = node->InputAt(0);
|
| + Node* offset = node->InputAt(1);
|
| + Node* length = node->InputAt(2);
|
| + Node* value = node->InputAt(3);
|
| + Node* effect = node->InputAt(4);
|
| + Node* control = node->InputAt(5);
|
| + size_t const element_size = ElementSizeOf(access.machine_type());
|
| + if (access.guard_size() < element_size) {
|
| + Node* check = graph()->NewNode(machine()->Uint32LessThan(), offset, length);
|
| + Node* branch =
|
| + graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);
|
| +
|
| + Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
|
| + Node* etrue = graph()->NewNode(machine()->Store(StoreRepresentation(
|
| + access.machine_type(), kNoWriteBarrier)),
|
| + buffer, ComputeOffset(access, offset), value,
|
| + effect, if_true);
|
| +
|
| + Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
|
| + Node* efalse = effect;
|
| +
|
| + Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
|
| +
|
| + // Turn the {node} into an EffectPhi.
|
| + node->set_op(common()->EffectPhi(2));
|
| + node->ReplaceInput(0, etrue);
|
| + node->ReplaceInput(1, efalse);
|
| + node->ReplaceInput(2, merge);
|
| + node->TrimInputCount(3);
|
| } else {
|
| - DCHECK_EQ(kTypedArrayBoundsCheck, access.bounds_check);
|
| -
|
| - Node* base = node->InputAt(0);
|
| - Node* length = node->InputAt(2);
|
| - Node* value = node->InputAt(3);
|
| - Node* effect = node->InputAt(4);
|
| - Node* control = node->InputAt(5);
|
| - Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, length);
|
| -
|
| - IntPtrMatcher mbase(base);
|
| - if (mbase.HasValue()) {
|
| - Node* select = graph()->NewNode(
|
| - common()->Select(kMachIntPtr, BranchHint::kTrue), check, index,
|
| - jsgraph()->IntPtrConstant(AddressForOutOfBoundsStore() -
|
| - mbase.Value()));
|
| -
|
| - node->set_op(op);
|
| - node->ReplaceInput(1, select);
|
| - node->RemoveInput(2);
|
| - } else {
|
| - Diamond d(graph(), common(), check, BranchHint::kTrue);
|
| - d.Chain(control);
|
| - Node* store = graph()->NewNode(op, base, index, value, effect, d.if_true);
|
| - d.OverwriteWithEffectPhi(node, store, effect);
|
| - }
|
| + offset = graph()->NewNode(
|
| + simplified()->BoundsCheck(access.guard_size() - element_size), offset,
|
| + length);
|
| + node->set_op(machine()->Store(
|
| + StoreRepresentation(access.machine_type(), kNoWriteBarrier)));
|
| + node->ReplaceInput(1, ComputeOffset(access, offset));
|
| + node->RemoveInput(2);
|
| }
|
| }
|
|
|
|
|