| Index: src/compiler/simplified-operator-reducer.cc
|
| diff --git a/src/compiler/simplified-operator-reducer.cc b/src/compiler/simplified-operator-reducer.cc
|
| index a1a6a02bc89381481d961f9e7c22047b6a86e5bb..baa747c6724d604e912c7d93e053cdb9765cd4f4 100644
|
| --- a/src/compiler/simplified-operator-reducer.cc
|
| +++ b/src/compiler/simplified-operator-reducer.cc
|
| @@ -99,40 +99,62 @@ Reduction SimplifiedOperatorReducer::Reduce(Node* node) {
|
| if (m.HasValue()) return ReplaceNumber(FastUI2D(m.Value()));
|
| break;
|
| }
|
| - case IrOpcode::kLoadElement: {
|
| - ElementAccess access = ElementAccessOf(node->op());
|
| - if (access.bounds_check == kTypedArrayBoundsCheck) {
|
| - NumberMatcher mkey(node->InputAt(1));
|
| - NumberMatcher mlength(node->InputAt(2));
|
| - if (mkey.HasValue() && mlength.HasValue()) {
|
| - // Skip the typed array bounds check if key and length are constant.
|
| - if (mkey.Value() >= 0 && mkey.Value() < mlength.Value()) {
|
| - access.bounds_check = kNoBoundsCheck;
|
| - node->set_op(simplified()->LoadElement(access));
|
| - return Changed(node);
|
| - }
|
| - }
|
| - }
|
| + case IrOpcode::kBoundsCheck:
|
| + return ReduceBoundsCheck(node);
|
| + default:
|
| break;
|
| + }
|
| + return NoChange();
|
| +}
|
| +
|
| +
|
| +namespace {
|
| +
|
| +// TODO(bmeurer): Move to node-matchers.h/cc
|
| +class BoundsCheckMatcher FINAL : public NodeMatcher {
|
| + public:
|
| + typedef Uint32Matcher Offset;
|
| + typedef Uint32Matcher Length;
|
| +
|
| + explicit BoundsCheckMatcher(Node* node)
|
| + : NodeMatcher(node), offset_(InputAt(0)), length_(InputAt(1)) {
|
| + DCHECK_EQ(IrOpcode::kBoundsCheck, opcode());
|
| + }
|
| +
|
| + Offset const& offset() const { return offset_; }
|
| + Length const& length() const { return length_; }
|
| + size_t guard() const { return OpParameter<size_t>(op()); }
|
| +
|
| + private:
|
| + Offset const offset_;
|
| + Length const length_;
|
| +};
|
| +
|
| +} // namespace
|
| +
|
| +
|
| +Reduction SimplifiedOperatorReducer::ReduceBoundsCheck(Node* const node) {
|
| + BoundsCheckMatcher m(node);
|
| + if (m.offset().HasValue()) {
|
| + if (m.length().HasValue()) {
|
| + return Replace((m.offset().Value() < m.length().Value())
|
| + ? m.offset().node()
|
| + : m.length().node());
|
| }
|
| - case IrOpcode::kStoreElement: {
|
| - ElementAccess access = ElementAccessOf(node->op());
|
| - if (access.bounds_check == kTypedArrayBoundsCheck) {
|
| - NumberMatcher mkey(node->InputAt(1));
|
| - NumberMatcher mlength(node->InputAt(2));
|
| - if (mkey.HasValue() && mlength.HasValue()) {
|
| - // Skip the typed array bounds check if key and length are constant.
|
| - if (mkey.Value() >= 0 && mkey.Value() < mlength.Value()) {
|
| - access.bounds_check = kNoBoundsCheck;
|
| - node->set_op(simplified()->StoreElement(access));
|
| - return Changed(node);
|
| - }
|
| - }
|
| - }
|
| - break;
|
| + if (m.offset().Value() <= m.guard()) {
|
| + return Replace(m.offset().node());
|
| + }
|
| + }
|
| + if (m.offset().IsInt32Add()) {
|
| + Uint32BinopMatcher moffset(m.offset().node());
|
| + if (moffset.right().IsInRange(0, m.guard())) {
|
| + Node* const chk = graph()->NewNode(
|
| + simplified()->BoundsCheck(m.guard() - moffset.right().Value()),
|
| + moffset.left().node(), m.length().node());
|
| + Node* const add =
|
| + graph()->NewNode(machine()->Int32Add(), chk, moffset.right().node());
|
| + return Replace(add);
|
| }
|
| - default:
|
| - break;
|
| }
|
| return NoChange();
|
| }
|
|
|