simplified-lowering.cc 189 KB
Newer Older
1 2 3 4 5 6
// Copyright 2014 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/compiler/simplified-lowering.h"

7 8
#include <limits>

9
#include "include/v8-fast-api-calls.h"
10
#include "src/base/bits.h"
11
#include "src/base/small-vector.h"
12
#include "src/codegen/code-factory.h"
13
#include "src/codegen/machine-type.h"
14
#include "src/codegen/tick-counter.h"
15
#include "src/compiler/access-builder.h"
16
#include "src/compiler/common-operator.h"
17
#include "src/compiler/compiler-source-position-table.h"
18
#include "src/compiler/diamond.h"
19
#include "src/compiler/linkage.h"
20
#include "src/compiler/node-matchers.h"
21
#include "src/compiler/node-origin-table.h"
22
#include "src/compiler/node-properties.h"
23
#include "src/compiler/operation-typer.h"
24
#include "src/compiler/operator-properties.h"
25 26
#include "src/compiler/representation-change.h"
#include "src/compiler/simplified-operator.h"
27
#include "src/compiler/type-cache.h"
28
#include "src/numbers/conversions-inl.h"
29
#include "src/objects/objects.h"
30
#include "src/utils/address-map.h"
31 32 33 34 35

namespace v8 {
namespace internal {
namespace compiler {

36
// Macro for outputting trace information from representation inference.
37 38 39 40
#define TRACE(...)                                      \
  do {                                                  \
    if (FLAG_trace_representation) PrintF(__VA_ARGS__); \
  } while (false)
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58

// Representation selection and lowering of {Simplified} operators to machine
// operators are interwined. We use a fixpoint calculation to compute both the
// output representation and the best possible lowering for {Simplified} nodes.
// Representation change insertion ensures that all values are in the correct
// machine representation after this phase, as dictated by the machine
// operators themselves.
enum Phase {
  // 1.) PROPAGATE: Traverse the graph from the end, pushing usage information
  //     backwards from uses to definitions, around cycles in phis, according
  //     to local rules for each operator.
  //     During this phase, the usage information for a node determines the best
  //     possible lowering for each operator so far, and that in turn determines
  //     the output representation.
  //     Therefore, to be correct, this phase must iterate to a fixpoint before
  //     the next phase can begin.
  PROPAGATE,

59 60 61 62
  // 2.) RETYPE: Propagate types from type feedback forwards.
  RETYPE,

  // 3.) LOWER: perform lowering for all {Simplified} nodes by replacing some
63 64 65 66 67 68 69 70
  //     operators for some nodes, expanding some nodes to multiple nodes, or
  //     removing some (redundant) nodes.
  //     During this phase, use the {RepresentationChanger} to insert
  //     representation changes between uses that demand a particular
  //     representation and nodes that produce a different representation.
  LOWER
};

71 72
namespace {

73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89
MachineRepresentation MachineRepresentationFromArrayType(
    ExternalArrayType array_type) {
  switch (array_type) {
    case kExternalUint8Array:
    case kExternalUint8ClampedArray:
    case kExternalInt8Array:
      return MachineRepresentation::kWord8;
    case kExternalUint16Array:
    case kExternalInt16Array:
      return MachineRepresentation::kWord16;
    case kExternalUint32Array:
    case kExternalInt32Array:
      return MachineRepresentation::kWord32;
    case kExternalFloat32Array:
      return MachineRepresentation::kFloat32;
    case kExternalFloat64Array:
      return MachineRepresentation::kFloat64;
90 91 92
    case kExternalBigInt64Array:
    case kExternalBigUint64Array:
      UNIMPLEMENTED();
93 94 95
  }
  UNREACHABLE();
}
96

97
UseInfo CheckedUseInfoAsWord32FromHint(
98
    NumberOperationHint hint, const FeedbackSource& feedback = FeedbackSource(),
99
    IdentifyZeros identify_zeros = kDistinguishZeros) {
100
  switch (hint) {
101 102 103
    case NumberOperationHint::kSignedSmall:
    case NumberOperationHint::kSignedSmallInputs:
      return UseInfo::CheckedSignedSmallAsWord32(identify_zeros, feedback);
104
    case NumberOperationHint::kNumber:
105
      return UseInfo::CheckedNumberAsWord32(feedback);
106 107 108
    case NumberOperationHint::kNumberOrBoolean:
      // Not used currently.
      UNREACHABLE();
109
    case NumberOperationHint::kNumberOrOddball:
110
      return UseInfo::CheckedNumberOrOddballAsWord32(feedback);
111 112 113 114
  }
  UNREACHABLE();
}

115
UseInfo CheckedUseInfoAsFloat64FromHint(
116
    NumberOperationHint hint, const FeedbackSource& feedback,
117
    IdentifyZeros identify_zeros = kDistinguishZeros) {
118
  switch (hint) {
119 120
    case NumberOperationHint::kSignedSmall:
    case NumberOperationHint::kSignedSmallInputs:
121 122 123
      // Not used currently.
      UNREACHABLE();
    case NumberOperationHint::kNumber:
124
      return UseInfo::CheckedNumberAsFloat64(identify_zeros, feedback);
125 126
    case NumberOperationHint::kNumberOrBoolean:
      return UseInfo::CheckedNumberOrBooleanAsFloat64(identify_zeros, feedback);
127
    case NumberOperationHint::kNumberOrOddball:
128
      return UseInfo::CheckedNumberOrOddballAsFloat64(identify_zeros, feedback);
129 130 131 132
  }
  UNREACHABLE();
}

133 134
UseInfo TruncatingUseInfoFromRepresentation(MachineRepresentation rep) {
  switch (rep) {
135
    case MachineRepresentation::kTaggedSigned:
136
      return UseInfo::TaggedSigned();
137
    case MachineRepresentation::kTaggedPointer:
138 139 140
    case MachineRepresentation::kTagged:
      return UseInfo::AnyTagged();
    case MachineRepresentation::kFloat64:
141
      return UseInfo::TruncatingFloat64();
142
    case MachineRepresentation::kFloat32:
143
      return UseInfo::Float32();
144 145 146
    case MachineRepresentation::kWord8:
    case MachineRepresentation::kWord16:
    case MachineRepresentation::kWord32:
147
      return UseInfo::TruncatingWord32();
148
    case MachineRepresentation::kWord64:
149
      return UseInfo::Word64();
150 151
    case MachineRepresentation::kBit:
      return UseInfo::Bool();
152 153
    case MachineRepresentation::kCompressedPointer:
    case MachineRepresentation::kCompressed:
154
    case MachineRepresentation::kSimd128:
155 156
    case MachineRepresentation::kNone:
      break;
157
  }
158
  UNREACHABLE();
159 160 161
}

UseInfo UseInfoForBasePointer(const FieldAccess& access) {
162
  return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
163 164 165
}

UseInfo UseInfoForBasePointer(const ElementAccess& access) {
166
  return access.tag() != 0 ? UseInfo::AnyTagged() : UseInfo::Word();
167 168
}

169 170 171 172 173 174 175
void ReplaceEffectControlUses(Node* node, Node* effect, Node* control) {
  for (Edge edge : node->use_edges()) {
    if (NodeProperties::IsControlEdge(edge)) {
      edge.UpdateTo(control);
    } else if (NodeProperties::IsEffectEdge(edge)) {
      edge.UpdateTo(effect);
    } else {
176 177
      DCHECK(NodeProperties::IsValueEdge(edge) ||
             NodeProperties::IsContextEdge(edge));
178 179 180 181
    }
  }
}

182
bool CanOverflowSigned32(const Operator* op, Type left, Type right,
183 184 185 186 187 188 189 190 191 192
                         TypeCache const* type_cache, Zone* type_zone) {
  // We assume the inputs are checked Signed32 (or known statically to be
  // Signed32). Technically, the inputs could also be minus zero, which we treat
  // as 0 for the purpose of this function.
  if (left.Maybe(Type::MinusZero())) {
    left = Type::Union(left, type_cache->kSingletonZero, type_zone);
  }
  if (right.Maybe(Type::MinusZero())) {
    right = Type::Union(right, type_cache->kSingletonZero, type_zone);
  }
193 194
  left = Type::Intersect(left, Type::Signed32(), type_zone);
  right = Type::Intersect(right, Type::Signed32(), type_zone);
195
  if (left.IsNone() || right.IsNone()) return false;
196
  switch (op->opcode()) {
197
    case IrOpcode::kSpeculativeSafeIntegerAdd:
198 199
      return (left.Max() + right.Max() > kMaxInt) ||
             (left.Min() + right.Min() < kMinInt);
200

201
    case IrOpcode::kSpeculativeSafeIntegerSubtract:
202 203
      return (left.Max() - right.Min() > kMaxInt) ||
             (left.Min() - right.Max() < kMinInt);
204 205 206 207 208 209

    default:
      UNREACHABLE();
  }
  return true;
}
210

211
bool IsSomePositiveOrderedNumber(Type type) {
212
  return type.Is(Type::OrderedNumber()) && !type.IsNone() && type.Min() > 0;
213 214
}

215
}  // namespace
216

217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242
#ifdef DEBUG
// Helpers for monotonicity checking.
class InputUseInfos {
 public:
  explicit InputUseInfos(Zone* zone) : input_use_infos_(zone) {}

  void SetAndCheckInput(Node* node, int index, UseInfo use_info) {
    if (input_use_infos_.empty()) {
      input_use_infos_.resize(node->InputCount(), UseInfo::None());
    }
    // Check that the new use informatin is a super-type of the old
    // one.
    DCHECK(IsUseLessGeneral(input_use_infos_[index], use_info));
    input_use_infos_[index] = use_info;
  }

 private:
  ZoneVector<UseInfo> input_use_infos_;

  static bool IsUseLessGeneral(UseInfo use1, UseInfo use2) {
    return use1.truncation().IsLessGeneralThan(use2.truncation());
  }
};

#endif  // DEBUG

243 244 245
class RepresentationSelector {
 public:
  // Information for each node tracked during the fixpoint.
246
  class NodeInfo final {
247 248 249 250 251 252 253 254 255
   public:
    // Adds new use to the node. Returns true if something has changed
    // and the node has to be requeued.
    bool AddUse(UseInfo info) {
      Truncation old_truncation = truncation_;
      truncation_ = Truncation::Generalize(truncation_, info.truncation());
      return truncation_ != old_truncation;
    }

256 257 258 259 260 261
    void set_queued() { state_ = kQueued; }
    void set_visited() { state_ = kVisited; }
    void set_pushed() { state_ = kPushed; }
    void reset_state() { state_ = kUnvisited; }
    bool visited() const { return state_ == kVisited; }
    bool queued() const { return state_ == kQueued; }
262
    bool pushed() const { return state_ == kPushed; }
263
    bool unvisited() const { return state_ == kUnvisited; }
264
    Truncation truncation() const { return truncation_; }
265
    void set_output(MachineRepresentation output) { representation_ = output; }
266

267
    MachineRepresentation representation() const { return representation_; }
268

269
    // Helpers for feedback typing.
270 271
    void set_feedback_type(Type type) { feedback_type_ = type; }
    Type feedback_type() const { return feedback_type_; }
272
    void set_weakened() { weakened_ = true; }
273
    bool weakened() const { return weakened_; }
274 275
    void set_restriction_type(Type type) { restriction_type_ = type; }
    Type restriction_type() const { return restriction_type_; }
276

277
   private:
278 279
    enum State : uint8_t { kUnvisited, kPushed, kVisited, kQueued };
    State state_ = kUnvisited;
280 281
    MachineRepresentation representation_ =
        MachineRepresentation::kNone;             // Output representation.
282
    Truncation truncation_ = Truncation::None();  // Information about uses.
283

284 285
    Type restriction_type_ = Type::Any();
    Type feedback_type_;
286
    bool weakened_ = false;
287 288
  };

289 290
  RepresentationSelector(JSGraph* jsgraph, JSHeapBroker* broker, Zone* zone,
                         RepresentationChanger* changer,
291
                         SourcePositionTable* source_positions,
292
                         NodeOriginTable* node_origins,
293
                         TickCounter* tick_counter, Linkage* linkage)
294
      : jsgraph_(jsgraph),
295
        zone_(zone),
296
        might_need_revisit_(zone),
297
        count_(jsgraph->graph()->NodeCount()),
298
        info_(count_, zone),
299 300 301
#ifdef DEBUG
        node_input_use_infos_(count_, InputUseInfos(zone), zone),
#endif
302
        replacements_(zone),
303
        changer_(changer),
304 305
        revisit_queue_(zone),
        traversal_nodes_(zone),
306
        source_positions_(source_positions),
307
        node_origins_(node_origins),
308
        type_cache_(TypeCache::Get()),
309
        op_typer_(broker, graph_zone()),
310 311
        tick_counter_(tick_counter),
        linkage_(linkage) {
312
  }
313

314 315 316 317 318 319 320
  void ResetNodeInfoState() {
    // Clean up for the next phase.
    for (NodeInfo& info : info_) {
      info.reset_state();
    }
  }

321 322 323
  Type TypeOf(Node* node) {
    Type type = GetInfo(node)->feedback_type();
    return type.IsInvalid() ? NodeProperties::GetType(node) : type;
324 325
  }

326 327 328
  Type FeedbackTypeOf(Node* node) {
    Type type = GetInfo(node)->feedback_type();
    return type.IsInvalid() ? Type::None() : type;
329 330
  }

331
  Type TypePhi(Node* node) {
332
    int arity = node->op()->ValueInputCount();
333
    Type type = FeedbackTypeOf(node->InputAt(0));
334 335 336 337 338 339
    for (int i = 1; i < arity; ++i) {
      type = op_typer_.Merge(type, FeedbackTypeOf(node->InputAt(i)));
    }
    return type;
  }

340
  Type TypeSelect(Node* node) {
341 342 343 344 345 346 347
    return op_typer_.Merge(FeedbackTypeOf(node->InputAt(1)),
                           FeedbackTypeOf(node->InputAt(2)));
  }

  bool UpdateFeedbackType(Node* node) {
    if (node->op()->ValueOutputCount() == 0) return false;

348 349 350 351 352
    // For any non-phi node just wait until we get all inputs typed. We only
    // allow untyped inputs for phi nodes because phis are the only places
    // where cycles need to be broken.
    if (node->opcode() != IrOpcode::kPhi) {
      for (int i = 0; i < node->op()->ValueInputCount(); i++) {
353
        if (GetInfo(node->InputAt(i))->feedback_type().IsInvalid()) {
354 355 356 357 358
          return false;
        }
      }
    }

359 360 361 362
    NodeInfo* info = GetInfo(node);
    Type type = info->feedback_type();
    Type new_type = NodeProperties::GetType(node);

363 364 365 366 367 368 369
    // We preload these values here to avoid increasing the binary size too
    // much, which happens if we inline the calls into the macros below.
    Type input0_type;
    if (node->InputCount() > 0) input0_type = FeedbackTypeOf(node->InputAt(0));
    Type input1_type;
    if (node->InputCount() > 1) input1_type = FeedbackTypeOf(node->InputAt(1));

370
    switch (node->opcode()) {
371 372 373 374
#define DECLARE_CASE(Name)                               \
  case IrOpcode::k##Name: {                              \
    new_type = op_typer_.Name(input0_type, input1_type); \
    break;                                               \
375 376
  }
      SIMPLIFIED_NUMBER_BINOP_LIST(DECLARE_CASE)
377
      DECLARE_CASE(SameValue)
378 379
#undef DECLARE_CASE

380 381 382 383 384
#define DECLARE_CASE(Name)                                               \
  case IrOpcode::k##Name: {                                              \
    new_type = Type::Intersect(op_typer_.Name(input0_type, input1_type), \
                               info->restriction_type(), graph_zone());  \
    break;                                                               \
385 386
  }
      SIMPLIFIED_SPECULATIVE_NUMBER_BINOP_LIST(DECLARE_CASE)
387
      SIMPLIFIED_SPECULATIVE_BIGINT_BINOP_LIST(DECLARE_CASE)
388
#undef DECLARE_CASE
389

390 391 392 393
#define DECLARE_CASE(Name)                  \
  case IrOpcode::k##Name: {                 \
    new_type = op_typer_.Name(input0_type); \
    break;                                  \
394 395 396
  }
      SIMPLIFIED_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE
397

398 399 400 401 402
#define DECLARE_CASE(Name)                                              \
  case IrOpcode::k##Name: {                                             \
    new_type = Type::Intersect(op_typer_.Name(input0_type),             \
                               info->restriction_type(), graph_zone()); \
    break;                                                              \
403 404 405 406
  }
      SIMPLIFIED_SPECULATIVE_NUMBER_UNOP_LIST(DECLARE_CASE)
#undef DECLARE_CASE

407
      case IrOpcode::kConvertReceiver:
408
        new_type = op_typer_.ConvertReceiver(input0_type);
409 410
        break;

411
      case IrOpcode::kPlainPrimitiveToNumber:
412
        new_type = op_typer_.ToNumber(input0_type);
413 414
        break;

415
      case IrOpcode::kCheckBounds:
416 417 418
        new_type =
            Type::Intersect(op_typer_.CheckBounds(input0_type, input1_type),
                            info->restriction_type(), graph_zone());
419 420
        break;

421 422 423 424 425 426 427 428
      case IrOpcode::kCheckFloat64Hole:
        new_type = Type::Intersect(op_typer_.CheckFloat64Hole(input0_type),
                                   info->restriction_type(), graph_zone());
        break;

      case IrOpcode::kCheckNumber:
        new_type = Type::Intersect(op_typer_.CheckNumber(input0_type),
                                   info->restriction_type(), graph_zone());
429 430
        break;

431 432
      case IrOpcode::kPhi: {
        new_type = TypePhi(node);
433
        if (!type.IsInvalid()) {
434 435 436 437 438
          new_type = Weaken(node, type, new_type);
        }
        break;
      }

439 440 441 442 443
      case IrOpcode::kConvertTaggedHoleToUndefined:
        new_type = op_typer_.ConvertTaggedHoleToUndefined(
            FeedbackTypeOf(node->InputAt(0)));
        break;

444 445 446 447 448 449
      case IrOpcode::kTypeGuard: {
        new_type = op_typer_.TypeTypeGuard(node->op(),
                                           FeedbackTypeOf(node->InputAt(0)));
        break;
      }

450 451 452 453 454 455 456
      case IrOpcode::kSelect: {
        new_type = TypeSelect(node);
        break;
      }

      default:
        // Shortcut for operations that we do not handle.
457
        if (type.IsInvalid()) {
458
          GetInfo(node)->set_feedback_type(NodeProperties::GetType(node));
459 460 461 462
          return true;
        }
        return false;
    }
463 464 465 466 467 468
    // We need to guarantee that the feedback type is a subtype of the upper
    // bound. Naively that should hold, but weakening can actually produce
    // a bigger type if we are unlucky with ordering of phi typing. To be
    // really sure, just intersect the upper bound with the feedback type.
    new_type = Type::Intersect(GetUpperBound(node), new_type, graph_zone());

469
    if (!type.IsInvalid() && new_type.Is(type)) return false;
470
    GetInfo(node)->set_feedback_type(new_type);
471 472 473 474 475 476 477
    if (FLAG_trace_representation) {
      PrintNodeFeedbackType(node);
    }
    return true;
  }

  void PrintNodeFeedbackType(Node* n) {
478
    StdoutStream os;
479 480 481 482 483 484 485 486
    os << "#" << n->id() << ":" << *n->op() << "(";
    int j = 0;
    for (Node* const i : n->inputs()) {
      if (j++ > 0) os << ", ";
      os << "#" << i->id() << ":" << i->op()->mnemonic();
    }
    os << ")";
    if (NodeProperties::IsTyped(n)) {
487
      Type static_type = NodeProperties::GetType(n);
488
      os << "  [Static type: " << static_type;
489 490
      Type feedback_type = GetInfo(n)->feedback_type();
      if (!feedback_type.IsInvalid() && feedback_type != static_type) {
491
        os << ", Feedback type: " << feedback_type;
492 493 494 495 496 497
      }
      os << "]";
    }
    os << std::endl;
  }

498
  Type Weaken(Node* node, Type previous_type, Type current_type) {
499
    // If the types have nothing to do with integers, return the types.
500
    Type const integer = type_cache_->kInteger;
501
    if (!previous_type.Maybe(integer)) {
502 503
      return current_type;
    }
504
    DCHECK(current_type.Maybe(integer));
505

506
    Type current_integer = Type::Intersect(current_type, integer, graph_zone());
507
    DCHECK(!current_integer.IsNone());
508
    Type previous_integer =
509
        Type::Intersect(previous_type, integer, graph_zone());
510
    DCHECK(!previous_integer.IsNone());
511 512 513 514 515 516

    // Once we start weakening a node, we should always weaken.
    if (!GetInfo(node)->weakened()) {
      // Only weaken if there is range involved; we should converge quickly
      // for all other types (the exception is a union of many constants,
      // but we currently do not increase the number of constants in unions).
517 518
      Type previous = previous_integer.GetRange();
      Type current = current_integer.GetRange();
519
      if (current.IsInvalid() || previous.IsInvalid()) {
520 521 522 523 524 525 526 527 528 529 530
        return current_type;
      }
      // Range is involved => we are weakening.
      GetInfo(node)->set_weakened();
    }

    return Type::Union(current_type,
                       op_typer_.WeakenRange(previous_integer, current_integer),
                       graph_zone());
  }

531
  // Generates a pre-order traversal of the nodes, starting with End.
532 533 534 535 536 537 538
  void GenerateTraversal() {
    ZoneStack<NodeState> stack(zone_);

    stack.push({graph()->end(), 0});
    GetInfo(graph()->end())->set_pushed();
    while (!stack.empty()) {
      NodeState& current = stack.top();
539
      Node* node = current.node;
540

541
      // If there is an unvisited input, push it and continue with that node.
542
      bool pushed_unvisited = false;
543 544
      while (current.input_index < node->InputCount()) {
        Node* input = node->InputAt(current.input_index);
545 546 547 548 549 550 551 552
        NodeInfo* input_info = GetInfo(input);
        current.input_index++;
        if (input_info->unvisited()) {
          input_info->set_pushed();
          stack.push({input, 0});
          pushed_unvisited = true;
          break;
        } else if (input_info->pushed()) {
553
          // Optimization for the Retype phase.
554
          // If we had already pushed (and not visited) an input, it means that
555 556 557 558
          // the current node will be visited in the Retype phase before one of
          // its inputs. If this happens, the current node might need to be
          // revisited.
          MarkAsPossibleRevisit(node, input);
559 560 561 562 563 564 565 566 567 568
        }
      }

      if (pushed_unvisited) continue;

      stack.pop();
      NodeInfo* info = GetInfo(node);
      info->set_visited();

      // Generate the traversal
569
      traversal_nodes_.push_back(node);
570 571 572
    }
  }

573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606
  void PushNodeToRevisitIfVisited(Node* node) {
    NodeInfo* info = GetInfo(node);
    if (info->visited()) {
      TRACE(" QUEUEING #%d: %s\n", node->id(), node->op()->mnemonic());
      info->set_queued();
      revisit_queue_.push(node);
    }
  }

  // Tries to update the feedback type of the node, as well as setting its
  // machine representation (in VisitNode). Returns true iff updating the
  // feedback type is successful.
  bool RetypeNode(Node* node) {
    NodeInfo* info = GetInfo(node);
    info->set_visited();
    bool updated = UpdateFeedbackType(node);
    TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
    VisitNode<RETYPE>(node, info->truncation(), nullptr);
    TRACE("  ==> output %s\n", MachineReprToString(info->representation()));
    return updated;
  }

  // Visits the node and marks it as visited. Inside of VisitNode, we might
  // change the truncation of one of our inputs (see EnqueueInput<PROPAGATE> for
  // this). If we change the truncation of an already visited node, we will add
  // it to the revisit queue.
  void PropagateTruncation(Node* node) {
    NodeInfo* info = GetInfo(node);
    info->set_visited();
    TRACE(" visit #%d: %s (trunc: %s)\n", node->id(), node->op()->mnemonic(),
          info->truncation().description());
    VisitNode<PROPAGATE>(node, info->truncation(), nullptr);
  }

607 608 609 610 611 612 613 614 615
  // Backward propagation of truncations to a fixpoint.
  void RunPropagatePhase() {
    TRACE("--{Propagate phase}--\n");
    ResetNodeInfoState();
    DCHECK(revisit_queue_.empty());

    // Process nodes in reverse post order, with End as the root.
    for (auto it = traversal_nodes_.crbegin(); it != traversal_nodes_.crend();
         ++it) {
616
      PropagateTruncation(*it);
617

618
      while (!revisit_queue_.empty()) {
619
        Node* node = revisit_queue_.front();
620
        revisit_queue_.pop();
621
        PropagateTruncation(node);
622 623 624
      }
    }
  }
625

626 627 628 629 630
  // Forward propagation of types from type feedback to a fixpoint.
  void RunRetypePhase() {
    TRACE("--{Retype phase}--\n");
    ResetNodeInfoState();
    DCHECK(revisit_queue_.empty());
631

632 633 634
    for (auto it = traversal_nodes_.cbegin(); it != traversal_nodes_.cend();
         ++it) {
      Node* node = *it;
635
      if (!RetypeNode(node)) continue;
636

637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
      auto revisit_it = might_need_revisit_.find(node);
      if (revisit_it == might_need_revisit_.end()) continue;

      for (Node* const user : revisit_it->second) {
        PushNodeToRevisitIfVisited(user);
      }

      // Process the revisit queue.
      while (!revisit_queue_.empty()) {
        Node* revisit_node = revisit_queue_.front();
        revisit_queue_.pop();
        if (!RetypeNode(revisit_node)) continue;
        // Here we need to check all uses since we can't easily know which
        // nodes will need to be revisited due to having an input which was
        // a revisited node.
        for (Node* const user : revisit_node->uses()) {
          PushNodeToRevisitIfVisited(user);
654 655 656 657 658 659 660 661
        }
      }
    }
  }

  // Lowering and change insertion phase.
  void RunLowerPhase(SimplifiedLowering* lowering) {
    TRACE("--{Lower phase}--\n");
662 663 664
    for (auto it = traversal_nodes_.cbegin(); it != traversal_nodes_.cend();
         ++it) {
      Node* node = *it;
665
      NodeInfo* info = GetInfo(node);
666
      TRACE(" visit #%d: %s\n", node->id(), node->op()->mnemonic());
667
      // Reuse {VisitNode()} so the representation rules are in one place.
668 669
      SourcePositionTable::Scope scope(
          source_positions_, source_positions_->GetSourcePosition(node));
670 671
      NodeOriginTable::Scope origin_scope(node_origins_, "simplified lowering",
                                          node);
672
      VisitNode<LOWER>(node, info->truncation(), lowering);
673 674 675 676 677 678 679 680
    }

    // Perform the final replacements.
    for (NodeVector::iterator i = replacements_.begin();
         i != replacements_.end(); ++i) {
      Node* node = *i;
      Node* replacement = *(++i);
      node->ReplaceUses(replacement);
681
      node->Kill();
682 683 684 685 686
      // We also need to replace the node in the rest of the vector.
      for (NodeVector::iterator j = i + 1; j != replacements_.end(); ++j) {
        ++j;
        if (*j == node) *j = replacement;
      }
687 688 689
    }
  }

690 691 692 693 694 695 696
  void Run(SimplifiedLowering* lowering) {
    GenerateTraversal();
    RunPropagatePhase();
    RunRetypePhase();
    RunLowerPhase(lowering);
  }

697 698 699 700
  // Just assert for Retype and Lower. Propagate specialized below.
  template <Phase T>
  void EnqueueInput(Node* use_node, int index,
                    UseInfo use_info = UseInfo::None()) {
701
    static_assert(retype<T>() || lower<T>(),
702 703 704 705
                  "This version of ProcessRemainingInputs has to be called in "
                  "the Retype or Lower phase.");
  }

706 707 708 709 710 711 712 713
  template <Phase T>
  static constexpr bool propagate() {
    return T == PROPAGATE;
  }

  template <Phase T>
  static constexpr bool retype() {
    return T == RETYPE;
714 715
  }

716 717 718 719
  template <Phase T>
  static constexpr bool lower() {
    return T == LOWER;
  }
720

721 722 723 724
  template <Phase T>
  void SetOutput(Node* node, MachineRepresentation representation,
                 Type restriction_type = Type::Any());

725
  Type GetUpperBound(Node* node) { return NodeProperties::GetType(node); }
726

727
  bool InputCannotBe(Node* node, Type type) {
728
    DCHECK_EQ(1, node->op()->ValueInputCount());
729
    return !GetUpperBound(node->InputAt(0)).Maybe(type);
730 731
  }

732
  bool InputIs(Node* node, Type type) {
733
    DCHECK_EQ(1, node->op()->ValueInputCount());
734
    return GetUpperBound(node->InputAt(0)).Is(type);
735 736
  }

737
  bool BothInputsAreSigned32(Node* node) {
738
    return BothInputsAre(node, Type::Signed32());
739 740 741
  }

  bool BothInputsAreUnsigned32(Node* node) {
742
    return BothInputsAre(node, Type::Unsigned32());
743 744
  }

745
  bool BothInputsAre(Node* node, Type type) {
746
    DCHECK_EQ(2, node->op()->ValueInputCount());
747 748
    return GetUpperBound(node->InputAt(0)).Is(type) &&
           GetUpperBound(node->InputAt(1)).Is(type);
749 750
  }

751 752 753 754 755
  bool IsNodeRepresentationTagged(Node* node) {
    MachineRepresentation representation = GetInfo(node)->representation();
    return IsAnyTagged(representation);
  }

756
  bool OneInputCannotBe(Node* node, Type type) {
757
    DCHECK_EQ(2, node->op()->ValueInputCount());
758 759
    return !GetUpperBound(node->InputAt(0)).Maybe(type) ||
           !GetUpperBound(node->InputAt(1)).Maybe(type);
760 761
  }

762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777
  void ChangeToDeadValue(Node* node, Node* effect, Node* control) {
    DCHECK(TypeOf(node).IsNone());
    // If the node is unreachable, insert an Unreachable node and mark the
    // value dead.
    // TODO(jarin,tebbi) Find a way to unify/merge this insertion with
    // InsertUnreachableIfNecessary.
    Node* unreachable = effect =
        graph()->NewNode(jsgraph_->common()->Unreachable(), effect, control);
    const Operator* dead_value =
        jsgraph_->common()->DeadValue(GetInfo(node)->representation());
    node->ReplaceInput(0, unreachable);
    node->TrimInputCount(dead_value->ValueInputCount());
    ReplaceEffectControlUses(node, effect, control);
    NodeProperties::ChangeOp(node, dead_value);
  }

778 779
  void ChangeToPureOp(Node* node, const Operator* new_op) {
    DCHECK(new_op->HasProperty(Operator::kPure));
780
    DCHECK_EQ(new_op->ValueInputCount(), node->op()->ValueInputCount());
781 782 783 784 785
    if (node->op()->EffectInputCount() > 0) {
      DCHECK_LT(0, node->op()->ControlInputCount());
      Node* control = NodeProperties::GetControlInput(node);
      Node* effect = NodeProperties::GetEffectInput(node);
      if (TypeOf(node).IsNone()) {
786 787
        ChangeToDeadValue(node, effect, control);
        return;
788 789 790 791 792 793 794 795 796 797
      }
      // Rewire the effect and control chains.
      node->TrimInputCount(new_op->ValueInputCount());
      ReplaceEffectControlUses(node, effect, control);
    } else {
      DCHECK_EQ(0, node->op()->ControlInputCount());
    }
    NodeProperties::ChangeOp(node, new_op);
  }

798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821
  void ChangeUnaryToPureBinaryOp(Node* node, const Operator* new_op,
                                 int new_input_index, Node* new_input) {
    DCHECK(new_op->HasProperty(Operator::kPure));
    DCHECK_EQ(new_op->ValueInputCount(), 2);
    DCHECK_EQ(node->op()->ValueInputCount(), 1);
    DCHECK_LE(0, new_input_index);
    DCHECK_LE(new_input_index, 1);
    if (node->op()->EffectInputCount() > 0) {
      DCHECK_LT(0, node->op()->ControlInputCount());
      Node* control = NodeProperties::GetControlInput(node);
      Node* effect = NodeProperties::GetEffectInput(node);
      if (TypeOf(node).IsNone()) {
        ChangeToDeadValue(node, effect, control);
        return;
      }
      node->TrimInputCount(node->op()->ValueInputCount());
      ReplaceEffectControlUses(node, effect, control);
    } else {
      DCHECK_EQ(0, node->op()->ControlInputCount());
    }
    node->InsertInput(jsgraph_->zone(), new_input_index, new_input);
    NodeProperties::ChangeOp(node, new_op);
  }

822 823 824 825
  // Converts input {index} of {node} according to given UseInfo {use},
  // assuming the type of the input is {input_type}. If {input_type} is null,
  // it takes the input from the input node {TypeOf(node->InputAt(index))}.
  void ConvertInput(Node* node, int index, UseInfo use,
826
                    Type input_type = Type::Invalid()) {
827
    // In the change phase, insert a change before the use if necessary.
828
    if (use.representation() == MachineRepresentation::kNone)
829
      return;  // No input requirement on the use.
830
    Node* input = node->InputAt(index);
831
    DCHECK_NOT_NULL(input);
832 833
    NodeInfo* input_info = GetInfo(input);
    MachineRepresentation input_rep = input_info->representation();
834 835
    if (input_rep != use.representation() ||
        use.type_check() != TypeCheckKind::kNone) {
836 837 838
      // Output representation doesn't match usage.
      TRACE("  change: #%d:%s(@%d #%d:%s) ", node->id(), node->op()->mnemonic(),
            index, input->id(), input->op()->mnemonic());
839 840 841 842
      TRACE("from %s to %s:%s\n",
            MachineReprToString(input_info->representation()),
            MachineReprToString(use.representation()),
            use.truncation().description());
843
      if (input_type.IsInvalid()) {
844 845
        input_type = TypeOf(input);
      }
846 847
      Node* n = changer_->GetRepresentationFor(input, input_rep, input_type,
                                               node, use);
848 849 850 851
      node->ReplaceInput(index, n);
    }
  }

852 853 854
  template <Phase T>
  void ProcessInput(Node* node, int index, UseInfo use);

855
  // Just assert for Retype and Lower. Propagate specialized below.
856 857
  template <Phase T>
  void ProcessRemainingInputs(Node* node, int index) {
858
    static_assert(retype<T>() || lower<T>(),
859 860 861 862 863 864
                  "This version of ProcessRemainingInputs has to be called in "
                  "the Retype or Lower phase.");
    DCHECK_GE(index, NodeProperties::PastValueIndex(node));
    DCHECK_GE(index, NodeProperties::PastContextIndex(node));
  }

865 866 867 868 869 870 871 872 873 874 875 876
  // Marks node as a possible revisit since it is a use of input that will be
  // visited before input is visited.
  void MarkAsPossibleRevisit(Node* node, Node* input) {
    auto it = might_need_revisit_.find(input);
    if (it == might_need_revisit_.end()) {
      it = might_need_revisit_.insert({input, ZoneVector<Node*>(zone())}).first;
    }
    it->second.push_back(node);
    TRACE(" Marking #%d: %s as needing revisit due to #%d: %s\n", node->id(),
          node->op()->mnemonic(), input->id(), input->op()->mnemonic());
  }

877 878
  // Just assert for Retype. Propagate and Lower specialized below.
  template <Phase T>
879
  void VisitInputs(Node* node) {
880
    static_assert(
881
        retype<T>(),
882
        "This version of VisitInputs has to be called in the Retype phase.");
883 884
  }

885
  template <Phase T>
886
  void VisitReturn(Node* node) {
887
    int first_effect_index = NodeProperties::FirstEffectIndex(node);
888
    // Visit integer slot count to pop
889
    ProcessInput<T>(node, 0, UseInfo::TruncatingWord32());
890 891

    // Visit value, context and frame state inputs as tagged.
892
    for (int i = 1; i < first_effect_index; i++) {
893
      ProcessInput<T>(node, i, UseInfo::AnyTagged());
894 895
    }
    // Only enqueue other inputs (effects, control).
896
    for (int i = first_effect_index; i < node->InputCount(); i++) {
897
      EnqueueInput<T>(node, i);
898 899 900
    }
  }

901
  // Helper for an unused node.
902
  template <Phase T>
903
  void VisitUnused(Node* node) {
904 905
    int first_effect_index = NodeProperties::FirstEffectIndex(node);
    for (int i = 0; i < first_effect_index; i++) {
906
      ProcessInput<T>(node, i, UseInfo::None());
907
    }
908
    ProcessRemainingInputs<T>(node, first_effect_index);
909
    if (lower<T>()) Kill(node);
910 911
  }

912
  // Helper for no-op node.
913
  template <Phase T>
914
  void VisitNoop(Node* node, Truncation truncation) {
915
    if (truncation.IsUnused()) return VisitUnused<T>(node);
916 917
    MachineRepresentation representation =
        GetOutputInfoForPhi(node, TypeOf(node), truncation);
918
    VisitUnop<T>(node, UseInfo(representation, truncation), representation);
919
    if (lower<T>()) DeferReplacement(node, node->InputAt(0));
920 921
  }

922
  // Helper for binops of the R x L -> O variety.
923
  template <Phase T>
924
  void VisitBinop(Node* node, UseInfo left_use, UseInfo right_use,
925
                  MachineRepresentation output,
926
                  Type restriction_type = Type::Any()) {
927
    DCHECK_EQ(2, node->op()->ValueInputCount());
928 929
    ProcessInput<T>(node, 0, left_use);
    ProcessInput<T>(node, 1, right_use);
930
    for (int i = 2; i < node->InputCount(); i++) {
931
      EnqueueInput<T>(node, i);
932
    }
933
    SetOutput<T>(node, output, restriction_type);
934 935
  }

936
  // Helper for binops of the I x I -> O variety.
937
  template <Phase T>
938
  void VisitBinop(Node* node, UseInfo input_use, MachineRepresentation output,
939
                  Type restriction_type = Type::Any()) {
940
    VisitBinop<T>(node, input_use, input_use, output, restriction_type);
941 942
  }

943
  template <Phase T>
944 945 946
  void VisitSpeculativeInt32Binop(Node* node) {
    DCHECK_EQ(2, node->op()->ValueInputCount());
    if (BothInputsAre(node, Type::NumberOrOddball())) {
947 948
      return VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                           MachineRepresentation::kWord32);
949
    }
950
    NumberOperationHint hint = NumberOperationHintOf(node->op());
951 952
    return VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
                         MachineRepresentation::kWord32);
953 954
  }

955
  // Helper for unops of the I -> O variety.
956
  template <Phase T>
957
  void VisitUnop(Node* node, UseInfo input_use, MachineRepresentation output,
958
                 Type restriction_type = Type::Any()) {
959
    DCHECK_EQ(1, node->op()->ValueInputCount());
960 961 962
    ProcessInput<T>(node, 0, input_use);
    ProcessRemainingInputs<T>(node, 1);
    SetOutput<T>(node, output, restriction_type);
963 964 965
  }

  // Helper for leaf nodes.
966
  template <Phase T>
967
  void VisitLeaf(Node* node, MachineRepresentation output) {
968
    DCHECK_EQ(0, node->InputCount());
969
    SetOutput<T>(node, output);
970 971 972
  }

  // Helpers for specific types of binops.
973 974

  template <Phase T>
975
  void VisitFloat64Binop(Node* node) {
976 977
    VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
                  MachineRepresentation::kFloat64);
978
  }
979 980

  template <Phase T>
981
  void VisitInt64Binop(Node* node) {
982
    VisitBinop<T>(node, UseInfo::Word64(), MachineRepresentation::kWord64);
983
  }
984 985

  template <Phase T>
986
  void VisitWord32TruncatingBinop(Node* node) {
987 988
    VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                  MachineRepresentation::kWord32);
989
  }
990

991
  // Infer representation for phi-like nodes.
992 993 994
  // The {node} parameter is only used to decide on the int64 representation.
  // Once the type system supports an external pointer type, the {node}
  // parameter can be removed.
995
  MachineRepresentation GetOutputInfoForPhi(Node* node, Type type,
996
                                            Truncation use) {
997
    // Compute the representation.
998
    if (type.Is(Type::None())) {
999
      return MachineRepresentation::kNone;
1000
    } else if (type.Is(Type::Signed32()) || type.Is(Type::Unsigned32())) {
1001
      return MachineRepresentation::kWord32;
1002
    } else if (type.Is(Type::NumberOrOddball()) && use.IsUsedAsWord32()) {
1003
      return MachineRepresentation::kWord32;
1004
    } else if (type.Is(Type::Boolean())) {
1005
      return MachineRepresentation::kBit;
1006 1007
    } else if (type.Is(Type::NumberOrOddball()) &&
               use.TruncatesOddballAndBigIntToNumber()) {
1008
      return MachineRepresentation::kFloat64;
1009
    } else if (type.Is(Type::Union(Type::SignedSmall(), Type::NaN(), zone()))) {
1010 1011 1012 1013 1014
      // TODO(turbofan): For Phis that return either NaN or some Smi, it's
      // beneficial to not go all the way to double, unless the uses are
      // double uses. For tagging that just means some potentially expensive
      // allocation code; we might want to do the same for -0 as well?
      return MachineRepresentation::kTagged;
1015
    } else if (type.Is(Type::Number())) {
1016
      return MachineRepresentation::kFloat64;
1017 1018
    } else if (type.Is(Type::BigInt()) && use.IsUsedAsWord64()) {
      return MachineRepresentation::kWord64;
1019 1020
    } else if (type.Is(Type::ExternalPointer()) ||
               type.Is(Type::SandboxedExternalPointer())) {
1021
      return MachineType::PointerRepresentation();
1022
    }
1023
    return MachineRepresentation::kTagged;
1024 1025 1026
  }

  // Helper for handling selects.
1027
  template <Phase T>
1028
  void VisitSelect(Node* node, Truncation truncation,
1029
                   SimplifiedLowering* lowering) {
1030
    DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
1031
    ProcessInput<T>(node, 0, UseInfo::Bool());
1032

1033 1034
    MachineRepresentation output =
        GetOutputInfoForPhi(node, TypeOf(node), truncation);
1035
    SetOutput<T>(node, output);
1036

1037
    if (lower<T>()) {
1038 1039
      // Update the select operator.
      SelectParameters p = SelectParametersOf(node->op());
1040 1041 1042
      if (output != p.representation()) {
        NodeProperties::ChangeOp(node,
                                 lowering->common()->Select(output, p.hint()));
1043 1044
      }
    }
1045
    // Convert inputs to the output representation of this phi, pass the
1046
    // truncation truncation along.
1047
    UseInfo input_use(output, truncation);
1048 1049
    ProcessInput<T>(node, 1, input_use);
    ProcessInput<T>(node, 2, input_use);
1050 1051
  }

1052
  // Helper for handling phis.
1053
  template <Phase T>
1054
  void VisitPhi(Node* node, Truncation truncation,
1055
                SimplifiedLowering* lowering) {
1056 1057
    MachineRepresentation output =
        GetOutputInfoForPhi(node, TypeOf(node), truncation);
1058 1059
    // Only set the output representation if not running with type
    // feedback. (Feedback typing will set the representation.)
1060
    SetOutput<T>(node, output);
1061

1062
    int values = node->op()->ValueInputCount();
1063
    if (lower<T>()) {
1064
      // Update the phi operator.
1065 1066
      if (output != PhiRepresentationOf(node->op())) {
        NodeProperties::ChangeOp(node, lowering->common()->Phi(output, values));
1067
      }
1068
    }
1069

1070
    // Convert inputs to the output representation of this phi, pass the
1071
    // truncation along.
1072
    UseInfo input_use(output, truncation);
1073
    for (int i = 0; i < node->InputCount(); i++) {
1074
      ProcessInput<T>(node, i, i < values ? input_use : UseInfo::None());
1075
    }
1076 1077
  }

1078
  template <Phase T>
1079 1080
  void VisitObjectIs(Node* node, Type type, SimplifiedLowering* lowering) {
    Type const input_type = TypeOf(node->InputAt(0));
1081
    if (input_type.Is(type)) {
1082
      VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
1083
      if (lower<T>()) {
1084 1085 1086
        DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
      }
    } else {
1087
      VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
1088
      if (lower<T>() && !input_type.Maybe(type)) {
1089 1090 1091 1092 1093
        DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
      }
    }
  }

1094
  template <Phase T>
1095
  void VisitCheck(Node* node, Type type, SimplifiedLowering* lowering) {
1096
    if (InputIs(node, type)) {
1097 1098
      VisitUnop<T>(node, UseInfo::AnyTagged(),
                   MachineRepresentation::kTaggedPointer);
1099
      if (lower<T>()) DeferReplacement(node, node->InputAt(0));
1100
    } else {
1101 1102 1103
      VisitUnop<T>(node,
                   UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
                   MachineRepresentation::kTaggedPointer);
1104 1105 1106
    }
  }

1107
  template <Phase T>
1108
  void VisitCall(Node* node, SimplifiedLowering* lowering) {
1109 1110
    auto call_descriptor = CallDescriptorOf(node->op());
    int params = static_cast<int>(call_descriptor->ParameterCount());
1111
    int value_input_count = node->op()->ValueInputCount();
1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124

    DCHECK_GT(value_input_count, 0);
    DCHECK_GE(value_input_count, params);

    // The target of the call.
    ProcessInput<T>(node, 0, UseInfo::Any());

    // For the parameters (indexes [1, ..., params]), propagate representation
    // information from call descriptor.
    for (int i = 1; i <= params; i++) {
      ProcessInput<T>(node, i,
                      TruncatingUseInfoFromRepresentation(
                          call_descriptor->GetInputType(i).representation()));
1125
    }
1126 1127 1128 1129 1130 1131 1132

    // Rest of the value inputs.
    for (int i = params + 1; i < value_input_count; i++) {
      ProcessInput<T>(node, i, UseInfo::AnyTagged());
    }

    // Effect and Control.
1133
    ProcessRemainingInputs<T>(node, value_input_count);
1134

1135
    if (call_descriptor->ReturnCount() > 0) {
1136
      SetOutput<T>(node, call_descriptor->GetReturnType(0).representation());
1137
    } else {
1138
      SetOutput<T>(node, MachineRepresentation::kTagged);
1139 1140 1141
    }
  }

1142
  void MaskShiftOperand(Node* node, Type rhs_type) {
1143
    if (!rhs_type.Is(type_cache_->kZeroToThirtyOne)) {
1144 1145 1146 1147 1148 1149 1150
      Node* const rhs = NodeProperties::GetValueInput(node, 1);
      node->ReplaceInput(1,
                         graph()->NewNode(jsgraph_->machine()->Word32And(), rhs,
                                          jsgraph_->Int32Constant(0x1F)));
    }
  }

1151
  static MachineSemantic DeoptValueSemanticOf(Type type) {
1152
    // We only need signedness to do deopt correctly.
1153
    if (type.Is(Type::Signed32())) {
1154
      return MachineSemantic::kInt32;
1155
    } else if (type.Is(Type::Unsigned32())) {
1156 1157 1158
      return MachineSemantic::kUint32;
    } else {
      return MachineSemantic::kAny;
1159
    }
1160 1161
  }

1162
  static MachineType DeoptMachineTypeOf(MachineRepresentation rep, Type type) {
1163
    if (type.IsNone()) {
1164 1165 1166 1167 1168 1169
      return MachineType::None();
    }
    // Do not distinguish between various Tagged variations.
    if (IsAnyTagged(rep)) {
      return MachineType::AnyTagged();
    }
1170
    if (rep == MachineRepresentation::kWord64) {
1171 1172 1173 1174
      if (type.Is(Type::BigInt())) {
        return MachineType::AnyTagged();
      }

1175
      DCHECK(type.Is(TypeCache::Get()->kSafeInteger));
1176 1177
      return MachineType(rep, MachineSemantic::kInt64);
    }
1178 1179 1180 1181 1182
    MachineType machine_type(rep, DeoptValueSemanticOf(type));
    DCHECK(machine_type.representation() != MachineRepresentation::kWord32 ||
           machine_type.semantic() == MachineSemantic::kInt32 ||
           machine_type.semantic() == MachineSemantic::kUint32);
    DCHECK(machine_type.representation() != MachineRepresentation::kBit ||
1183
           type.Is(Type::Boolean()));
1184 1185 1186
    return machine_type;
  }

1187
  template <Phase T>
1188
  void VisitStateValues(Node* node) {
1189
    if (propagate<T>()) {
1190
      for (int i = 0; i < node->InputCount(); i++) {
1191 1192 1193 1194 1195 1196 1197
        // When lowering 64 bit BigInts to Word64 representation, we have to
        // make sure they are rematerialized before deoptimization. By
        // propagating a AnyTagged use, the RepresentationChanger is going to
        // insert the necessary conversions.
        // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
        // truncated BigInts.
        if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
1198
          EnqueueInput<T>(node, i, UseInfo::AnyTagged());
1199
        } else {
1200
          EnqueueInput<T>(node, i, UseInfo::Any());
1201
        }
1202
      }
1203
    } else if (lower<T>()) {
1204 1205
      Zone* zone = jsgraph_->zone();
      ZoneVector<MachineType>* types =
1206
          zone->New<ZoneVector<MachineType>>(node->InputCount(), zone);
1207
      for (int i = 0; i < node->InputCount(); i++) {
1208
        Node* input = node->InputAt(i);
1209 1210 1211
        // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
        // truncated BigInts.
        if (TypeOf(input).Is(Type::BigInt())) {
1212
          ConvertInput(node, i, UseInfo::AnyTagged());
1213 1214
        }

1215 1216
        (*types)[i] =
            DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1217
      }
1218 1219 1220
      SparseInputMask mask = SparseInputMaskOf(node->op());
      NodeProperties::ChangeOp(
          node, jsgraph_->common()->TypedStateValues(types, mask));
1221
    }
1222
    SetOutput<T>(node, MachineRepresentation::kTagged);
1223 1224
  }

1225
  template <Phase T>
1226 1227 1228 1229
  void VisitFrameState(Node* node) {
    DCHECK_EQ(5, node->op()->ValueInputCount());
    DCHECK_EQ(1, OperatorProperties::GetFrameStateInputCount(node->op()));

1230 1231
    ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // Parameters.
    ProcessInput<T>(node, 1, UseInfo::AnyTagged());  // Registers.
1232

1233 1234 1235
    // Accumulator is a special flower - we need to remember its type in
    // a singleton typed-state-values node (as if it was a singleton
    // state-values node).
1236
    Node* accumulator = node->InputAt(2);
1237
    if (propagate<T>()) {
1238 1239 1240
      // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
      // truncated BigInts.
      if (TypeOf(accumulator).Is(Type::BigInt())) {
1241
        EnqueueInput<T>(node, 2, UseInfo::AnyTagged());
1242
      } else {
1243
        EnqueueInput<T>(node, 2, UseInfo::Any());
1244
      }
1245
    } else if (lower<T>()) {
1246 1247 1248 1249 1250
      // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
      // truncated BigInts.
      if (TypeOf(accumulator).Is(Type::BigInt())) {
        ConvertInput(node, 2, UseInfo::AnyTagged());
      }
1251 1252 1253 1254 1255
      Zone* zone = jsgraph_->zone();
      if (accumulator == jsgraph_->OptimizedOutConstant()) {
        node->ReplaceInput(2, jsgraph_->SingleDeadTypedStateValues());
      } else {
        ZoneVector<MachineType>* types =
1256
            zone->New<ZoneVector<MachineType>>(1, zone);
1257 1258 1259 1260 1261 1262
        (*types)[0] = DeoptMachineTypeOf(GetInfo(accumulator)->representation(),
                                         TypeOf(accumulator));

        node->ReplaceInput(
            2, jsgraph_->graph()->NewNode(jsgraph_->common()->TypedStateValues(
                                              types, SparseInputMask::Dense()),
1263
                                          node->InputAt(2)));
1264 1265 1266
      }
    }

1267 1268 1269 1270
    ProcessInput<T>(node, 3, UseInfo::AnyTagged());  // Context.
    ProcessInput<T>(node, 4, UseInfo::AnyTagged());  // Closure.
    ProcessInput<T>(node, 5, UseInfo::AnyTagged());  // Outer frame state.
    return SetOutput<T>(node, MachineRepresentation::kTagged);
1271 1272
  }

1273
  template <Phase T>
1274
  void VisitObjectState(Node* node) {
1275
    if (propagate<T>()) {
1276
      for (int i = 0; i < node->InputCount(); i++) {
1277 1278 1279
        // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
        // truncated BigInts.
        if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
1280
          EnqueueInput<T>(node, i, UseInfo::AnyTagged());
1281
        } else {
1282
          EnqueueInput<T>(node, i, UseInfo::Any());
1283
        }
1284
      }
1285
    } else if (lower<T>()) {
1286 1287
      Zone* zone = jsgraph_->zone();
      ZoneVector<MachineType>* types =
1288
          zone->New<ZoneVector<MachineType>>(node->InputCount(), zone);
1289 1290
      for (int i = 0; i < node->InputCount(); i++) {
        Node* input = node->InputAt(i);
1291 1292
        (*types)[i] =
            DeoptMachineTypeOf(GetInfo(input)->representation(), TypeOf(input));
1293 1294 1295 1296 1297
        // TODO(nicohartmann): Remove, once the deoptimizer can rematerialize
        // truncated BigInts.
        if (TypeOf(node->InputAt(i)).Is(Type::BigInt())) {
          ConvertInput(node, i, UseInfo::AnyTagged());
        }
1298
      }
1299 1300
      NodeProperties::ChangeOp(node, jsgraph_->common()->TypedObjectState(
                                         ObjectIdOf(node->op()), types));
1301
    }
1302
    SetOutput<T>(node, MachineRepresentation::kTagged);
1303 1304
  }

1305
  const Operator* Int32Op(Node* node) {
1306 1307 1308
    return changer_->Int32OperatorFor(node->opcode());
  }

1309 1310 1311 1312
  const Operator* Int32OverflowOp(Node* node) {
    return changer_->Int32OverflowOperatorFor(node->opcode());
  }

1313 1314 1315 1316
  const Operator* Int64Op(Node* node) {
    return changer_->Int64OperatorFor(node->opcode());
  }

1317
  const Operator* Uint32Op(Node* node) {
1318 1319 1320
    return changer_->Uint32OperatorFor(node->opcode());
  }

1321 1322 1323 1324
  const Operator* Uint32OverflowOp(Node* node) {
    return changer_->Uint32OverflowOperatorFor(node->opcode());
  }

1325
  const Operator* Float64Op(Node* node) {
1326 1327 1328
    return changer_->Float64OperatorFor(node->opcode());
  }

1329 1330
  WriteBarrierKind WriteBarrierKindFor(
      BaseTaggedness base_taggedness,
1331
      MachineRepresentation field_representation, Type field_type,
1332
      MachineRepresentation value_representation, Node* value) {
1333
    if (base_taggedness == kTaggedBase &&
1334
        CanBeTaggedPointer(field_representation)) {
1335
      Type value_type = NodeProperties::GetType(value);
1336
      if (value_representation == MachineRepresentation::kTaggedSigned) {
1337 1338 1339
        // Write barriers are only for stores of heap objects.
        return kNoWriteBarrier;
      }
1340 1341
      if (field_type.Is(Type::BooleanOrNullOrUndefined()) ||
          value_type.Is(Type::BooleanOrNullOrUndefined())) {
1342 1343 1344 1345
        // Write barriers are not necessary when storing true, false, null or
        // undefined, because these special oddballs are always in the root set.
        return kNoWriteBarrier;
      }
1346
      if (value_type.IsHeapConstant()) {
1347
        RootIndex root_index;
1348 1349 1350
        const RootsTable& roots_table = jsgraph_->isolate()->roots_table();
        if (roots_table.IsRootHandle(value_type.AsHeapConstant()->Value(),
                                     &root_index)) {
1351
          if (RootsTable::IsImmortalImmovable(root_index)) {
1352 1353 1354
            // Write barriers are unnecessary for immortal immovable roots.
            return kNoWriteBarrier;
          }
1355
        }
1356
      }
1357
      if (field_representation == MachineRepresentation::kTaggedPointer ||
1358
          value_representation == MachineRepresentation::kTaggedPointer) {
1359 1360 1361 1362
        // Write barriers for heap objects are cheaper.
        return kPointerWriteBarrier;
      }
      NumberMatcher m(value);
1363 1364
      if (m.HasResolvedValue()) {
        if (IsSmiDouble(m.ResolvedValue())) {
1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378
          // Storing a smi doesn't need a write barrier.
          return kNoWriteBarrier;
        }
        // The NumberConstant will be represented as HeapNumber.
        return kPointerWriteBarrier;
      }
      return kFullWriteBarrier;
    }
    return kNoWriteBarrier;
  }

  WriteBarrierKind WriteBarrierKindFor(
      BaseTaggedness base_taggedness,
      MachineRepresentation field_representation, int field_offset,
1379
      Type field_type, MachineRepresentation value_representation,
1380
      Node* value) {
1381 1382 1383 1384 1385 1386 1387 1388
    WriteBarrierKind write_barrier_kind =
        WriteBarrierKindFor(base_taggedness, field_representation, field_type,
                            value_representation, value);
    if (write_barrier_kind != kNoWriteBarrier) {
      if (base_taggedness == kTaggedBase &&
          field_offset == HeapObject::kMapOffset) {
        write_barrier_kind = kMapWriteBarrier;
      }
1389
    }
1390
    return write_barrier_kind;
1391 1392
  }

1393 1394 1395 1396 1397 1398
  Graph* graph() const { return jsgraph_->graph(); }
  CommonOperatorBuilder* common() const { return jsgraph_->common(); }
  SimplifiedOperatorBuilder* simplified() const {
    return jsgraph_->simplified();
  }

1399
  void LowerToCheckedInt32Mul(Node* node, Truncation truncation,
1400
                              Type input0_type, Type input1_type) {
1401 1402 1403
    // If one of the inputs is positive and/or truncation is being applied,
    // there is no need to return -0.
    CheckForMinusZeroMode mz_mode =
1404
        truncation.IdentifiesZeroAndMinusZero() ||
1405 1406
                IsSomePositiveOrderedNumber(input0_type) ||
                IsSomePositiveOrderedNumber(input1_type)
1407 1408 1409 1410 1411
            ? CheckForMinusZeroMode::kDontCheckForMinusZero
            : CheckForMinusZeroMode::kCheckForMinusZero;
    NodeProperties::ChangeOp(node, simplified()->CheckedInt32Mul(mz_mode));
  }

1412 1413 1414 1415 1416 1417
  void ChangeToInt32OverflowOp(Node* node) {
    NodeProperties::ChangeOp(node, Int32OverflowOp(node));
  }

  void ChangeToUint32OverflowOp(Node* node) {
    NodeProperties::ChangeOp(node, Uint32OverflowOp(node));
1418 1419
  }

1420
  template <Phase T>
1421 1422
  void VisitSpeculativeIntegerAdditiveOp(Node* node, Truncation truncation,
                                         SimplifiedLowering* lowering) {
1423 1424
    Type left_upper = GetUpperBound(node->InputAt(0));
    Type right_upper = GetUpperBound(node->InputAt(1));
1425

1426 1427
    if (left_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
        right_upper.Is(type_cache_->kAdditiveSafeIntegerOrMinusZero)) {
1428 1429
      // Only eliminate the node if its typing rule can be satisfied, namely
      // that a safe integer is produced.
1430
      if (truncation.IsUnused()) return VisitUnused<T>(node);
1431

1432 1433 1434
      // If we know how to interpret the result or if the users only care
      // about the low 32-bits, we can truncate to Word32 do a wrapping
      // addition.
1435 1436
      if (GetUpperBound(node).Is(Type::Signed32()) ||
          GetUpperBound(node).Is(Type::Unsigned32()) ||
1437 1438
          truncation.IsUsedAsWord32()) {
        // => Int32Add/Sub
1439
        VisitWord32TruncatingBinop<T>(node);
1440
        if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
1441 1442
        return;
      }
1443 1444
    }

1445 1446
    // Try to use type feedback.
    NumberOperationHint hint = NumberOperationHintOf(node->op());
1447
    DCHECK_EQ(hint, NumberOperationHint::kSignedSmall);
1448

1449 1450
    Type left_feedback_type = TypeOf(node->InputAt(0));
    Type right_feedback_type = TypeOf(node->InputAt(1));
1451 1452 1453 1454 1455 1456 1457

    // Using Signed32 as restriction type amounts to promising there won't be
    // signed overflow. This is incompatible with relying on a Word32
    // truncation in order to skip the overflow check.
    Type const restriction =
        truncation.IsUsedAsWord32() ? Type::Any() : Type::Signed32();

1458 1459
    // Handle the case when no int32 checks on inputs are necessary (but
    // an overflow check is needed on the output). Note that we do not
1460 1461 1462 1463 1464 1465 1466 1467
    // have to do any check if at most one side can be minus zero. For
    // subtraction we need to handle the case of -0 - 0 properly, since
    // that can produce -0.
    Type left_constraint_type =
        node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd
            ? Type::Signed32OrMinusZero()
            : Type::Signed32();
    if (left_upper.Is(left_constraint_type) &&
1468 1469
        right_upper.Is(Type::Signed32OrMinusZero()) &&
        (left_upper.Is(Type::Signed32()) || right_upper.Is(Type::Signed32()))) {
1470
      VisitBinop<T>(node, UseInfo::TruncatingWord32(),
1471
                    MachineRepresentation::kWord32, restriction);
1472 1473 1474 1475 1476 1477 1478
    } else {
      // If the output's truncation is identify-zeros, we can pass it
      // along. Moreover, if the operation is addition and we know the
      // right-hand side is not minus zero, we do not have to distinguish
      // between 0 and -0.
      IdentifyZeros left_identify_zeros = truncation.identify_zeros();
      if (node->opcode() == IrOpcode::kSpeculativeSafeIntegerAdd &&
1479
          !right_feedback_type.Maybe(Type::MinusZero())) {
1480
        left_identify_zeros = kIdentifyZeros;
1481
      }
1482
      UseInfo left_use = CheckedUseInfoAsWord32FromHint(hint, FeedbackSource(),
1483
                                                        left_identify_zeros);
1484 1485 1486 1487
      // For CheckedInt32Add and CheckedInt32Sub, we don't need to do
      // a minus zero check for the right hand side, since we already
      // know that the left hand side is a proper Signed32 value,
      // potentially guarded by a check.
1488
      UseInfo right_use = CheckedUseInfoAsWord32FromHint(hint, FeedbackSource(),
1489
                                                         kIdentifyZeros);
1490
      VisitBinop<T>(node, left_use, right_use, MachineRepresentation::kWord32,
1491
                    restriction);
1492
    }
1493

1494
    if (lower<T>()) {
1495 1496
      if (truncation.IsUsedAsWord32() ||
          !CanOverflowSigned32(node->op(), left_feedback_type,
1497 1498
                               right_feedback_type, type_cache_,
                               graph_zone())) {
1499 1500 1501 1502 1503
        ChangeToPureOp(node, Int32Op(node));

      } else {
        ChangeToInt32OverflowOp(node);
      }
1504
    }
1505
    return;
1506 1507
  }

1508
  template <Phase T>
1509 1510
  void VisitSpeculativeAdditiveOp(Node* node, Truncation truncation,
                                  SimplifiedLowering* lowering) {
1511
    if (BothInputsAre(node, type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
1512 1513
        (GetUpperBound(node).Is(Type::Signed32()) ||
         GetUpperBound(node).Is(Type::Unsigned32()) ||
1514 1515
         truncation.IsUsedAsWord32())) {
      // => Int32Add/Sub
1516
      VisitWord32TruncatingBinop<T>(node);
1517
      if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
1518 1519 1520 1521
      return;
    }

    // default case => Float64Add/Sub
1522 1523 1524 1525
    VisitBinop<T>(node,
                  UseInfo::CheckedNumberOrOddballAsFloat64(kDistinguishZeros,
                                                           FeedbackSource()),
                  MachineRepresentation::kFloat64, Type::Number());
1526
    if (lower<T>()) {
1527 1528 1529 1530 1531
      ChangeToPureOp(node, Float64Op(node));
    }
    return;
  }

1532
  template <Phase T>
1533 1534 1535 1536
  void VisitSpeculativeNumberModulus(Node* node, Truncation truncation,
                                     SimplifiedLowering* lowering) {
    if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN()) &&
        (truncation.IsUsedAsWord32() ||
1537
         NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1538
      // => unsigned Uint32Mod
1539
      VisitWord32TruncatingBinop<T>(node);
1540
      if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
1541 1542 1543 1544
      return;
    }
    if (BothInputsAre(node, Type::Signed32OrMinusZeroOrNaN()) &&
        (truncation.IsUsedAsWord32() ||
1545
         NodeProperties::GetType(node).Is(Type::Signed32()))) {
1546
      // => signed Int32Mod
1547
      VisitWord32TruncatingBinop<T>(node);
1548
      if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1549 1550 1551 1552 1553 1554 1555 1556 1557
      return;
    }

    // Try to use type feedback.
    NumberOperationHint hint = NumberOperationHintOf(node->op());

    // Handle the case when no uint32 checks on inputs are necessary
    // (but an overflow check is needed on the output).
    if (BothInputsAreUnsigned32(node)) {
1558
      if (hint == NumberOperationHint::kSignedSmall) {
1559 1560
        VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                      MachineRepresentation::kWord32, Type::Unsigned32());
1561
        if (lower<T>()) ChangeToUint32OverflowOp(node);
1562 1563 1564 1565 1566 1567 1568 1569
        return;
      }
    }

    // Handle the case when no int32 checks on inputs are necessary
    // (but an overflow check is needed on the output).
    if (BothInputsAre(node, Type::Signed32())) {
      // If both the inputs the feedback are int32, use the overflow op.
1570
      if (hint == NumberOperationHint::kSignedSmall) {
1571 1572
        VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                      MachineRepresentation::kWord32, Type::Signed32());
1573
        if (lower<T>()) ChangeToInt32OverflowOp(node);
1574 1575 1576 1577
        return;
      }
    }

1578
    if (hint == NumberOperationHint::kSignedSmall) {
1579
      // If the result is truncated, we only need to check the inputs.
1580 1581 1582 1583 1584
      // For the left hand side we just propagate the identify zeros
      // mode of the {truncation}; and for modulus the sign of the
      // right hand side doesn't matter anyways, so in particular there's
      // no observable difference between a 0 and a -0 then.
      UseInfo const lhs_use = CheckedUseInfoAsWord32FromHint(
1585
          hint, FeedbackSource(), truncation.identify_zeros());
1586
      UseInfo const rhs_use = CheckedUseInfoAsWord32FromHint(
1587
          hint, FeedbackSource(), kIdentifyZeros);
1588
      if (truncation.IsUsedAsWord32()) {
1589
        VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32);
1590
        if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1591
      } else if (BothInputsAre(node, Type::Unsigned32OrMinusZeroOrNaN())) {
1592 1593
        VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
                      Type::Unsigned32());
1594
        if (lower<T>()) ChangeToUint32OverflowOp(node);
1595
      } else {
1596 1597
        VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kWord32,
                      Type::Signed32());
1598
        if (lower<T>()) ChangeToInt32OverflowOp(node);
1599 1600 1601 1602
      }
      return;
    }

1603 1604
    if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
        TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
1605
        (truncation.IsUsedAsWord32() ||
1606
         NodeProperties::GetType(node).Is(Type::Unsigned32()))) {
1607 1608
      VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                    MachineRepresentation::kWord32, Type::Number());
1609
      if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
1610 1611
      return;
    }
1612 1613
    if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
        TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
1614
        (truncation.IsUsedAsWord32() ||
1615
         NodeProperties::GetType(node).Is(Type::Signed32()))) {
1616 1617
      VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                    MachineRepresentation::kWord32, Type::Number());
1618
      if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
1619 1620
      return;
    }
1621

1622
    // default case => Float64Mod
1623 1624 1625 1626 1627
    // For the left hand side we just propagate the identify zeros
    // mode of the {truncation}; and for modulus the sign of the
    // right hand side doesn't matter anyways, so in particular there's
    // no observable difference between a 0 and a -0 then.
    UseInfo const lhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1628
        truncation.identify_zeros(), FeedbackSource());
1629
    UseInfo const rhs_use = UseInfo::CheckedNumberOrOddballAsFloat64(
1630
        kIdentifyZeros, FeedbackSource());
1631 1632
    VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kFloat64,
                  Type::Number());
1633
    if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
1634 1635 1636
    return;
  }

1637 1638
  // Just assert for Propagate and Retype. Lower specialized below.
  template <Phase T>
1639
  void InsertUnreachableIfNecessary(Node* node) {
1640 1641 1642
    static_assert(propagate<T>() || retype<T>(),
                  "This version of InsertUnreachableIfNecessary has to be "
                  "called in the Propagate or Retype phase.");
1643 1644
  }

1645
  template <Phase T>
1646
  void VisitCheckBounds(Node* node, SimplifiedLowering* lowering) {
1647 1648
    CheckBoundsParameters const& p = CheckBoundsParametersOf(node->op());
    FeedbackSource const& feedback = p.check_parameters().feedback();
1649 1650
    Type const index_type = TypeOf(node->InputAt(0));
    Type const length_type = TypeOf(node->InputAt(1));
1651 1652 1653 1654 1655 1656

    // Conversions, if requested and needed, will be handled by the
    // representation changer, not by the lower-level Checked*Bounds operators.
    CheckBoundsFlags new_flags =
        p.flags().without(CheckBoundsFlag::kConvertStringAndMinusZero);

1657
    if (length_type.Is(Type::Unsigned31())) {
1658 1659 1660 1661 1662 1663
      if (index_type.Is(Type::Integral32()) ||
          (index_type.Is(Type::Integral32OrMinusZero()) &&
           p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero)) {
        // Map the values in the [-2^31,-1] range to the [2^31,2^32-1] range,
        // which will be considered out-of-bounds because the {length_type} is
        // limited to Unsigned31. This also converts -0 to 0.
1664 1665
        VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                      MachineRepresentation::kWord32);
1666
        if (lower<T>()) {
1667 1668 1669 1670 1671 1672 1673
          if (lowering->poisoning_level_ ==
                  PoisoningMitigationLevel::kDontPoison &&
              (index_type.IsNone() || length_type.IsNone() ||
               (index_type.Min() >= 0.0 &&
                index_type.Max() < length_type.Min()))) {
            // The bounds check is redundant if we already know that
            // the index is within the bounds of [0.0, length[.
1674 1675
            // TODO(neis): Move this into TypedOptimization?
            new_flags |= CheckBoundsFlag::kAbortOnOutOfBounds;
1676
          }
1677
          NodeProperties::ChangeOp(
1678
              node, simplified()->CheckedUint32Bounds(feedback, new_flags));
1679
        }
1680
      } else if (p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero) {
1681 1682
        VisitBinop<T>(node, UseInfo::CheckedTaggedAsArrayIndex(feedback),
                      UseInfo::Word(), MachineType::PointerRepresentation());
1683
        if (lower<T>()) {
1684 1685
          if (jsgraph_->machine()->Is64()) {
            NodeProperties::ChangeOp(
1686
                node, simplified()->CheckedUint64Bounds(feedback, new_flags));
1687 1688
          } else {
            NodeProperties::ChangeOp(
1689
                node, simplified()->CheckedUint32Bounds(feedback, new_flags));
1690
          }
1691
        }
1692 1693 1694 1695 1696 1697 1698 1699
      } else {
        VisitBinop<T>(
            node, UseInfo::CheckedSigned32AsWord32(kDistinguishZeros, feedback),
            UseInfo::TruncatingWord32(), MachineRepresentation::kWord32);
        if (lower<T>()) {
          NodeProperties::ChangeOp(
              node, simplified()->CheckedUint32Bounds(feedback, new_flags));
        }
1700 1701
      }
    } else {
1702
      CHECK(length_type.Is(type_cache_->kPositiveSafeInteger));
1703 1704 1705 1706
      IdentifyZeros zero_handling =
          (p.flags() & CheckBoundsFlag::kConvertStringAndMinusZero)
              ? kIdentifyZeros
              : kDistinguishZeros;
1707
      VisitBinop<T>(node,
1708
                    UseInfo::CheckedSigned64AsWord64(zero_handling, feedback),
1709
                    UseInfo::Word64(), MachineRepresentation::kWord64);
1710
      if (lower<T>()) {
1711
        NodeProperties::ChangeOp(
1712
            node, simplified()->CheckedUint64Bounds(feedback, new_flags));
1713 1714 1715 1716
      }
    }
  }

1717 1718 1719
  static MachineType MachineTypeFor(CTypeInfo::Type type) {
    switch (type) {
      case CTypeInfo::Type::kVoid:
1720
        return MachineType::AnyTagged();
1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734
      case CTypeInfo::Type::kBool:
        return MachineType::Bool();
      case CTypeInfo::Type::kInt32:
        return MachineType::Int32();
      case CTypeInfo::Type::kUint32:
        return MachineType::Uint32();
      case CTypeInfo::Type::kInt64:
        return MachineType::Int64();
      case CTypeInfo::Type::kUint64:
        return MachineType::Uint64();
      case CTypeInfo::Type::kFloat32:
        return MachineType::Float32();
      case CTypeInfo::Type::kFloat64:
        return MachineType::Float64();
1735 1736
      case CTypeInfo::Type::kV8Value:
        return MachineType::AnyTagged();
1737 1738 1739 1740 1741 1742 1743 1744 1745 1746 1747 1748 1749
    }
  }

  UseInfo UseInfoForFastApiCallArgument(CTypeInfo::Type type,
                                        FeedbackSource const& feedback) {
    switch (type) {
      case CTypeInfo::Type::kVoid:
        UNREACHABLE();
      case CTypeInfo::Type::kBool:
        return UseInfo::Bool();
      case CTypeInfo::Type::kInt32:
      case CTypeInfo::Type::kUint32:
        return UseInfo::CheckedNumberAsWord32(feedback);
1750 1751
      // TODO(mslekova): We deopt for unsafe integers, but ultimately we want
      // to make this less restrictive in order to stay on the fast path.
1752
      case CTypeInfo::Type::kInt64:
1753
      case CTypeInfo::Type::kUint64:
1754
        return UseInfo::CheckedSigned64AsWord64(kIdentifyZeros, feedback);
1755
      case CTypeInfo::Type::kFloat32:
1756
      case CTypeInfo::Type::kFloat64:
1757
        return UseInfo::CheckedNumberAsFloat64(kDistinguishZeros, feedback);
1758 1759
      case CTypeInfo::Type::kV8Value:
        return UseInfo::AnyTagged();
1760 1761 1762 1763 1764
    }
  }

  static constexpr int kInitialArgumentsCount = 10;

1765
  template <Phase T>
1766 1767 1768 1769 1770 1771 1772 1773 1774 1775
  void VisitFastApiCall(Node* node, SimplifiedLowering* lowering) {
    FastApiCallParameters const& op_params =
        FastApiCallParametersOf(node->op());
    const CFunctionInfo* c_signature = op_params.signature();
    const int c_arg_count = c_signature->ArgumentCount();
    CallDescriptor* call_descriptor = op_params.descriptor();
    int js_arg_count = static_cast<int>(call_descriptor->ParameterCount());
    const int value_input_count = node->op()->ValueInputCount();
    CHECK_EQ(FastApiCallNode::ArityForArgc(c_arg_count, js_arg_count),
             value_input_count);
1776 1777

    base::SmallVector<UseInfo, kInitialArgumentsCount> arg_use_info(
1778
        c_arg_count);
1779
    // The target of the fast call.
1780
    ProcessInput<T>(node, 0, UseInfo::Word());
1781
    // Propagate representation information from TypeInfo.
1782
    for (int i = 0; i < c_arg_count; i++) {
1783
      arg_use_info[i] = UseInfoForFastApiCallArgument(
1784 1785 1786
          c_signature->ArgumentInfo(i).GetType(), op_params.feedback());
      ProcessInput<T>(node, i + FastApiCallNode::kFastTargetInputCount,
                      arg_use_info[i]);
1787 1788
    }

1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804
    // The call code for the slow call.
    ProcessInput<T>(node, c_arg_count + FastApiCallNode::kFastTargetInputCount,
                    UseInfo::AnyTagged());
    for (int i = 1; i <= js_arg_count; i++) {
      ProcessInput<T>(node,
                      c_arg_count + FastApiCallNode::kFastTargetInputCount + i,
                      TruncatingUseInfoFromRepresentation(
                          call_descriptor->GetInputType(i).representation()));
    }
    for (int i = c_arg_count + FastApiCallNode::kFastTargetInputCount +
                 js_arg_count;
         i < value_input_count; ++i) {
      ProcessInput<T>(node, i, UseInfo::AnyTagged());
    }
    ProcessRemainingInputs<T>(node, value_input_count);

1805 1806
    MachineType return_type =
        MachineTypeFor(c_signature->ReturnInfo().GetType());
1807
    SetOutput<T>(node, return_type.representation());
1808 1809
  }

1810 1811
  // Dispatching routine for visiting the node {node} with the usage {use}.
  // Depending on the operator, propagate new usage info to the inputs.
1812
  template <Phase T>
1813
  void VisitNode(Node* node, Truncation truncation,
1814
                 SimplifiedLowering* lowering) {
1815
    tick_counter_->TickAndMaybeEnterSafepoint();
1816

1817 1818 1819
    // Unconditionally eliminate unused pure nodes (only relevant if there's
    // a pure operation in between two effectful ones, where the last one
    // is unused).
1820 1821 1822
    // Note: We must not do this for constants, as they are cached and we
    // would thus kill the cached {node} during lowering (i.e. replace all
    // uses with Dead), but at that point some node lowering might have
1823 1824
    // already taken the constant {node} from the cache (while it was not
    // yet killed) and we would afterwards replace that use with Dead as well.
1825
    if (node->op()->ValueInputCount() > 0 &&
1826
        node->op()->HasProperty(Operator::kPure) && truncation.IsUnused()) {
1827
      return VisitUnused<T>(node);
1828
    }
1829

1830
    if (lower<T>()) InsertUnreachableIfNecessary<T>(node);
1831

1832 1833 1834 1835 1836
    switch (node->opcode()) {
      //------------------------------------------------------------------
      // Common operators.
      //------------------------------------------------------------------
      case IrOpcode::kStart:
1837 1838 1839
        // We use Start as a terminator for the frame state chain, so even
        // tho Start doesn't really produce a value, we have to say Tagged
        // here, otherwise the input conversion will fail.
1840
        return VisitLeaf<T>(node, MachineRepresentation::kTagged);
1841
      case IrOpcode::kParameter:
1842
        return VisitUnop<T>(node, UseInfo::None(),
1843 1844 1845
                            linkage()
                                ->GetParameterType(ParameterIndexOf(node->op()))
                                .representation());
1846
      case IrOpcode::kInt32Constant:
1847
        return VisitLeaf<T>(node, MachineRepresentation::kWord32);
1848
      case IrOpcode::kInt64Constant:
1849
        return VisitLeaf<T>(node, MachineRepresentation::kWord64);
1850
      case IrOpcode::kExternalConstant:
1851
        return VisitLeaf<T>(node, MachineType::PointerRepresentation());
1852
      case IrOpcode::kNumberConstant: {
1853
        double const value = OpParameter<double>(node->op());
1854 1855
        int value_as_int;
        if (DoubleToSmiInteger(value, &value_as_int)) {
1856 1857
          VisitLeaf<T>(node, MachineRepresentation::kTaggedSigned);
          if (lower<T>()) {
1858 1859 1860 1861 1862
            intptr_t smi = bit_cast<intptr_t>(Smi::FromInt(value_as_int));
            DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(smi));
          }
          return;
        }
1863
        VisitLeaf<T>(node, MachineRepresentation::kTagged);
1864 1865
        return;
      }
1866
      case IrOpcode::kHeapConstant:
1867
      case IrOpcode::kDelayedStringConstant:
1868
        return VisitLeaf<T>(node, MachineRepresentation::kTaggedPointer);
1869
      case IrOpcode::kPointerConstant: {
1870 1871
        VisitLeaf<T>(node, MachineType::PointerRepresentation());
        if (lower<T>()) {
1872
          intptr_t const value = OpParameter<intptr_t>(node->op());
1873 1874 1875 1876
          DeferReplacement(node, lowering->jsgraph()->IntPtrConstant(value));
        }
        return;
      }
1877

1878
      case IrOpcode::kBranch: {
1879
        DCHECK(TypeOf(node->InputAt(0)).Is(Type::Boolean()));
1880
        ProcessInput<T>(node, 0, UseInfo::Bool());
1881
        EnqueueInput<T>(node, NodeProperties::FirstControlIndex(node));
1882
        return;
1883
      }
1884
      case IrOpcode::kSwitch:
1885
        ProcessInput<T>(node, 0, UseInfo::TruncatingWord32());
1886
        EnqueueInput<T>(node, NodeProperties::FirstControlIndex(node));
1887
        return;
1888
      case IrOpcode::kSelect:
1889
        return VisitSelect<T>(node, truncation, lowering);
1890
      case IrOpcode::kPhi:
1891
        return VisitPhi<T>(node, truncation, lowering);
1892
      case IrOpcode::kCall:
1893
        return VisitCall<T>(node, lowering);
1894

1895 1896 1897
      //------------------------------------------------------------------
      // JavaScript operators.
      //------------------------------------------------------------------
1898
      case IrOpcode::kToBoolean: {
1899
        if (truncation.IsUsedAsBool()) {
1900 1901
          ProcessInput<T>(node, 0, UseInfo::Bool());
          SetOutput<T>(node, MachineRepresentation::kBit);
1902
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
1903
        } else {
1904
          VisitInputs<T>(node);
1905
          SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
1906 1907 1908
        }
        return;
      }
1909
      case IrOpcode::kJSToNumber:
1910
      case IrOpcode::kJSToNumberConvertBigInt:
1911
      case IrOpcode::kJSToNumeric: {
1912 1913
        DCHECK(NodeProperties::GetType(node).Is(Type::Union(
            Type::BigInt(), Type::NumberOrOddball(), graph()->zone())));
1914
        VisitInputs<T>(node);
1915
        // TODO(bmeurer): Optimize somewhat based on input type?
1916
        if (truncation.IsUsedAsWord32()) {
1917
          SetOutput<T>(node, MachineRepresentation::kWord32);
1918
          if (lower<T>())
1919
            lowering->DoJSToNumberOrNumericTruncatesToWord32(node, this);
1920
        } else if (truncation.TruncatesOddballAndBigIntToNumber()) {
1921
          SetOutput<T>(node, MachineRepresentation::kFloat64);
1922
          if (lower<T>())
1923
            lowering->DoJSToNumberOrNumericTruncatesToFloat64(node, this);
1924
        } else {
1925
          SetOutput<T>(node, MachineRepresentation::kTagged);
1926
        }
1927
        return;
1928
      }
1929 1930 1931 1932 1933

      //------------------------------------------------------------------
      // Simplified operators.
      //------------------------------------------------------------------
      case IrOpcode::kBooleanNot: {
1934
        if (lower<T>()) {
1935 1936
          NodeInfo* input_info = GetInfo(node->InputAt(0));
          if (input_info->representation() == MachineRepresentation::kBit) {
1937
            // BooleanNot(x: kRepBit) => Word32Equal(x, #0)
1938
            node->AppendInput(jsgraph_->zone(), jsgraph_->Int32Constant(0));
1939
            NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
1940
          } else if (CanBeTaggedPointer(input_info->representation())) {
1941
            // BooleanNot(x: kRepTagged) => WordEqual(x, #false)
1942
            node->AppendInput(jsgraph_->zone(), jsgraph_->FalseConstant());
1943
            NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
1944
          } else {
1945
            DCHECK(TypeOf(node->InputAt(0)).IsNone());
1946
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
1947 1948 1949
          }
        } else {
          // No input representation requirement; adapt during lowering.
1950 1951
          ProcessInput<T>(node, 0, UseInfo::AnyTruncatingToBool());
          SetOutput<T>(node, MachineRepresentation::kBit);
1952
        }
1953
        return;
1954
      }
1955
      case IrOpcode::kNumberEqual: {
1956 1957
        Type const lhs_type = TypeOf(node->InputAt(0));
        Type const rhs_type = TypeOf(node->InputAt(1));
1958 1959 1960 1961 1962 1963 1964
        // Regular number comparisons in JavaScript generally identify zeros,
        // so we always pass kIdentifyZeros for the inputs, and in addition
        // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
        // For equality we also handle the case that one side is non-zero, in
        // which case we allow to truncate NaN to 0 on the other side.
        if ((lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
             rhs_type.Is(Type::Unsigned32OrMinusZero())) ||
1965 1966
            (lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
             rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
1967
             OneInputCannotBe(node, type_cache_->kZeroish))) {
1968
          // => unsigned Int32Cmp
1969 1970
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        MachineRepresentation::kBit);
1971
          if (lower<T>()) NodeProperties::ChangeOp(node, Uint32Op(node));
1972 1973
          return;
        }
1974 1975
        if ((lhs_type.Is(Type::Signed32OrMinusZero()) &&
             rhs_type.Is(Type::Signed32OrMinusZero())) ||
1976 1977
            (lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
             rhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
1978
             OneInputCannotBe(node, type_cache_->kZeroish))) {
1979
          // => signed Int32Cmp
1980 1981
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        MachineRepresentation::kBit);
1982
          if (lower<T>()) NodeProperties::ChangeOp(node, Int32Op(node));
1983 1984 1985
          return;
        }
        // => Float64Cmp
1986 1987
        VisitBinop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
                      MachineRepresentation::kBit);
1988
        if (lower<T>()) NodeProperties::ChangeOp(node, Float64Op(node));
1989 1990
        return;
      }
1991
      case IrOpcode::kNumberLessThan:
1992
      case IrOpcode::kNumberLessThanOrEqual: {
1993 1994 1995 1996 1997 1998 1999
        Type const lhs_type = TypeOf(node->InputAt(0));
        Type const rhs_type = TypeOf(node->InputAt(1));
        // Regular number comparisons in JavaScript generally identify zeros,
        // so we always pass kIdentifyZeros for the inputs, and in addition
        // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
        if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
            rhs_type.Is(Type::Unsigned32OrMinusZero())) {
2000
          // => unsigned Int32Cmp
2001 2002
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        MachineRepresentation::kBit);
2003
          if (lower<T>()) NodeProperties::ChangeOp(node, Uint32Op(node));
2004 2005
        } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
                   rhs_type.Is(Type::Signed32OrMinusZero())) {
2006
          // => signed Int32Cmp
2007 2008
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        MachineRepresentation::kBit);
2009
          if (lower<T>()) NodeProperties::ChangeOp(node, Int32Op(node));
2010 2011
        } else {
          // => Float64Cmp
2012 2013
          VisitBinop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
                        MachineRepresentation::kBit);
2014
          if (lower<T>()) NodeProperties::ChangeOp(node, Float64Op(node));
2015 2016 2017
        }
        return;
      }
2018

2019 2020
      case IrOpcode::kSpeculativeSafeIntegerAdd:
      case IrOpcode::kSpeculativeSafeIntegerSubtract:
2021
        return VisitSpeculativeIntegerAdditiveOp<T>(node, truncation, lowering);
2022

2023 2024
      case IrOpcode::kSpeculativeNumberAdd:
      case IrOpcode::kSpeculativeNumberSubtract:
2025
        return VisitSpeculativeAdditiveOp<T>(node, truncation, lowering);
2026

2027 2028
      case IrOpcode::kSpeculativeNumberLessThan:
      case IrOpcode::kSpeculativeNumberLessThanOrEqual:
2029
      case IrOpcode::kSpeculativeNumberEqual: {
2030 2031 2032 2033 2034 2035 2036
        Type const lhs_type = TypeOf(node->InputAt(0));
        Type const rhs_type = TypeOf(node->InputAt(1));
        // Regular number comparisons in JavaScript generally identify zeros,
        // so we always pass kIdentifyZeros for the inputs, and in addition
        // we can truncate -0 to 0 for otherwise Unsigned32 or Signed32 inputs.
        if (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
            rhs_type.Is(Type::Unsigned32OrMinusZero())) {
2037
          // => unsigned Int32Cmp
2038 2039
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        MachineRepresentation::kBit);
2040
          if (lower<T>()) ChangeToPureOp(node, Uint32Op(node));
2041
          return;
2042 2043
        } else if (lhs_type.Is(Type::Signed32OrMinusZero()) &&
                   rhs_type.Is(Type::Signed32OrMinusZero())) {
2044
          // => signed Int32Cmp
2045 2046
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        MachineRepresentation::kBit);
2047
          if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2048 2049 2050 2051 2052
          return;
        }
        // Try to use type feedback.
        NumberOperationHint hint = NumberOperationHintOf(node->op());
        switch (hint) {
2053
          case NumberOperationHint::kSignedSmall:
2054
            if (propagate<T>()) {
2055 2056 2057 2058
              VisitBinop<T>(node,
                            CheckedUseInfoAsWord32FromHint(
                                hint, FeedbackSource(), kIdentifyZeros),
                            MachineRepresentation::kBit);
2059
            } else if (retype<T>()) {
2060
              SetOutput<T>(node, MachineRepresentation::kBit, Type::Any());
2061
            } else {
2062
              DCHECK(lower<T>());
2063 2064 2065 2066
              Node* lhs = node->InputAt(0);
              Node* rhs = node->InputAt(1);
              if (IsNodeRepresentationTagged(lhs) &&
                  IsNodeRepresentationTagged(rhs)) {
2067 2068 2069 2070
                VisitBinop<T>(node,
                              UseInfo::CheckedSignedSmallAsTaggedSigned(
                                  FeedbackSource(), kIdentifyZeros),
                              MachineRepresentation::kBit);
2071 2072 2073 2074
                ChangeToPureOp(
                    node, changer_->TaggedSignedOperatorFor(node->opcode()));

              } else {
2075 2076 2077 2078
                VisitBinop<T>(node,
                              CheckedUseInfoAsWord32FromHint(
                                  hint, FeedbackSource(), kIdentifyZeros),
                              MachineRepresentation::kBit);
2079 2080 2081
                ChangeToPureOp(node, Int32Op(node));
              }
            }
2082
            return;
2083
          case NumberOperationHint::kSignedSmallInputs:
2084 2085 2086
            // This doesn't make sense for compare operations.
            UNREACHABLE();
          case NumberOperationHint::kNumberOrOddball:
2087 2088 2089 2090 2091
            // Abstract and strict equality don't perform ToNumber conversions
            // on Oddballs, so make sure we don't accidentially sneak in a
            // hint with Oddball feedback here.
            DCHECK_NE(IrOpcode::kSpeculativeNumberEqual, node->opcode());
            V8_FALLTHROUGH;
2092
          case NumberOperationHint::kNumberOrBoolean:
2093
          case NumberOperationHint::kNumber:
2094 2095 2096 2097
            VisitBinop<T>(node,
                          CheckedUseInfoAsFloat64FromHint(
                              hint, FeedbackSource(), kIdentifyZeros),
                          MachineRepresentation::kBit);
2098
            if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2099 2100 2101 2102 2103
            return;
        }
        UNREACHABLE();
        return;
      }
2104

2105 2106
      case IrOpcode::kNumberAdd:
      case IrOpcode::kNumberSubtract: {
2107
        if (TypeOf(node->InputAt(0))
2108
                .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
2109
            TypeOf(node->InputAt(1))
2110
                .Is(type_cache_->kAdditiveSafeIntegerOrMinusZero) &&
2111 2112
            (TypeOf(node).Is(Type::Signed32()) ||
             TypeOf(node).Is(Type::Unsigned32()) ||
2113 2114
             truncation.IsUsedAsWord32())) {
          // => Int32Add/Sub
2115
          VisitWord32TruncatingBinop<T>(node);
2116
          if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2117
        } else if (jsgraph_->machine()->Is64() &&
2118 2119
                   BothInputsAre(node, type_cache_->kSafeInteger) &&
                   GetUpperBound(node).Is(type_cache_->kSafeInteger)) {
2120
          // => Int64Add/Sub
2121
          VisitInt64Binop<T>(node);
2122
          if (lower<T>()) ChangeToPureOp(node, Int64Op(node));
2123 2124
        } else {
          // => Float64Add/Sub
2125
          VisitFloat64Binop<T>(node);
2126
          if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2127
        }
2128
        return;
2129
      }
2130
      case IrOpcode::kSpeculativeNumberMultiply: {
2131
        if (BothInputsAre(node, Type::Integral32()) &&
2132 2133
            (NodeProperties::GetType(node).Is(Type::Signed32()) ||
             NodeProperties::GetType(node).Is(Type::Unsigned32()) ||
2134
             (truncation.IsUsedAsWord32() &&
2135
              NodeProperties::GetType(node).Is(
2136
                  type_cache_->kSafeIntegerOrMinusZero)))) {
2137 2138 2139 2140 2141
          // Multiply reduces to Int32Mul if the inputs are integers, and
          // (a) the output is either known to be Signed32, or
          // (b) the output is known to be Unsigned32, or
          // (c) the uses are truncating and the result is in the safe
          //     integer range.
2142
          VisitWord32TruncatingBinop<T>(node);
2143
          if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2144
          return;
2145
        }
2146 2147
        // Try to use type feedback.
        NumberOperationHint hint = NumberOperationHintOf(node->op());
2148 2149
        Type input0_type = TypeOf(node->InputAt(0));
        Type input1_type = TypeOf(node->InputAt(1));
2150 2151 2152 2153

        // Handle the case when no int32 checks on inputs are necessary
        // (but an overflow check is needed on the output).
        if (BothInputsAre(node, Type::Signed32())) {
2154
          // If both inputs and feedback are int32, use the overflow op.
2155
          if (hint == NumberOperationHint::kSignedSmall) {
2156 2157
            VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                          MachineRepresentation::kWord32, Type::Signed32());
2158
            if (lower<T>()) {
2159 2160 2161 2162
              LowerToCheckedInt32Mul(node, truncation, input0_type,
                                     input1_type);
            }
            return;
2163
          }
2164 2165
        }

2166
        if (hint == NumberOperationHint::kSignedSmall) {
2167 2168
          VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
                        MachineRepresentation::kWord32, Type::Signed32());
2169
          if (lower<T>()) {
2170
            LowerToCheckedInt32Mul(node, truncation, input0_type, input1_type);
2171
          }
2172 2173
          return;
        }
2174

2175
        // Checked float64 x float64 => float64
2176 2177 2178 2179
        VisitBinop<T>(node,
                      UseInfo::CheckedNumberOrOddballAsFloat64(
                          kDistinguishZeros, FeedbackSource()),
                      MachineRepresentation::kFloat64, Type::Number());
2180
        if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2181
        return;
2182
      }
2183
      case IrOpcode::kNumberMultiply: {
2184 2185 2186 2187
        if (TypeOf(node->InputAt(0)).Is(Type::Integral32()) &&
            TypeOf(node->InputAt(1)).Is(Type::Integral32()) &&
            (TypeOf(node).Is(Type::Signed32()) ||
             TypeOf(node).Is(Type::Unsigned32()) ||
2188
             (truncation.IsUsedAsWord32() &&
2189
              TypeOf(node).Is(type_cache_->kSafeIntegerOrMinusZero)))) {
2190 2191 2192 2193 2194
          // Multiply reduces to Int32Mul if the inputs are integers, and
          // (a) the output is either known to be Signed32, or
          // (b) the output is known to be Unsigned32, or
          // (c) the uses are truncating and the result is in the safe
          //     integer range.
2195
          VisitWord32TruncatingBinop<T>(node);
2196
          if (lower<T>()) ChangeToPureOp(node, Int32Op(node));
2197 2198 2199
          return;
        }
        // Number x Number => Float64Mul
2200
        VisitFloat64Binop<T>(node);
2201
        if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2202 2203
        return;
      }
2204
      case IrOpcode::kSpeculativeNumberDivide: {
2205
        if (BothInputsAreUnsigned32(node) && truncation.IsUsedAsWord32()) {
2206
          // => unsigned Uint32Div
2207
          VisitWord32TruncatingBinop<T>(node);
2208
          if (lower<T>()) DeferReplacement(node, lowering->Uint32Div(node));
2209 2210
          return;
        }
2211
        if (BothInputsAreSigned32(node)) {
2212
          if (NodeProperties::GetType(node).Is(Type::Signed32())) {
2213
            // => signed Int32Div
2214
            VisitWord32TruncatingBinop<T>(node);
2215
            if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2216
            return;
2217
          }
2218
          if (truncation.IsUsedAsWord32()) {
2219
            // => signed Int32Div
2220
            VisitWord32TruncatingBinop<T>(node);
2221
            if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2222
            return;
2223
          }
2224
        }
2225 2226

        // Try to use type feedback.
2227
        NumberOperationHint hint = NumberOperationHintOf(node->op());
2228

2229 2230 2231
        // Handle the case when no uint32 checks on inputs are necessary
        // (but an overflow check is needed on the output).
        if (BothInputsAreUnsigned32(node)) {
2232
          if (hint == NumberOperationHint::kSignedSmall) {
2233 2234
            VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                          MachineRepresentation::kWord32, Type::Unsigned32());
2235
            if (lower<T>()) ChangeToUint32OverflowOp(node);
2236 2237 2238 2239
            return;
          }
        }

2240 2241
        // Handle the case when no int32 checks on inputs are necessary
        // (but an overflow check is needed on the output).
2242
        if (BothInputsAreSigned32(node)) {
2243
          // If both the inputs the feedback are int32, use the overflow op.
2244
          if (hint == NumberOperationHint::kSignedSmall) {
2245 2246
            VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                          MachineRepresentation::kWord32, Type::Signed32());
2247
            if (lower<T>()) ChangeToInt32OverflowOp(node);
2248 2249 2250 2251
            return;
          }
        }

2252
        if (hint == NumberOperationHint::kSignedSmall ||
2253
            hint == NumberOperationHint::kSignedSmallInputs) {
2254
          // If the result is truncated, we only need to check the inputs.
2255
          if (truncation.IsUsedAsWord32()) {
2256 2257
            VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
                          MachineRepresentation::kWord32);
2258
            if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2259
            return;
2260
          } else if (hint != NumberOperationHint::kSignedSmallInputs) {
2261 2262
            VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
                          MachineRepresentation::kWord32, Type::Signed32());
2263
            if (lower<T>()) ChangeToInt32OverflowOp(node);
2264
            return;
2265 2266 2267 2268
          }
        }

        // default case => Float64Div
2269 2270 2271 2272
        VisitBinop<T>(node,
                      UseInfo::CheckedNumberOrOddballAsFloat64(
                          kDistinguishZeros, FeedbackSource()),
                      MachineRepresentation::kFloat64, Type::Number());
2273
        if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2274 2275 2276
        return;
      }
      case IrOpcode::kNumberDivide: {
2277 2278 2279 2280
        if (TypeOf(node->InputAt(0)).Is(Type::Unsigned32()) &&
            TypeOf(node->InputAt(1)).Is(Type::Unsigned32()) &&
            (truncation.IsUsedAsWord32() ||
             TypeOf(node).Is(Type::Unsigned32()))) {
2281
          // => unsigned Uint32Div
2282
          VisitWord32TruncatingBinop<T>(node);
2283
          if (lower<T>()) DeferReplacement(node, lowering->Uint32Div(node));
2284
          return;
2285
        }
2286 2287 2288 2289 2290
        if (TypeOf(node->InputAt(0)).Is(Type::Signed32()) &&
            TypeOf(node->InputAt(1)).Is(Type::Signed32()) &&
            (truncation.IsUsedAsWord32() ||
             TypeOf(node).Is(Type::Signed32()))) {
          // => signed Int32Div
2291
          VisitWord32TruncatingBinop<T>(node);
2292
          if (lower<T>()) DeferReplacement(node, lowering->Int32Div(node));
2293
          return;
2294
        }
2295
        // Number x Number => Float64Div
2296
        VisitFloat64Binop<T>(node);
2297
        if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2298
        return;
2299
      }
2300
      case IrOpcode::kSpeculativeNumberModulus:
2301
        return VisitSpeculativeNumberModulus<T>(node, truncation, lowering);
2302
      case IrOpcode::kNumberModulus: {
2303 2304 2305 2306
        Type const lhs_type = TypeOf(node->InputAt(0));
        Type const rhs_type = TypeOf(node->InputAt(1));
        if ((lhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN()) &&
             rhs_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) &&
2307
            (truncation.IsUsedAsWord32() ||
2308
             TypeOf(node).Is(Type::Unsigned32()))) {
2309
          // => unsigned Uint32Mod
2310
          VisitWord32TruncatingBinop<T>(node);
2311
          if (lower<T>()) DeferReplacement(node, lowering->Uint32Mod(node));
2312
          return;
2313
        }
2314 2315 2316 2317 2318
        if ((lhs_type.Is(Type::Signed32OrMinusZeroOrNaN()) &&
             rhs_type.Is(Type::Signed32OrMinusZeroOrNaN())) &&
            (truncation.IsUsedAsWord32() || TypeOf(node).Is(Type::Signed32()) ||
             (truncation.IdentifiesZeroAndMinusZero() &&
              TypeOf(node).Is(Type::Signed32OrMinusZero())))) {
2319
          // => signed Int32Mod
2320
          VisitWord32TruncatingBinop<T>(node);
2321
          if (lower<T>()) DeferReplacement(node, lowering->Int32Mod(node));
2322
          return;
2323
        }
2324
        // => Float64Mod
2325 2326 2327 2328 2329 2330 2331
        // For the left hand side we just propagate the identify zeros
        // mode of the {truncation}; and for modulus the sign of the
        // right hand side doesn't matter anyways, so in particular there's
        // no observable difference between a 0 and a -0 then.
        UseInfo const lhs_use =
            UseInfo::TruncatingFloat64(truncation.identify_zeros());
        UseInfo const rhs_use = UseInfo::TruncatingFloat64(kIdentifyZeros);
2332
        VisitBinop<T>(node, lhs_use, rhs_use, MachineRepresentation::kFloat64);
2333
        if (lower<T>()) ChangeToPureOp(node, Float64Op(node));
2334
        return;
2335
      }
2336 2337 2338
      case IrOpcode::kNumberBitwiseOr:
      case IrOpcode::kNumberBitwiseXor:
      case IrOpcode::kNumberBitwiseAnd: {
2339
        VisitWord32TruncatingBinop<T>(node);
2340
        if (lower<T>()) NodeProperties::ChangeOp(node, Int32Op(node));
2341
        return;
2342
      }
2343 2344 2345
      case IrOpcode::kSpeculativeNumberBitwiseOr:
      case IrOpcode::kSpeculativeNumberBitwiseXor:
      case IrOpcode::kSpeculativeNumberBitwiseAnd:
2346
        VisitSpeculativeInt32Binop<T>(node);
2347
        if (lower<T>()) {
2348 2349 2350
          ChangeToPureOp(node, Int32Op(node));
        }
        return;
2351
      case IrOpcode::kNumberShiftLeft: {
2352
        Type rhs_type = GetUpperBound(node->InputAt(1));
2353 2354 2355
        VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                      UseInfo::TruncatingWord32(),
                      MachineRepresentation::kWord32);
2356
        if (lower<T>()) {
2357 2358
          MaskShiftOperand(node, rhs_type);
          ChangeToPureOp(node, lowering->machine()->Word32Shl());
2359
        }
2360
        return;
2361
      }
2362 2363
      case IrOpcode::kSpeculativeNumberShiftLeft: {
        if (BothInputsAre(node, Type::NumberOrOddball())) {
2364
          Type rhs_type = GetUpperBound(node->InputAt(1));
2365 2366 2367
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        UseInfo::TruncatingWord32(),
                        MachineRepresentation::kWord32);
2368
          if (lower<T>()) {
2369 2370
            MaskShiftOperand(node, rhs_type);
            ChangeToPureOp(node, lowering->machine()->Word32Shl());
2371 2372 2373
          }
          return;
        }
2374
        NumberOperationHint hint = NumberOperationHintOf(node->op());
2375
        Type rhs_type = GetUpperBound(node->InputAt(1));
2376 2377
        VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
                      MachineRepresentation::kWord32, Type::Signed32());
2378
        if (lower<T>()) {
2379 2380
          MaskShiftOperand(node, rhs_type);
          ChangeToPureOp(node, lowering->machine()->Word32Shl());
2381
        }
2382
        return;
2383
      }
2384
      case IrOpcode::kNumberShiftRight: {
2385
        Type rhs_type = GetUpperBound(node->InputAt(1));
2386 2387 2388
        VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                      UseInfo::TruncatingWord32(),
                      MachineRepresentation::kWord32);
2389
        if (lower<T>()) {
2390 2391
          MaskShiftOperand(node, rhs_type);
          ChangeToPureOp(node, lowering->machine()->Word32Sar());
2392
        }
2393
        return;
2394
      }
2395 2396
      case IrOpcode::kSpeculativeNumberShiftRight: {
        if (BothInputsAre(node, Type::NumberOrOddball())) {
2397
          Type rhs_type = GetUpperBound(node->InputAt(1));
2398 2399 2400
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        UseInfo::TruncatingWord32(),
                        MachineRepresentation::kWord32);
2401
          if (lower<T>()) {
2402 2403
            MaskShiftOperand(node, rhs_type);
            ChangeToPureOp(node, lowering->machine()->Word32Sar());
2404 2405 2406
          }
          return;
        }
2407
        NumberOperationHint hint = NumberOperationHintOf(node->op());
2408
        Type rhs_type = GetUpperBound(node->InputAt(1));
2409 2410
        VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
                      MachineRepresentation::kWord32, Type::Signed32());
2411
        if (lower<T>()) {
2412 2413
          MaskShiftOperand(node, rhs_type);
          ChangeToPureOp(node, lowering->machine()->Word32Sar());
2414 2415 2416
        }
        return;
      }
2417
      case IrOpcode::kNumberShiftRightLogical: {
2418
        Type rhs_type = GetUpperBound(node->InputAt(1));
2419 2420 2421
        VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                      UseInfo::TruncatingWord32(),
                      MachineRepresentation::kWord32);
2422
        if (lower<T>()) {
2423 2424
          MaskShiftOperand(node, rhs_type);
          ChangeToPureOp(node, lowering->machine()->Word32Shr());
2425
        }
2426
        return;
2427
      }
2428
      case IrOpcode::kSpeculativeNumberShiftRightLogical: {
2429
        NumberOperationHint hint = NumberOperationHintOf(node->op());
2430
        Type rhs_type = GetUpperBound(node->InputAt(1));
2431
        if (rhs_type.Is(type_cache_->kZeroish) &&
2432
            hint == NumberOperationHint::kSignedSmall &&
2433 2434 2435 2436 2437
            !truncation.IsUsedAsWord32()) {
          // The SignedSmall or Signed32 feedback means that the results that we
          // have seen so far were of type Unsigned31.  We speculate that this
          // will continue to hold.  Moreover, since the RHS is 0, the result
          // will just be the (converted) LHS.
2438 2439
          VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
                        MachineRepresentation::kWord32, Type::Unsigned31());
2440
          if (lower<T>()) {
2441
            node->RemoveInput(1);
2442
            NodeProperties::ChangeOp(
2443
                node, simplified()->CheckedUint32ToInt32(FeedbackSource()));
2444 2445 2446
          }
          return;
        }
2447
        if (BothInputsAre(node, Type::NumberOrOddball())) {
2448 2449 2450
          VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                        UseInfo::TruncatingWord32(),
                        MachineRepresentation::kWord32);
2451
          if (lower<T>()) {
2452 2453
            MaskShiftOperand(node, rhs_type);
            ChangeToPureOp(node, lowering->machine()->Word32Shr());
2454 2455 2456
          }
          return;
        }
2457 2458
        VisitBinop<T>(node, CheckedUseInfoAsWord32FromHint(hint),
                      MachineRepresentation::kWord32, Type::Unsigned32());
2459
        if (lower<T>()) {
2460 2461
          MaskShiftOperand(node, rhs_type);
          ChangeToPureOp(node, lowering->machine()->Word32Shr());
2462 2463 2464
        }
        return;
      }
2465
      case IrOpcode::kNumberAbs: {
2466 2467 2468 2469 2470
        // NumberAbs maps both 0 and -0 to 0, so we can generally
        // pass the kIdentifyZeros truncation to its input, and
        // choose to ignore minus zero in all cases.
        Type const input_type = TypeOf(node->InputAt(0));
        if (input_type.Is(Type::Unsigned32OrMinusZero())) {
2471 2472
          VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                       MachineRepresentation::kWord32);
2473
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2474
        } else if (input_type.Is(Type::Signed32OrMinusZero())) {
2475 2476
          VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                       MachineRepresentation::kWord32);
2477
          if (lower<T>()) DeferReplacement(node, lowering->Int32Abs(node));
2478
        } else if (input_type.Is(type_cache_->kPositiveIntegerOrNaN)) {
2479 2480
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
                       MachineRepresentation::kFloat64);
2481
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2482
        } else {
2483 2484
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
                       MachineRepresentation::kFloat64);
2485
          if (lower<T>()) NodeProperties::ChangeOp(node, Float64Op(node));
2486 2487 2488
        }
        return;
      }
2489
      case IrOpcode::kNumberClz32: {
2490 2491
        VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                     MachineRepresentation::kWord32);
2492
        if (lower<T>()) NodeProperties::ChangeOp(node, Uint32Op(node));
2493
        return;
2494
      }
2495
      case IrOpcode::kNumberImul: {
2496 2497 2498
        VisitBinop<T>(node, UseInfo::TruncatingWord32(),
                      UseInfo::TruncatingWord32(),
                      MachineRepresentation::kWord32);
2499
        if (lower<T>()) NodeProperties::ChangeOp(node, Uint32Op(node));
2500
        return;
2501
      }
2502
      case IrOpcode::kNumberFround: {
2503 2504
        VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                     MachineRepresentation::kFloat32);
2505
        if (lower<T>()) NodeProperties::ChangeOp(node, Float64Op(node));
2506 2507
        return;
      }
2508
      case IrOpcode::kNumberMax: {
2509 2510 2511
        // It is safe to use the feedback types for left and right hand side
        // here, since we can only narrow those types and thus we can only
        // promise a more specific truncation.
2512 2513 2514
        // For NumberMax we generally propagate whether the truncation
        // identifies zeros to the inputs, and we choose to ignore minus
        // zero in those cases.
2515 2516
        Type const lhs_type = TypeOf(node->InputAt(0));
        Type const rhs_type = TypeOf(node->InputAt(1));
2517 2518 2519 2520 2521
        if ((lhs_type.Is(Type::Unsigned32()) &&
             rhs_type.Is(Type::Unsigned32())) ||
            (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
             rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
             truncation.IdentifiesZeroAndMinusZero())) {
2522
          VisitWord32TruncatingBinop<T>(node);
2523
          if (lower<T>()) {
2524 2525 2526
            lowering->DoMax(node, lowering->machine()->Uint32LessThan(),
                            MachineRepresentation::kWord32);
          }
2527 2528 2529 2530 2531
        } else if ((lhs_type.Is(Type::Signed32()) &&
                    rhs_type.Is(Type::Signed32())) ||
                   (lhs_type.Is(Type::Signed32OrMinusZero()) &&
                    rhs_type.Is(Type::Signed32OrMinusZero()) &&
                    truncation.IdentifiesZeroAndMinusZero())) {
2532
          VisitWord32TruncatingBinop<T>(node);
2533
          if (lower<T>()) {
2534 2535 2536
            lowering->DoMax(node, lowering->machine()->Int32LessThan(),
                            MachineRepresentation::kWord32);
          }
2537
        } else if (jsgraph_->machine()->Is64() &&
2538 2539
                   lhs_type.Is(type_cache_->kSafeInteger) &&
                   rhs_type.Is(type_cache_->kSafeInteger)) {
2540
          VisitInt64Binop<T>(node);
2541
          if (lower<T>()) {
2542 2543 2544
            lowering->DoMax(node, lowering->machine()->Int64LessThan(),
                            MachineRepresentation::kWord64);
          }
2545
        } else {
2546 2547 2548
          VisitBinop<T>(node,
                        UseInfo::TruncatingFloat64(truncation.identify_zeros()),
                        MachineRepresentation::kFloat64);
2549
          if (lower<T>()) {
2550 2551 2552 2553 2554 2555 2556
            // If the right hand side is not NaN, and the left hand side
            // is not NaN (or -0 if the difference between the zeros is
            // observed), we can do a simple floating point comparison here.
            if (lhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
                                ? Type::OrderedNumber()
                                : Type::PlainNumber()) &&
                rhs_type.Is(Type::OrderedNumber())) {
2557 2558 2559 2560 2561
              lowering->DoMax(node, lowering->machine()->Float64LessThan(),
                              MachineRepresentation::kFloat64);
            } else {
              NodeProperties::ChangeOp(node, Float64Op(node));
            }
2562 2563 2564 2565 2566
          }
        }
        return;
      }
      case IrOpcode::kNumberMin: {
2567 2568 2569
        // It is safe to use the feedback types for left and right hand side
        // here, since we can only narrow those types and thus we can only
        // promise a more specific truncation.
2570 2571 2572
        // For NumberMin we generally propagate whether the truncation
        // identifies zeros to the inputs, and we choose to ignore minus
        // zero in those cases.
2573 2574
        Type const lhs_type = TypeOf(node->InputAt(0));
        Type const rhs_type = TypeOf(node->InputAt(1));
2575 2576 2577 2578 2579
        if ((lhs_type.Is(Type::Unsigned32()) &&
             rhs_type.Is(Type::Unsigned32())) ||
            (lhs_type.Is(Type::Unsigned32OrMinusZero()) &&
             rhs_type.Is(Type::Unsigned32OrMinusZero()) &&
             truncation.IdentifiesZeroAndMinusZero())) {
2580
          VisitWord32TruncatingBinop<T>(node);
2581
          if (lower<T>()) {
2582 2583 2584
            lowering->DoMin(node, lowering->machine()->Uint32LessThan(),
                            MachineRepresentation::kWord32);
          }
2585 2586 2587 2588 2589
        } else if ((lhs_type.Is(Type::Signed32()) &&
                    rhs_type.Is(Type::Signed32())) ||
                   (lhs_type.Is(Type::Signed32OrMinusZero()) &&
                    rhs_type.Is(Type::Signed32OrMinusZero()) &&
                    truncation.IdentifiesZeroAndMinusZero())) {
2590
          VisitWord32TruncatingBinop<T>(node);
2591
          if (lower<T>()) {
2592 2593 2594
            lowering->DoMin(node, lowering->machine()->Int32LessThan(),
                            MachineRepresentation::kWord32);
          }
2595
        } else if (jsgraph_->machine()->Is64() &&
2596 2597
                   lhs_type.Is(type_cache_->kSafeInteger) &&
                   rhs_type.Is(type_cache_->kSafeInteger)) {
2598
          VisitInt64Binop<T>(node);
2599
          if (lower<T>()) {
2600 2601 2602
            lowering->DoMin(node, lowering->machine()->Int64LessThan(),
                            MachineRepresentation::kWord64);
          }
2603
        } else {
2604 2605 2606
          VisitBinop<T>(node,
                        UseInfo::TruncatingFloat64(truncation.identify_zeros()),
                        MachineRepresentation::kFloat64);
2607
          if (lower<T>()) {
2608 2609 2610 2611 2612 2613 2614
            // If the left hand side is not NaN, and the right hand side
            // is not NaN (or -0 if the difference between the zeros is
            // observed), we can do a simple floating point comparison here.
            if (lhs_type.Is(Type::OrderedNumber()) &&
                rhs_type.Is(truncation.IdentifiesZeroAndMinusZero()
                                ? Type::OrderedNumber()
                                : Type::PlainNumber())) {
2615 2616
              lowering->DoMin(node,
                              lowering->machine()->Float64LessThanOrEqual(),
2617 2618 2619 2620
                              MachineRepresentation::kFloat64);
            } else {
              NodeProperties::ChangeOp(node, Float64Op(node));
            }
2621 2622 2623 2624
          }
        }
        return;
      }
2625 2626
      case IrOpcode::kNumberAtan2:
      case IrOpcode::kNumberPow: {
2627 2628
        VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
                      MachineRepresentation::kFloat64);
2629
        if (lower<T>()) NodeProperties::ChangeOp(node, Float64Op(node));
2630 2631
        return;
      }
2632 2633
      case IrOpcode::kNumberCeil:
      case IrOpcode::kNumberFloor:
2634
      case IrOpcode::kNumberRound:
2635
      case IrOpcode::kNumberTrunc: {
2636 2637 2638 2639
        // For NumberCeil, NumberFloor, NumberRound and NumberTrunc we propagate
        // the zero identification part of the truncation, and we turn them into
        // no-ops if we figure out (late) that their input is already an
        // integer, NaN or -0.
2640
        Type const input_type = TypeOf(node->InputAt(0));
2641 2642 2643
        VisitUnop<T>(node,
                     UseInfo::TruncatingFloat64(truncation.identify_zeros()),
                     MachineRepresentation::kFloat64);
2644
        if (lower<T>()) {
2645
          if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
2646
            DeferReplacement(node, node->InputAt(0));
2647 2648
          } else if (node->opcode() == IrOpcode::kNumberRound) {
            DeferReplacement(node, lowering->Float64Round(node));
2649 2650 2651 2652 2653 2654
          } else {
            NodeProperties::ChangeOp(node, Float64Op(node));
          }
        }
        return;
      }
2655 2656
      case IrOpcode::kCheckBigInt: {
        if (InputIs(node, Type::BigInt())) {
2657
          VisitNoop<T>(node, truncation);
2658
        } else {
2659 2660
          VisitUnop<T>(node, UseInfo::AnyTagged(),
                       MachineRepresentation::kTaggedPointer);
2661 2662 2663 2664
        }
        return;
      }
      case IrOpcode::kBigIntAsUintN: {
2665 2666
        ProcessInput<T>(node, 0, UseInfo::TruncatingWord64());
        SetOutput<T>(node, MachineRepresentation::kWord64, Type::BigInt());
2667 2668
        return;
      }
2669 2670 2671 2672
      case IrOpcode::kNumberAcos:
      case IrOpcode::kNumberAcosh:
      case IrOpcode::kNumberAsin:
      case IrOpcode::kNumberAsinh:
2673
      case IrOpcode::kNumberAtan:
2674
      case IrOpcode::kNumberAtanh:
2675
      case IrOpcode::kNumberCos:
2676
      case IrOpcode::kNumberCosh:
2677
      case IrOpcode::kNumberExp:
2678
      case IrOpcode::kNumberExpm1:
2679
      case IrOpcode::kNumberLog:
2680 2681
      case IrOpcode::kNumberLog1p:
      case IrOpcode::kNumberLog2:
2682
      case IrOpcode::kNumberLog10:
2683
      case IrOpcode::kNumberCbrt:
2684
      case IrOpcode::kNumberSin:
2685 2686
      case IrOpcode::kNumberSinh:
      case IrOpcode::kNumberTan:
2687
      case IrOpcode::kNumberTanh: {
2688 2689
        VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                     MachineRepresentation::kFloat64);
2690
        if (lower<T>()) NodeProperties::ChangeOp(node, Float64Op(node));
2691 2692
        return;
      }
2693 2694
      case IrOpcode::kNumberSign: {
        if (InputIs(node, Type::Signed32())) {
2695 2696
          VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                       MachineRepresentation::kWord32);
2697
          if (lower<T>()) DeferReplacement(node, lowering->Int32Sign(node));
2698
        } else {
2699 2700
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kFloat64);
2701
          if (lower<T>()) DeferReplacement(node, lowering->Float64Sign(node));
2702 2703 2704
        }
        return;
      }
2705 2706 2707 2708
      case IrOpcode::kNumberSilenceNaN: {
        Type const input_type = TypeOf(node->InputAt(0));
        if (input_type.Is(Type::OrderedNumber())) {
          // No need to silence anything if the input cannot be NaN.
2709 2710
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kFloat64);
2711
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2712
        } else {
2713 2714
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kFloat64);
2715
          if (lower<T>()) NodeProperties::ChangeOp(node, Float64Op(node));
2716 2717 2718
        }
        return;
      }
2719
      case IrOpcode::kNumberSqrt: {
2720 2721
        VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                     MachineRepresentation::kFloat64);
2722
        if (lower<T>()) NodeProperties::ChangeOp(node, Float64Op(node));
2723 2724
        return;
      }
2725
      case IrOpcode::kNumberToBoolean: {
2726 2727 2728
        // For NumberToBoolean we don't care whether the input is 0 or
        // -0, since both of them are mapped to false anyways, so we
        // can generally pass kIdentifyZeros truncation.
2729
        Type const input_type = TypeOf(node->InputAt(0));
2730 2731 2732
        if (input_type.Is(Type::Integral32OrMinusZeroOrNaN())) {
          // 0, -0 and NaN all map to false, so we can safely truncate
          // all of them to zero here.
2733 2734
          VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                       MachineRepresentation::kBit);
2735
          if (lower<T>()) lowering->DoIntegral32ToBit(node);
2736
        } else if (input_type.Is(Type::OrderedNumber())) {
2737 2738
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
                       MachineRepresentation::kBit);
2739
          if (lower<T>()) lowering->DoOrderedNumberToBit(node);
2740
        } else {
2741 2742
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(kIdentifyZeros),
                       MachineRepresentation::kBit);
2743
          if (lower<T>()) lowering->DoNumberToBit(node);
2744 2745 2746
        }
        return;
      }
2747
      case IrOpcode::kNumberToInt32: {
2748
        // Just change representation if necessary.
2749 2750
        VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                     MachineRepresentation::kWord32);
2751
        if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2752
        return;
2753
      }
2754
      case IrOpcode::kNumberToString: {
2755 2756
        VisitUnop<T>(node, UseInfo::AnyTagged(),
                     MachineRepresentation::kTaggedPointer);
2757 2758
        return;
      }
2759
      case IrOpcode::kNumberToUint32: {
2760
        // Just change representation if necessary.
2761 2762
        VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                     MachineRepresentation::kWord32);
2763
        if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2764
        return;
2765
      }
2766
      case IrOpcode::kNumberToUint8Clamped: {
2767
        Type const input_type = TypeOf(node->InputAt(0));
2768
        if (input_type.Is(type_cache_->kUint8OrMinusZeroOrNaN)) {
2769 2770
          VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                       MachineRepresentation::kWord32);
2771
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2772
        } else if (input_type.Is(Type::Unsigned32OrMinusZeroOrNaN())) {
2773 2774
          VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                       MachineRepresentation::kWord32);
2775
          if (lower<T>()) lowering->DoUnsigned32ToUint8Clamped(node);
2776
        } else if (input_type.Is(Type::Signed32OrMinusZeroOrNaN())) {
2777 2778
          VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                       MachineRepresentation::kWord32);
2779
          if (lower<T>()) lowering->DoSigned32ToUint8Clamped(node);
2780
        } else if (input_type.Is(type_cache_->kIntegerOrMinusZeroOrNaN)) {
2781 2782
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kFloat64);
2783
          if (lower<T>()) lowering->DoIntegerToUint8Clamped(node);
2784
        } else {
2785 2786
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kFloat64);
2787
          if (lower<T>()) lowering->DoNumberToUint8Clamped(node);
2788 2789 2790
        }
        return;
      }
2791
      case IrOpcode::kReferenceEqual: {
2792
        VisitBinop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
2793
        if (lower<T>()) {
2794
          if (COMPRESS_POINTERS_BOOL) {
2795 2796 2797 2798
            NodeProperties::ChangeOp(node, lowering->machine()->Word32Equal());
          } else {
            NodeProperties::ChangeOp(node, lowering->machine()->WordEqual());
          }
2799
        }
2800
        return;
2801
      }
2802
      case IrOpcode::kSameValueNumbersOnly: {
2803 2804
        VisitBinop<T>(node, UseInfo::AnyTagged(),
                      MachineRepresentation::kTaggedPointer);
2805 2806
        return;
      }
2807
      case IrOpcode::kSameValue: {
2808
        if (truncation.IsUnused()) return VisitUnused<T>(node);
2809
        if (BothInputsAre(node, Type::Number())) {
2810 2811
          VisitBinop<T>(node, UseInfo::TruncatingFloat64(),
                        MachineRepresentation::kBit);
2812
          if (lower<T>()) {
2813 2814 2815 2816
            NodeProperties::ChangeOp(node,
                                     lowering->simplified()->NumberSameValue());
          }
        } else {
2817 2818
          VisitBinop<T>(node, UseInfo::AnyTagged(),
                        MachineRepresentation::kTaggedPointer);
2819
        }
2820 2821
        return;
      }
2822
      case IrOpcode::kTypeOf: {
2823 2824
        return VisitUnop<T>(node, UseInfo::AnyTagged(),
                            MachineRepresentation::kTaggedPointer);
2825
      }
2826 2827 2828 2829 2830 2831 2832 2833 2834 2835
      case IrOpcode::kTierUpCheck: {
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());
        ProcessInput<T>(node, 1, UseInfo::AnyTagged());
        ProcessInput<T>(node, 2, UseInfo::AnyTagged());
        ProcessInput<T>(node, 3, UseInfo::TruncatingWord32());
        ProcessInput<T>(node, 4, UseInfo::AnyTagged());
        ProcessRemainingInputs<T>(node, 5);
        SetOutput<T>(node, MachineRepresentation::kNone);
        return;
      }
2836 2837 2838 2839 2840 2841
      case IrOpcode::kUpdateInterruptBudget: {
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());
        ProcessRemainingInputs<T>(node, 1);
        SetOutput<T>(node, MachineRepresentation::kNone);
        return;
      }
2842
      case IrOpcode::kNewConsString: {
2843 2844 2845 2846
        ProcessInput<T>(node, 0, UseInfo::TruncatingWord32());  // length
        ProcessInput<T>(node, 1, UseInfo::AnyTagged());         // first
        ProcessInput<T>(node, 2, UseInfo::AnyTagged());         // second
        SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
2847 2848
        return;
      }
2849
      case IrOpcode::kSpeculativeBigIntAdd: {
2850 2851 2852 2853 2854
        // TODO(nicohartmann@, chromium:1073440): There should be special
        // handling for trunction.IsUnused() that correctly propagates deadness,
        // but preserves type checking which may throw exceptions. Until this
        // is fully supported, we lower to int64 operations but keep pushing
        // type constraints.
2855
        if (truncation.IsUsedAsWord64()) {
2856 2857 2858
          VisitBinop<T>(
              node, UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
              MachineRepresentation::kWord64);
2859
          if (lower<T>()) {
2860 2861 2862
            ChangeToPureOp(node, lowering->machine()->Int64Add());
          }
        } else {
2863 2864 2865
          VisitBinop<T>(node,
                        UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
                        MachineRepresentation::kTaggedPointer);
2866
          if (lower<T>()) {
2867 2868
            NodeProperties::ChangeOp(node, lowering->simplified()->BigIntAdd());
          }
2869
        }
2870 2871
        return;
      }
2872 2873
      case IrOpcode::kSpeculativeBigIntSubtract: {
        if (truncation.IsUsedAsWord64()) {
2874 2875 2876
          VisitBinop<T>(
              node, UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
              MachineRepresentation::kWord64);
2877
          if (lower<T>()) {
2878 2879 2880
            ChangeToPureOp(node, lowering->machine()->Int64Sub());
          }
        } else {
2881 2882 2883
          VisitBinop<T>(node,
                        UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
                        MachineRepresentation::kTaggedPointer);
2884
          if (lower<T>()) {
2885 2886 2887 2888 2889 2890
            NodeProperties::ChangeOp(node,
                                     lowering->simplified()->BigIntSubtract());
          }
        }
        return;
      }
2891 2892
      case IrOpcode::kSpeculativeBigIntNegate: {
        if (truncation.IsUsedAsWord64()) {
2893 2894 2895
          VisitUnop<T>(node,
                       UseInfo::CheckedBigIntTruncatingWord64(FeedbackSource{}),
                       MachineRepresentation::kWord64);
2896
          if (lower<T>()) {
2897 2898 2899 2900
            ChangeUnaryToPureBinaryOp(node, lowering->machine()->Int64Sub(), 0,
                                      jsgraph_->Int64Constant(0));
          }
        } else {
2901 2902 2903
          VisitUnop<T>(node,
                       UseInfo::CheckedBigIntAsTaggedPointer(FeedbackSource{}),
                       MachineRepresentation::kTaggedPointer);
2904
          if (lower<T>()) {
2905 2906
            ChangeToPureOp(node, lowering->simplified()->BigIntNegate());
          }
2907 2908 2909
        }
        return;
      }
2910
      case IrOpcode::kStringConcat: {
2911 2912 2913 2914 2915
        // TODO(turbofan): We currently depend on having this first length input
        // to make sure that the overflow check is properly scheduled before the
        // actual string concatenation. We should also use the length to pass it
        // to the builtin or decide in optimized code how to construct the
        // resulting string (i.e. cons string or sequential string).
2916 2917 2918 2919
        ProcessInput<T>(node, 0, UseInfo::TaggedSigned());  // length
        ProcessInput<T>(node, 1, UseInfo::AnyTagged());     // first
        ProcessInput<T>(node, 2, UseInfo::AnyTagged());     // second
        SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
2920 2921
        return;
      }
2922 2923
      case IrOpcode::kStringEqual:
      case IrOpcode::kStringLessThan:
2924
      case IrOpcode::kStringLessThanOrEqual: {
2925 2926
        return VisitBinop<T>(node, UseInfo::AnyTagged(),
                             MachineRepresentation::kTaggedPointer);
2927
      }
2928
      case IrOpcode::kStringCharCodeAt: {
2929 2930
        return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
                             MachineRepresentation::kWord32);
2931
      }
2932
      case IrOpcode::kStringCodePointAt: {
2933 2934
        return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
                             MachineRepresentation::kTaggedSigned);
2935
      }
2936
      case IrOpcode::kStringFromSingleCharCode: {
2937 2938
        VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                     MachineRepresentation::kTaggedPointer);
2939
        return;
2940
      }
2941
      case IrOpcode::kStringFromSingleCodePoint: {
2942 2943
        VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                     MachineRepresentation::kTaggedPointer);
2944 2945
        return;
      }
2946
      case IrOpcode::kStringFromCodePointAt: {
2947 2948
        return VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::Word(),
                             MachineRepresentation::kTaggedPointer);
2949
      }
2950
      case IrOpcode::kStringIndexOf: {
2951 2952 2953 2954
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());
        ProcessInput<T>(node, 1, UseInfo::AnyTagged());
        ProcessInput<T>(node, 2, UseInfo::TaggedSigned());
        SetOutput<T>(node, MachineRepresentation::kTaggedSigned);
2955 2956
        return;
      }
2957 2958 2959 2960
      case IrOpcode::kStringLength: {
        // TODO(bmeurer): The input representation should be TaggedPointer.
        // Fix this once we have a dedicated StringConcat/JSStringAdd
        // operator, which marks it's output as TaggedPointer properly.
2961 2962
        VisitUnop<T>(node, UseInfo::AnyTagged(),
                     MachineRepresentation::kWord32);
2963 2964
        return;
      }
2965
      case IrOpcode::kStringSubstring: {
2966 2967 2968 2969 2970
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());
        ProcessInput<T>(node, 1, UseInfo::TruncatingWord32());
        ProcessInput<T>(node, 2, UseInfo::TruncatingWord32());
        ProcessRemainingInputs<T>(node, 3);
        SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
2971 2972
        return;
      }
2973 2974
      case IrOpcode::kStringToLowerCaseIntl:
      case IrOpcode::kStringToUpperCaseIntl: {
2975 2976
        VisitUnop<T>(node, UseInfo::AnyTagged(),
                     MachineRepresentation::kTaggedPointer);
2977 2978
        return;
      }
2979
      case IrOpcode::kCheckBounds:
2980
        return VisitCheckBounds<T>(node, lowering);
2981
      case IrOpcode::kPoisonIndex: {
2982 2983
        VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                     MachineRepresentation::kWord32);
2984 2985
        return;
      }
2986 2987
      case IrOpcode::kCheckHeapObject: {
        if (InputCannotBe(node, Type::SignedSmall())) {
2988 2989
          VisitUnop<T>(node, UseInfo::AnyTagged(),
                       MachineRepresentation::kTaggedPointer);
2990
        } else {
2991 2992 2993
          VisitUnop<T>(
              node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
              MachineRepresentation::kTaggedPointer);
2994
        }
2995
        if (lower<T>()) DeferReplacement(node, node->InputAt(0));
2996 2997
        return;
      }
2998
      case IrOpcode::kCheckIf: {
2999 3000 3001
        ProcessInput<T>(node, 0, UseInfo::Bool());
        ProcessRemainingInputs<T>(node, 1);
        SetOutput<T>(node, MachineRepresentation::kNone);
3002 3003
        return;
      }
3004
      case IrOpcode::kCheckInternalizedString: {
3005
        VisitCheck<T>(node, Type::InternalizedString(), lowering);
3006 3007
        return;
      }
3008
      case IrOpcode::kCheckNumber: {
3009
        Type const input_type = TypeOf(node->InputAt(0));
3010
        if (input_type.Is(Type::Number())) {
3011
          VisitNoop<T>(node, truncation);
3012
        } else {
3013 3014
          VisitUnop<T>(node, UseInfo::AnyTagged(),
                       MachineRepresentation::kTagged);
3015 3016 3017
        }
        return;
      }
3018
      case IrOpcode::kCheckReceiver: {
3019
        VisitCheck<T>(node, Type::Receiver(), lowering);
3020 3021
        return;
      }
3022
      case IrOpcode::kCheckReceiverOrNullOrUndefined: {
3023
        VisitCheck<T>(node, Type::ReceiverOrNullOrUndefined(), lowering);
3024 3025
        return;
      }
3026
      case IrOpcode::kCheckSmi: {
3027
        const CheckParameters& params = CheckParametersOf(node->op());
3028
        if (SmiValuesAre32Bits() && truncation.IsUsedAsWord32()) {
3029 3030 3031 3032
          VisitUnop<T>(node,
                       UseInfo::CheckedSignedSmallAsWord32(kDistinguishZeros,
                                                           params.feedback()),
                       MachineRepresentation::kWord32);
3033
        } else {
3034
          VisitUnop<T>(
3035 3036 3037
              node,
              UseInfo::CheckedSignedSmallAsTaggedSigned(params.feedback()),
              MachineRepresentation::kTaggedSigned);
3038
        }
3039
        if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3040 3041
        return;
      }
3042
      case IrOpcode::kCheckString: {
3043 3044
        const CheckParameters& params = CheckParametersOf(node->op());
        if (InputIs(node, Type::String())) {
3045 3046
          VisitUnop<T>(node, UseInfo::AnyTagged(),
                       MachineRepresentation::kTaggedPointer);
3047
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3048
        } else {
3049
          VisitUnop<T>(
3050 3051 3052 3053
              node,
              UseInfo::CheckedHeapObjectAsTaggedPointer(params.feedback()),
              MachineRepresentation::kTaggedPointer);
        }
3054 3055
        return;
      }
3056
      case IrOpcode::kCheckSymbol: {
3057
        VisitCheck<T>(node, Type::Symbol(), lowering);
3058 3059
        return;
      }
3060

3061
      case IrOpcode::kAllocate: {
3062 3063 3064
        ProcessInput<T>(node, 0, UseInfo::Word());
        ProcessRemainingInputs<T>(node, 1);
        SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3065
        return;
3066
      }
3067
      case IrOpcode::kLoadMessage: {
3068 3069
        if (truncation.IsUnused()) return VisitUnused<T>(node);
        VisitUnop<T>(node, UseInfo::Word(), MachineRepresentation::kTagged);
3070 3071 3072
        return;
      }
      case IrOpcode::kStoreMessage: {
3073 3074 3075 3076
        ProcessInput<T>(node, 0, UseInfo::Word());
        ProcessInput<T>(node, 1, UseInfo::AnyTagged());
        ProcessRemainingInputs<T>(node, 2);
        SetOutput<T>(node, MachineRepresentation::kNone);
3077 3078
        return;
      }
3079
      case IrOpcode::kLoadFieldByIndex: {
3080
        if (truncation.IsUnused()) return VisitUnused<T>(node);
3081 3082
        VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
                      MachineRepresentation::kTagged);
3083 3084
        return;
      }
3085
      case IrOpcode::kLoadField: {
3086
        if (truncation.IsUnused()) return VisitUnused<T>(node);
3087
        FieldAccess access = FieldAccessOf(node->op());
3088
        MachineRepresentation const representation =
3089
            access.machine_type.representation();
3090
        VisitUnop<T>(node, UseInfoForBasePointer(access), representation);
3091
        return;
3092 3093 3094
      }
      case IrOpcode::kStoreField: {
        FieldAccess access = FieldAccessOf(node->op());
3095 3096 3097 3098 3099
        Node* value_node = node->InputAt(1);
        NodeInfo* input_info = GetInfo(value_node);
        MachineRepresentation field_representation =
            access.machine_type.representation();

3100
        // Convert to Smi if possible, such that we can avoid a write barrier.
3101
        if (field_representation == MachineRepresentation::kTagged &&
3102
            TypeOf(value_node).Is(Type::SignedSmall())) {
3103
          field_representation = MachineRepresentation::kTaggedSigned;
3104
        }
3105
        WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
3106 3107 3108
            access.base_is_tagged, field_representation, access.offset,
            access.type, input_info->representation(), value_node);

3109 3110 3111 3112 3113
        ProcessInput<T>(node, 0, UseInfoForBasePointer(access));
        ProcessInput<T>(
            node, 1, TruncatingUseInfoFromRepresentation(field_representation));
        ProcessRemainingInputs<T>(node, 2);
        SetOutput<T>(node, MachineRepresentation::kNone);
3114
        if (lower<T>()) {
3115 3116 3117 3118 3119 3120
          if (write_barrier_kind < access.write_barrier_kind) {
            access.write_barrier_kind = write_barrier_kind;
            NodeProperties::ChangeOp(
                node, jsgraph_->simplified()->StoreField(access));
          }
        }
3121
        return;
3122
      }
3123
      case IrOpcode::kLoadElement: {
3124
        if (truncation.IsUnused()) return VisitUnused<T>(node);
3125
        ElementAccess access = ElementAccessOf(node->op());
3126 3127
        VisitBinop<T>(node, UseInfoForBasePointer(access), UseInfo::Word(),
                      access.machine_type.representation());
3128
        return;
3129
      }
3130
      case IrOpcode::kLoadStackArgument: {
3131
        if (truncation.IsUnused()) return VisitUnused<T>(node);
3132
        VisitBinop<T>(node, UseInfo::Word(), MachineRepresentation::kTagged);
3133 3134
        return;
      }
3135 3136
      case IrOpcode::kStoreElement: {
        ElementAccess access = ElementAccessOf(node->op());
3137 3138 3139 3140 3141
        Node* value_node = node->InputAt(2);
        NodeInfo* input_info = GetInfo(value_node);
        MachineRepresentation element_representation =
            access.machine_type.representation();

3142
        // Convert to Smi if possible, such that we can avoid a write barrier.
3143
        if (element_representation == MachineRepresentation::kTagged &&
3144
            TypeOf(value_node).Is(Type::SignedSmall())) {
3145
          element_representation = MachineRepresentation::kTaggedSigned;
3146
        }
3147
        WriteBarrierKind write_barrier_kind = WriteBarrierKindFor(
3148 3149
            access.base_is_tagged, element_representation, access.type,
            input_info->representation(), value_node);
3150 3151 3152 3153 3154 3155 3156
        ProcessInput<T>(node, 0, UseInfoForBasePointer(access));  // base
        ProcessInput<T>(node, 1, UseInfo::Word());                // index
        ProcessInput<T>(node, 2,
                        TruncatingUseInfoFromRepresentation(
                            element_representation));  // value
        ProcessRemainingInputs<T>(node, 3);
        SetOutput<T>(node, MachineRepresentation::kNone);
3157
        if (lower<T>()) {
3158 3159 3160 3161 3162 3163
          if (write_barrier_kind < access.write_barrier_kind) {
            access.write_barrier_kind = write_barrier_kind;
            NodeProperties::ChangeOp(
                node, jsgraph_->simplified()->StoreElement(access));
          }
        }
3164
        return;
3165
      }
3166
      case IrOpcode::kNumberIsFloat64Hole: {
3167 3168
        VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                     MachineRepresentation::kBit);
3169 3170
        return;
      }
3171
      case IrOpcode::kTransitionAndStoreElement: {
3172
        Type value_type = TypeOf(node->InputAt(2));
3173

3174 3175
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // array
        ProcessInput<T>(node, 1, UseInfo::Word());       // index
3176

3177
        if (value_type.Is(Type::SignedSmall())) {
3178
          ProcessInput<T>(node, 2, UseInfo::TruncatingWord32());  // value
3179
          if (lower<T>()) {
3180 3181 3182
            NodeProperties::ChangeOp(node,
                                     simplified()->StoreSignedSmallElement());
          }
3183
        } else if (value_type.Is(Type::Number())) {
3184
          ProcessInput<T>(node, 2, UseInfo::TruncatingFloat64());  // value
3185
          if (lower<T>()) {
3186 3187 3188 3189 3190
            Handle<Map> double_map = DoubleMapParameterOf(node->op());
            NodeProperties::ChangeOp(
                node,
                simplified()->TransitionAndStoreNumberElement(double_map));
          }
3191
        } else if (value_type.Is(Type::NonNumber())) {
3192
          ProcessInput<T>(node, 2, UseInfo::AnyTagged());  // value
3193
          if (lower<T>()) {
3194 3195 3196 3197 3198 3199
            Handle<Map> fast_map = FastMapParameterOf(node->op());
            NodeProperties::ChangeOp(
                node, simplified()->TransitionAndStoreNonNumberElement(
                          fast_map, value_type));
          }
        } else {
3200
          ProcessInput<T>(node, 2, UseInfo::AnyTagged());  // value
3201 3202
        }

3203 3204
        ProcessRemainingInputs<T>(node, 3);
        SetOutput<T>(node, MachineRepresentation::kNone);
3205 3206
        return;
      }
3207 3208 3209
      case IrOpcode::kLoadTypedElement: {
        MachineRepresentation const rep =
            MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3210 3211 3212 3213 3214 3215
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // buffer
        ProcessInput<T>(node, 1, UseInfo::AnyTagged());  // base pointer
        ProcessInput<T>(node, 2, UseInfo::Word());       // external pointer
        ProcessInput<T>(node, 3, UseInfo::Word());       // index
        ProcessRemainingInputs<T>(node, 4);
        SetOutput<T>(node, rep);
3216 3217 3218 3219 3220
        return;
      }
      case IrOpcode::kLoadDataViewElement: {
        MachineRepresentation const rep =
            MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3221 3222 3223 3224 3225 3226
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // object
        ProcessInput<T>(node, 1, UseInfo::Word());       // base
        ProcessInput<T>(node, 2, UseInfo::Word());       // index
        ProcessInput<T>(node, 3, UseInfo::Bool());       // little-endian
        ProcessRemainingInputs<T>(node, 4);
        SetOutput<T>(node, rep);
3227 3228 3229 3230 3231
        return;
      }
      case IrOpcode::kStoreTypedElement: {
        MachineRepresentation const rep =
            MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3232 3233 3234 3235 3236 3237 3238 3239
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // buffer
        ProcessInput<T>(node, 1, UseInfo::AnyTagged());  // base pointer
        ProcessInput<T>(node, 2, UseInfo::Word());       // external pointer
        ProcessInput<T>(node, 3, UseInfo::Word());       // index
        ProcessInput<T>(node, 4,
                        TruncatingUseInfoFromRepresentation(rep));  // value
        ProcessRemainingInputs<T>(node, 5);
        SetOutput<T>(node, MachineRepresentation::kNone);
3240 3241
        return;
      }
3242 3243 3244
      case IrOpcode::kStoreDataViewElement: {
        MachineRepresentation const rep =
            MachineRepresentationFromArrayType(ExternalArrayTypeOf(node->op()));
3245 3246 3247 3248 3249 3250 3251 3252
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());  // object
        ProcessInput<T>(node, 1, UseInfo::Word());       // base
        ProcessInput<T>(node, 2, UseInfo::Word());       // index
        ProcessInput<T>(node, 3,
                        TruncatingUseInfoFromRepresentation(rep));  // value
        ProcessInput<T>(node, 4, UseInfo::Bool());  // little-endian
        ProcessRemainingInputs<T>(node, 5);
        SetOutput<T>(node, MachineRepresentation::kNone);
3253 3254
        return;
      }
3255
      case IrOpcode::kConvertReceiver: {
3256
        Type input_type = TypeOf(node->InputAt(0));
3257 3258
        VisitBinop<T>(node, UseInfo::AnyTagged(),
                      MachineRepresentation::kTaggedPointer);
3259
        if (lower<T>()) {
3260
          // Try to optimize the {node} based on the input type.
3261
          if (input_type.Is(Type::Receiver())) {
3262
            DeferReplacement(node, node->InputAt(0));
3263
          } else if (input_type.Is(Type::NullOrUndefined())) {
3264
            DeferReplacement(node, node->InputAt(1));
3265
          } else if (!input_type.Maybe(Type::NullOrUndefined())) {
3266 3267 3268 3269 3270 3271 3272
            NodeProperties::ChangeOp(
                node, lowering->simplified()->ConvertReceiver(
                          ConvertReceiverMode::kNotNullOrUndefined));
          }
        }
        return;
      }
3273 3274
      case IrOpcode::kPlainPrimitiveToNumber: {
        if (InputIs(node, Type::Boolean())) {
3275
          VisitUnop<T>(node, UseInfo::Bool(), MachineRepresentation::kWord32);
3276
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3277
        } else if (InputIs(node, Type::String())) {
3278 3279
          VisitUnop<T>(node, UseInfo::AnyTagged(),
                       MachineRepresentation::kTagged);
3280
          if (lower<T>()) {
3281 3282
            NodeProperties::ChangeOp(node, simplified()->StringToNumber());
          }
3283
        } else if (truncation.IsUsedAsWord32()) {
3284
          if (InputIs(node, Type::NumberOrOddball())) {
3285 3286
            VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                         MachineRepresentation::kWord32);
3287
            if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3288
          } else {
3289 3290
            VisitUnop<T>(node, UseInfo::AnyTagged(),
                         MachineRepresentation::kWord32);
3291
            if (lower<T>()) {
3292 3293 3294
              NodeProperties::ChangeOp(node,
                                       simplified()->PlainPrimitiveToWord32());
            }
3295
          }
3296
        } else if (truncation.TruncatesOddballAndBigIntToNumber()) {
3297
          if (InputIs(node, Type::NumberOrOddball())) {
3298 3299
            VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                         MachineRepresentation::kFloat64);
3300
            if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3301
          } else {
3302 3303
            VisitUnop<T>(node, UseInfo::AnyTagged(),
                         MachineRepresentation::kFloat64);
3304
            if (lower<T>()) {
3305 3306 3307
              NodeProperties::ChangeOp(node,
                                       simplified()->PlainPrimitiveToFloat64());
            }
3308 3309
          }
        } else {
3310 3311
          VisitUnop<T>(node, UseInfo::AnyTagged(),
                       MachineRepresentation::kTagged);
3312 3313
        }
        return;
3314
      }
3315
      case IrOpcode::kSpeculativeToNumber: {
3316 3317 3318
        NumberOperationParameters const& p =
            NumberOperationParametersOf(node->op());
        switch (p.hint()) {
3319 3320
          case NumberOperationHint::kSignedSmall:
          case NumberOperationHint::kSignedSmallInputs:
3321 3322 3323
            VisitUnop<T>(node,
                         CheckedUseInfoAsWord32FromHint(p.hint(), p.feedback()),
                         MachineRepresentation::kWord32, Type::Signed32());
3324 3325
            break;
          case NumberOperationHint::kNumber:
3326
          case NumberOperationHint::kNumberOrBoolean:
3327
          case NumberOperationHint::kNumberOrOddball:
3328 3329 3330
            VisitUnop<T>(
                node, CheckedUseInfoAsFloat64FromHint(p.hint(), p.feedback()),
                MachineRepresentation::kFloat64);
3331 3332
            break;
        }
3333
        if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3334 3335
        return;
      }
3336 3337
      case IrOpcode::kObjectIsArrayBufferView: {
        // TODO(turbofan): Introduce a Type::ArrayBufferView?
3338
        VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3339 3340
        return;
      }
3341
      case IrOpcode::kObjectIsBigInt: {
3342
        VisitObjectIs<T>(node, Type::BigInt(), lowering);
3343 3344
        return;
      }
3345
      case IrOpcode::kObjectIsCallable: {
3346
        VisitObjectIs<T>(node, Type::Callable(), lowering);
3347 3348
        return;
      }
3349 3350
      case IrOpcode::kObjectIsConstructor: {
        // TODO(turbofan): Introduce a Type::Constructor?
3351
        VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3352 3353
        return;
      }
3354
      case IrOpcode::kObjectIsDetectableCallable: {
3355
        VisitObjectIs<T>(node, Type::DetectableCallable(), lowering);
3356 3357
        return;
      }
3358
      case IrOpcode::kObjectIsFiniteNumber: {
3359
        Type const input_type = GetUpperBound(node->InputAt(0));
3360
        if (input_type.Is(type_cache_->kSafeInteger)) {
3361
          VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3362
          if (lower<T>()) {
3363 3364
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
          }
3365
        } else if (!input_type.Maybe(Type::Number())) {
3366
          VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3367
          if (lower<T>()) {
3368 3369
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
          }
3370
        } else if (input_type.Is(Type::Number())) {
3371 3372
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kBit);
3373
          if (lower<T>()) {
3374 3375 3376 3377
            NodeProperties::ChangeOp(node,
                                     lowering->simplified()->NumberIsFinite());
          }
        } else {
3378
          VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3379 3380 3381 3382
        }
        return;
      }
      case IrOpcode::kNumberIsFinite: {
3383 3384
        VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                     MachineRepresentation::kBit);
3385
        return;
3386
      }
3387
      case IrOpcode::kObjectIsSafeInteger: {
3388
        Type const input_type = GetUpperBound(node->InputAt(0));
3389
        if (input_type.Is(type_cache_->kSafeInteger)) {
3390
          VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3391
          if (lower<T>()) {
3392 3393
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
          }
3394
        } else if (!input_type.Maybe(Type::Number())) {
3395
          VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3396
          if (lower<T>()) {
3397 3398
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
          }
3399
        } else if (input_type.Is(Type::Number())) {
3400 3401
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kBit);
3402
          if (lower<T>()) {
3403 3404 3405 3406
            NodeProperties::ChangeOp(
                node, lowering->simplified()->NumberIsSafeInteger());
          }
        } else {
3407
          VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3408 3409 3410 3411 3412 3413
        }
        return;
      }
      case IrOpcode::kNumberIsSafeInteger: {
        UNREACHABLE();
      }
3414
      case IrOpcode::kObjectIsInteger: {
3415
        Type const input_type = GetUpperBound(node->InputAt(0));
3416
        if (input_type.Is(type_cache_->kSafeInteger)) {
3417
          VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3418
          if (lower<T>()) {
3419 3420
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
          }
3421
        } else if (!input_type.Maybe(Type::Number())) {
3422
          VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3423
          if (lower<T>()) {
3424 3425
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
          }
3426
        } else if (input_type.Is(Type::Number())) {
3427 3428
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kBit);
3429
          if (lower<T>()) {
3430 3431 3432 3433
            NodeProperties::ChangeOp(node,
                                     lowering->simplified()->NumberIsInteger());
          }
        } else {
3434
          VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3435 3436 3437 3438
        }
        return;
      }
      case IrOpcode::kNumberIsInteger: {
3439 3440
        VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                     MachineRepresentation::kBit);
3441 3442
        return;
      }
3443
      case IrOpcode::kObjectIsMinusZero: {
3444
        Type const input_type = GetUpperBound(node->InputAt(0));
3445
        if (input_type.Is(Type::MinusZero())) {
3446
          VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3447
          if (lower<T>()) {
3448 3449
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
          }
3450
        } else if (!input_type.Maybe(Type::MinusZero())) {
3451
          VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3452
          if (lower<T>()) {
3453 3454
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
          }
3455
        } else if (input_type.Is(Type::Number())) {
3456 3457
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kBit);
3458
          if (lower<T>()) {
3459
            NodeProperties::ChangeOp(node, simplified()->NumberIsMinusZero());
3460 3461
          }
        } else {
3462
          VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3463 3464 3465
        }
        return;
      }
3466
      case IrOpcode::kObjectIsNaN: {
3467
        Type const input_type = GetUpperBound(node->InputAt(0));
3468
        if (input_type.Is(Type::NaN())) {
3469
          VisitUnop<T>(node, UseInfo::None(), MachineRepresentation::kBit);
3470
          if (lower<T>()) {
3471 3472
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(1));
          }
3473
        } else if (!input_type.Maybe(Type::NaN())) {
3474
          VisitUnop<T>(node, UseInfo::Any(), MachineRepresentation::kBit);
3475
          if (lower<T>()) {
3476 3477
            DeferReplacement(node, lowering->jsgraph()->Int32Constant(0));
          }
3478
        } else if (input_type.Is(Type::Number())) {
3479 3480
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kBit);
3481
          if (lower<T>()) {
3482
            NodeProperties::ChangeOp(node, simplified()->NumberIsNaN());
3483 3484
          }
        } else {
3485
          VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3486 3487 3488
        }
        return;
      }
3489
      case IrOpcode::kNumberIsNaN: {
3490 3491
        VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                     MachineRepresentation::kBit);
3492 3493
        return;
      }
3494
      case IrOpcode::kObjectIsNonCallable: {
3495
        VisitObjectIs<T>(node, Type::NonCallable(), lowering);
3496 3497 3498
        return;
      }
      case IrOpcode::kObjectIsNumber: {
3499
        VisitObjectIs<T>(node, Type::Number(), lowering);
3500 3501 3502
        return;
      }
      case IrOpcode::kObjectIsReceiver: {
3503
        VisitObjectIs<T>(node, Type::Receiver(), lowering);
3504 3505 3506 3507
        return;
      }
      case IrOpcode::kObjectIsSmi: {
        // TODO(turbofan): Optimize based on input representation.
3508
        VisitUnop<T>(node, UseInfo::AnyTagged(), MachineRepresentation::kBit);
3509 3510 3511
        return;
      }
      case IrOpcode::kObjectIsString: {
3512
        VisitObjectIs<T>(node, Type::String(), lowering);
3513 3514
        return;
      }
3515
      case IrOpcode::kObjectIsSymbol: {
3516
        VisitObjectIs<T>(node, Type::Symbol(), lowering);
3517 3518
        return;
      }
3519
      case IrOpcode::kObjectIsUndetectable: {
3520
        VisitObjectIs<T>(node, Type::Undetectable(), lowering);
3521 3522
        return;
      }
3523
      case IrOpcode::kArgumentsFrame: {
3524
        SetOutput<T>(node, MachineType::PointerRepresentation());
3525 3526
        return;
      }
3527 3528
      case IrOpcode::kArgumentsLength:
      case IrOpcode::kRestLength: {
3529 3530
        VisitUnop<T>(node, UseInfo::Word(),
                     MachineRepresentation::kTaggedSigned);
3531 3532
        return;
      }
3533 3534
      case IrOpcode::kNewDoubleElements:
      case IrOpcode::kNewSmiOrObjectElements: {
3535 3536
        VisitUnop<T>(node, UseInfo::Word(),
                     MachineRepresentation::kTaggedPointer);
3537 3538
        return;
      }
3539
      case IrOpcode::kNewArgumentsElements: {
3540 3541
        VisitBinop<T>(node, UseInfo::Word(), UseInfo::TaggedSigned(),
                      MachineRepresentation::kTaggedPointer);
3542 3543
        return;
      }
3544
      case IrOpcode::kCheckFloat64Hole: {
3545
        Type const input_type = TypeOf(node->InputAt(0));
3546 3547 3548 3549 3550 3551
        CheckFloat64HoleMode mode =
            CheckFloat64HoleParametersOf(node->op()).mode();
        if (mode == CheckFloat64HoleMode::kAllowReturnHole) {
          // If {mode} is allow-return-hole _and_ the {truncation}
          // identifies NaN and undefined, we can just pass along
          // the {truncation} and completely wipe the {node}.
3552
          if (truncation.IsUnused()) return VisitUnused<T>(node);
3553
          if (truncation.TruncatesOddballAndBigIntToNumber()) {
3554 3555
            VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                         MachineRepresentation::kFloat64);
3556
            if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3557 3558 3559
            return;
          }
        }
3560 3561 3562
        VisitUnop<T>(
            node, UseInfo(MachineRepresentation::kFloat64, Truncation::Any()),
            MachineRepresentation::kFloat64, Type::Number());
3563
        if (lower<T>() && input_type.Is(Type::Number())) {
3564
          DeferReplacement(node, node->InputAt(0));
3565 3566 3567
        }
        return;
      }
3568
      case IrOpcode::kCheckNotTaggedHole: {
3569 3570
        VisitUnop<T>(node, UseInfo::AnyTagged(),
                     MachineRepresentation::kTagged);
3571 3572
        return;
      }
3573
      case IrOpcode::kCheckClosure: {
3574 3575 3576
        VisitUnop<T>(
            node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
            MachineRepresentation::kTaggedPointer);
3577 3578
        return;
      }
3579 3580 3581 3582
      case IrOpcode::kConvertTaggedHoleToUndefined: {
        if (InputIs(node, Type::NumberOrOddball()) &&
            truncation.IsUsedAsWord32()) {
          // Propagate the Word32 truncation.
3583 3584
          VisitUnop<T>(node, UseInfo::TruncatingWord32(),
                       MachineRepresentation::kWord32);
3585
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3586
        } else if (InputIs(node, Type::NumberOrOddball()) &&
3587
                   truncation.TruncatesOddballAndBigIntToNumber()) {
3588
          // Propagate the Float64 truncation.
3589 3590
          VisitUnop<T>(node, UseInfo::TruncatingFloat64(),
                       MachineRepresentation::kFloat64);
3591
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3592
        } else if (InputIs(node, Type::NonInternal())) {
3593 3594
          VisitUnop<T>(node, UseInfo::AnyTagged(),
                       MachineRepresentation::kTagged);
3595
          if (lower<T>()) DeferReplacement(node, node->InputAt(0));
3596
        } else {
3597 3598
          // TODO(turbofan): Add a (Tagged) truncation that identifies hole
          // and undefined, i.e. for a[i] === obj cases.
3599 3600
          VisitUnop<T>(node, UseInfo::AnyTagged(),
                       MachineRepresentation::kTagged);
3601
        }
3602 3603
        return;
      }
3604 3605
      case IrOpcode::kCheckEqualsSymbol:
      case IrOpcode::kCheckEqualsInternalizedString:
3606 3607
        return VisitBinop<T>(node, UseInfo::AnyTagged(),
                             MachineRepresentation::kNone);
3608 3609
      case IrOpcode::kMapGuard:
        // Eliminate MapGuard nodes here.
3610
        return VisitUnused<T>(node);
3611 3612
      case IrOpcode::kCheckMaps: {
        CheckMapsParameters const& p = CheckMapsParametersOf(node->op());
3613
        return VisitUnop<T>(
3614 3615 3616
            node, UseInfo::CheckedHeapObjectAsTaggedPointer(p.feedback()),
            MachineRepresentation::kNone);
      }
3617 3618 3619 3620 3621
      case IrOpcode::kDynamicCheckMaps: {
        return VisitUnop<T>(
            node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
            MachineRepresentation::kNone);
      }
3622
      case IrOpcode::kTransitionElementsKind: {
3623
        return VisitUnop<T>(
3624
            node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3625
            MachineRepresentation::kNone);
3626
      }
3627
      case IrOpcode::kCompareMaps:
3628
        return VisitUnop<T>(
3629
            node, UseInfo::CheckedHeapObjectAsTaggedPointer(FeedbackSource()),
3630
            MachineRepresentation::kBit);
3631
      case IrOpcode::kEnsureWritableFastElements:
3632 3633
        return VisitBinop<T>(node, UseInfo::AnyTagged(),
                             MachineRepresentation::kTaggedPointer);
3634
      case IrOpcode::kMaybeGrowFastElements: {
3635 3636 3637 3638 3639 3640
        ProcessInput<T>(node, 0, UseInfo::AnyTagged());         // object
        ProcessInput<T>(node, 1, UseInfo::AnyTagged());         // elements
        ProcessInput<T>(node, 2, UseInfo::TruncatingWord32());  // index
        ProcessInput<T>(node, 3, UseInfo::TruncatingWord32());  // length
        ProcessRemainingInputs<T>(node, 4);
        SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3641 3642
        return;
      }
3643

3644
      case IrOpcode::kDateNow:
3645
        VisitInputs<T>(node);
3646
        return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3647
      case IrOpcode::kFrameState:
3648
        return VisitFrameState<T>(node);
3649
      case IrOpcode::kStateValues:
3650
        return VisitStateValues<T>(node);
3651
      case IrOpcode::kObjectState:
3652
        return VisitObjectState<T>(node);
3653
      case IrOpcode::kObjectId:
3654
        return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3655

3656
      case IrOpcode::kTypeGuard: {
3657 3658
        // We just get rid of the sigma here, choosing the best representation
        // for the sigma's type.
3659
        Type type = TypeOf(node);
3660
        MachineRepresentation representation =
3661
            GetOutputInfoForPhi(node, type, truncation);
3662

3663 3664 3665
        // Here we pretend that the input has the sigma's type for the
        // conversion.
        UseInfo use(representation, truncation);
3666
        if (propagate<T>()) {
3667
          EnqueueInput<T>(node, 0, use);
3668
        } else if (lower<T>()) {
3669 3670
          ConvertInput(node, 0, use, type);
        }
3671 3672
        ProcessRemainingInputs<T>(node, 1);
        SetOutput<T>(node, representation);
3673 3674
        return;
      }
3675

3676
      case IrOpcode::kFoldConstant:
3677
        VisitInputs<T>(node);
3678
        return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3679

3680
      case IrOpcode::kFinishRegion:
3681
        VisitInputs<T>(node);
3682
        // Assume the output is tagged pointer.
3683
        return SetOutput<T>(node, MachineRepresentation::kTaggedPointer);
3684

3685
      case IrOpcode::kReturn:
3686
        VisitReturn<T>(node);
3687
        // Assume the output is tagged.
3688
        return SetOutput<T>(node, MachineRepresentation::kTagged);
3689

3690
      case IrOpcode::kFindOrderedHashMapEntry: {
3691
        Type const key_type = TypeOf(node->InputAt(1));
3692
        if (key_type.Is(Type::Signed32OrMinusZero())) {
3693 3694
          VisitBinop<T>(node, UseInfo::AnyTagged(), UseInfo::TruncatingWord32(),
                        MachineType::PointerRepresentation());
3695
          if (lower<T>()) {
3696
            NodeProperties::ChangeOp(
3697 3698
                node,
                lowering->simplified()->FindOrderedHashMapEntryForInt32Key());
3699 3700
          }
        } else {
3701 3702
          VisitBinop<T>(node, UseInfo::AnyTagged(),
                        MachineRepresentation::kTaggedSigned);
3703
        }
3704 3705
        return;
      }
3706

3707
      case IrOpcode::kFastApiCall: {
3708
        VisitFastApiCall<T>(node, lowering);
3709 3710 3711
        return;
      }

3712 3713 3714 3715 3716 3717 3718
      // Operators with all inputs tagged and no or tagged output have uniform
      // handling.
      case IrOpcode::kEnd:
      case IrOpcode::kIfSuccess:
      case IrOpcode::kIfException:
      case IrOpcode::kIfTrue:
      case IrOpcode::kIfFalse:
3719 3720
      case IrOpcode::kIfValue:
      case IrOpcode::kIfDefault:
3721 3722 3723 3724 3725 3726 3727 3728 3729
      case IrOpcode::kDeoptimize:
      case IrOpcode::kEffectPhi:
      case IrOpcode::kTerminate:
      case IrOpcode::kCheckpoint:
      case IrOpcode::kLoop:
      case IrOpcode::kMerge:
      case IrOpcode::kThrow:
      case IrOpcode::kBeginRegion:
      case IrOpcode::kProjection:
3730
      case IrOpcode::kOsrValue:
3731
      case IrOpcode::kArgumentsElementsState:
3732
      case IrOpcode::kArgumentsLengthState:
3733
      case IrOpcode::kUnreachable:
3734
      case IrOpcode::kRuntimeAbort:
3735
// All JavaScript operators except JSToNumber have uniform handling.
3736
#define OPCODE_CASE(name, ...) case IrOpcode::k##name:
3737 3738 3739 3740 3741
        JS_SIMPLE_BINOP_LIST(OPCODE_CASE)
        JS_OBJECT_OP_LIST(OPCODE_CASE)
        JS_CONTEXT_OP_LIST(OPCODE_CASE)
        JS_OTHER_OP_LIST(OPCODE_CASE)
#undef OPCODE_CASE
3742
      case IrOpcode::kJSBitwiseNot:
3743 3744
      case IrOpcode::kJSDecrement:
      case IrOpcode::kJSIncrement:
3745
      case IrOpcode::kJSNegate:
3746 3747 3748 3749
      case IrOpcode::kJSToLength:
      case IrOpcode::kJSToName:
      case IrOpcode::kJSToObject:
      case IrOpcode::kJSToString:
3750
      case IrOpcode::kJSParseInt:
3751
        VisitInputs<T>(node);
3752
        // Assume the output is tagged.
3753
        return SetOutput<T>(node, MachineRepresentation::kTagged);
3754
      case IrOpcode::kDeadValue:
3755 3756
        ProcessInput<T>(node, 0, UseInfo::Any());
        return SetOutput<T>(node, MachineRepresentation::kNone);
3757
      case IrOpcode::kStaticAssert:
3758 3759
        return VisitUnop<T>(node, UseInfo::Any(),
                            MachineRepresentation::kTagged);
3760
      case IrOpcode::kAssertType:
3761 3762
        return VisitUnop<T>(node, UseInfo::AnyTagged(),
                            MachineRepresentation::kTagged);
3763
      default:
3764
        FATAL(
3765 3766
            "Representation inference: unsupported opcode %i (%s), node #%i\n.",
            node->opcode(), node->op()->mnemonic(), node->id());
3767
        break;
3768
    }
3769
    UNREACHABLE();
3770 3771 3772
  }

  void DeferReplacement(Node* node, Node* replacement) {
3773 3774 3775 3776
    TRACE("defer replacement #%d:%s with #%d:%s\n", node->id(),
          node->op()->mnemonic(), replacement->id(),
          replacement->op()->mnemonic());

3777 3778 3779 3780 3781 3782 3783 3784 3785
    // Disconnect the node from effect and control chains, if necessary.
    if (node->op()->EffectInputCount() > 0) {
      DCHECK_LT(0, node->op()->ControlInputCount());
      // Disconnect the node from effect and control chains.
      Node* control = NodeProperties::GetControlInput(node);
      Node* effect = NodeProperties::GetEffectInput(node);
      ReplaceEffectControlUses(node, effect, control);
    }

3786 3787 3788
    replacements_.push_back(node);
    replacements_.push_back(replacement);

3789
    node->NullAllInputs();  // Node is now dead.
3790 3791
  }

3792 3793 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806
  void Kill(Node* node) {
    TRACE("killing #%d:%s\n", node->id(), node->op()->mnemonic());

    if (node->op()->EffectInputCount() == 1) {
      DCHECK_LT(0, node->op()->ControlInputCount());
      // Disconnect the node from effect and control chains.
      Node* control = NodeProperties::GetControlInput(node);
      Node* effect = NodeProperties::GetEffectInput(node);
      ReplaceEffectControlUses(node, effect, control);
    } else {
      DCHECK_EQ(0, node->op()->EffectInputCount());
      DCHECK_EQ(0, node->op()->ControlOutputCount());
      DCHECK_EQ(0, node->op()->EffectOutputCount());
    }

3807
    node->ReplaceUses(jsgraph_->Dead());
3808 3809 3810 3811

    node->NullAllInputs();  // The {node} is now dead.
  }

3812 3813
 private:
  JSGraph* jsgraph_;
3814
  Zone* zone_;                      // Temporary zone.
3815 3816
  // Map from node to its uses that might need to be revisited.
  ZoneMap<Node*, ZoneVector<Node*>> might_need_revisit_;
3817
  size_t const count_;              // number of nodes in the graph
3818
  ZoneVector<NodeInfo> info_;       // node id -> usage information
3819 3820 3821 3822
#ifdef DEBUG
  ZoneVector<InputUseInfos> node_input_use_infos_;  // Debug information about
                                                    // requirements on inputs.
#endif                                              // DEBUG
3823 3824
  NodeVector replacements_;         // replacements to be done after lowering
  RepresentationChanger* changer_;  // for inserting representation changes
3825
  ZoneQueue<Node*> revisit_queue_;  // Queue for revisiting nodes.
3826 3827 3828 3829 3830

  struct NodeState {
    Node* node;
    int input_index;
  };
3831
  NodeVector traversal_nodes_;  // Order in which to traverse the nodes.
3832 3833 3834 3835 3836 3837
  // TODO(danno): RepresentationSelector shouldn't know anything about the
  // source positions table, but must for now since there currently is no other
  // way to pass down source position information to nodes created during
  // lowering. Once this phase becomes a vanilla reducer, it should get source
  // position information via the SourcePositionWrapper like all other reducers.
  SourcePositionTable* source_positions_;
3838
  NodeOriginTable* node_origins_;
3839
  TypeCache const* type_cache_;
3840
  OperationTyper op_typer_;  // helper for the feedback typer
3841
  TickCounter* const tick_counter_;
3842
  Linkage* const linkage_;
3843 3844 3845 3846 3847

  NodeInfo* GetInfo(Node* node) {
    DCHECK(node->id() < count_);
    return &info_[node->id()];
  }
3848 3849
  Zone* zone() { return zone_; }
  Zone* graph_zone() { return jsgraph_->zone(); }
3850
  Linkage* linkage() { return linkage_; }
3851 3852
};

3853
// Template specializations
3854 3855

// Enqueue {use_node}'s {index} input if the {use_info} contains new information
3856
// for that input node.
3857 3858 3859 3860 3861 3862 3863 3864 3865 3866 3867 3868
template <>
void RepresentationSelector::EnqueueInput<PROPAGATE>(Node* use_node, int index,
                                                     UseInfo use_info) {
  Node* node = use_node->InputAt(index);
  NodeInfo* info = GetInfo(node);
#ifdef DEBUG
  // Check monotonicity of input requirements.
  node_input_use_infos_[use_node->id()].SetAndCheckInput(use_node, index,
                                                         use_info);
#endif  // DEBUG
  if (info->unvisited()) {
    info->AddUse(use_info);
3869
    TRACE("  initial #%i: %s\n", node->id(), info->truncation().description());
3870 3871
    return;
  }
3872
  TRACE("   queue #%i?: %s\n", node->id(), info->truncation().description());
3873 3874 3875 3876
  if (info->AddUse(use_info)) {
    // New usage information for the node is available.
    if (!info->queued()) {
      DCHECK(info->visited());
3877
      revisit_queue_.push(node);
3878
      info->set_queued();
3879
      TRACE("   added: %s\n", info->truncation().description());
3880
    } else {
3881
      TRACE(" inqueue: %s\n", info->truncation().description());
3882 3883 3884 3885
    }
  }
}

3886 3887 3888 3889 3890 3891 3892 3893 3894 3895 3896 3897 3898 3899 3900 3901 3902 3903 3904 3905 3906 3907 3908 3909 3910 3911 3912 3913 3914 3915 3916 3917
template <>
void RepresentationSelector::SetOutput<PROPAGATE>(
    Node* node, MachineRepresentation representation, Type restriction_type) {
  NodeInfo* const info = GetInfo(node);
  info->set_restriction_type(restriction_type);
}

template <>
void RepresentationSelector::SetOutput<RETYPE>(
    Node* node, MachineRepresentation representation, Type restriction_type) {
  NodeInfo* const info = GetInfo(node);
  DCHECK(info->restriction_type().Is(restriction_type));
  DCHECK(restriction_type.Is(info->restriction_type()));
  info->set_output(representation);
}

template <>
void RepresentationSelector::SetOutput<LOWER>(
    Node* node, MachineRepresentation representation, Type restriction_type) {
  NodeInfo* const info = GetInfo(node);
  DCHECK_EQ(info->representation(), representation);
  DCHECK(info->restriction_type().Is(restriction_type));
  DCHECK(restriction_type.Is(info->restriction_type()));
  USE(info);
}

template <>
void RepresentationSelector::ProcessInput<PROPAGATE>(Node* node, int index,
                                                     UseInfo use) {
  DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
                 !node->op()->HasProperty(Operator::kNoDeopt) &&
                     node->op()->EffectInputCount() > 0);
3918
  EnqueueInput<PROPAGATE>(node, index, use);
3919 3920 3921 3922 3923 3924 3925 3926 3927 3928 3929 3930 3931 3932 3933 3934 3935 3936 3937 3938 3939 3940 3941
}

template <>
void RepresentationSelector::ProcessInput<RETYPE>(Node* node, int index,
                                                  UseInfo use) {
  DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
                 !node->op()->HasProperty(Operator::kNoDeopt) &&
                     node->op()->EffectInputCount() > 0);
}

template <>
void RepresentationSelector::ProcessInput<LOWER>(Node* node, int index,
                                                 UseInfo use) {
  DCHECK_IMPLIES(use.type_check() != TypeCheckKind::kNone,
                 !node->op()->HasProperty(Operator::kNoDeopt) &&
                     node->op()->EffectInputCount() > 0);
  ConvertInput(node, index, use);
}

template <>
void RepresentationSelector::ProcessRemainingInputs<PROPAGATE>(Node* node,
                                                               int index) {
  DCHECK_GE(index, NodeProperties::PastContextIndex(node));
3942 3943

  // Enqueue other inputs (effects, control).
3944
  for (int i = std::max(index, NodeProperties::FirstEffectIndex(node));
3945 3946
       i < node->InputCount(); ++i) {
    EnqueueInput<PROPAGATE>(node, i);
3947 3948 3949
  }
}

3950 3951 3952 3953 3954 3955
// The default, most general visitation case. For {node}, process all value,
// context, frame state, effect, and control inputs, assuming that value
// inputs should have {kRepTagged} representation and can observe all output
// values {kTypeAny}.
template <>
void RepresentationSelector::VisitInputs<PROPAGATE>(Node* node) {
3956
  int first_effect_index = NodeProperties::FirstEffectIndex(node);
3957
  // Visit value, context and frame state inputs as tagged.
3958
  for (int i = 0; i < first_effect_index; i++) {
3959 3960 3961
    ProcessInput<PROPAGATE>(node, i, UseInfo::AnyTagged());
  }
  // Only enqueue other inputs (effects, control).
3962
  for (int i = first_effect_index; i < node->InputCount(); i++) {
3963 3964 3965 3966 3967 3968
    EnqueueInput<PROPAGATE>(node, i);
  }
}

template <>
void RepresentationSelector::VisitInputs<LOWER>(Node* node) {
3969
  int first_effect_index = NodeProperties::FirstEffectIndex(node);
3970
  // Visit value, context and frame state inputs as tagged.
3971
  for (int i = 0; i < first_effect_index; i++) {
3972 3973 3974 3975
    ProcessInput<LOWER>(node, i, UseInfo::AnyTagged());
  }
}

3976 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 4008
template <>
void RepresentationSelector::InsertUnreachableIfNecessary<LOWER>(Node* node) {
  // If the node is effectful and it produces an impossible value, then we
  // insert Unreachable node after it.
  if (node->op()->ValueOutputCount() > 0 &&
      node->op()->EffectOutputCount() > 0 &&
      node->opcode() != IrOpcode::kUnreachable && TypeOf(node).IsNone()) {
    Node* control = (node->op()->ControlOutputCount() == 0)
                        ? NodeProperties::GetControlInput(node, 0)
                        : NodeProperties::FindSuccessfulControlProjection(node);

    Node* unreachable =
        graph()->NewNode(common()->Unreachable(), node, control);

    // Insert unreachable node and replace all the effect uses of the {node}
    // with the new unreachable node.
    for (Edge edge : node->use_edges()) {
      if (!NodeProperties::IsEffectEdge(edge)) continue;
      // Make sure to not overwrite the unreachable node's input. That would
      // create a cycle.
      if (edge.from() == unreachable) continue;
      // Avoid messing up the exceptional path.
      if (edge.from()->opcode() == IrOpcode::kIfException) {
        DCHECK(!node->op()->HasProperty(Operator::kNoThrow));
        DCHECK_EQ(NodeProperties::GetControlInput(edge.from()), node);
        continue;
      }

      edge.UpdateTo(unreachable);
    }
  }
}

4009 4010
SimplifiedLowering::SimplifiedLowering(JSGraph* jsgraph, JSHeapBroker* broker,
                                       Zone* zone,
4011
                                       SourcePositionTable* source_positions,
4012
                                       NodeOriginTable* node_origins,
4013
                                       PoisoningMitigationLevel poisoning_level,
4014 4015
                                       TickCounter* tick_counter,
                                       Linkage* linkage)
4016
    : jsgraph_(jsgraph),
4017
      broker_(broker),
4018
      zone_(zone),
4019
      type_cache_(TypeCache::Get()),
4020
      source_positions_(source_positions),
4021
      node_origins_(node_origins),
4022
      poisoning_level_(poisoning_level),
4023 4024
      tick_counter_(tick_counter),
      linkage_(linkage) {}
4025

4026
void SimplifiedLowering::LowerAllNodes() {
4027
  RepresentationChanger changer(jsgraph(), broker_);
4028
  RepresentationSelector selector(jsgraph(), broker_, zone_, &changer,
4029
                                  source_positions_, node_origins_,
4030
                                  tick_counter_, linkage_);
4031 4032 4033
  selector.Run(this);
}

4034
void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToFloat64(
4035
    Node* node, RepresentationSelector* selector) {
4036
  DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
4037
         node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
4038
         node->opcode() == IrOpcode::kJSToNumeric);
4039 4040 4041 4042 4043 4044 4045 4046 4047 4048 4049 4050 4051 4052
  Node* value = node->InputAt(0);
  Node* context = node->InputAt(1);
  Node* frame_state = node->InputAt(2);
  Node* effect = node->InputAt(3);
  Node* control = node->InputAt(4);

  Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* etrue0 = effect;
  Node* vtrue0;
  {
4053
    vtrue0 = graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
4054 4055 4056 4057 4058 4059 4060
    vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
  }

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0;
  {
4061 4062 4063 4064 4065 4066 4067 4068 4069 4070 4071
    Operator const* op =
        node->opcode() == IrOpcode::kJSToNumber
            ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
                   ? ToNumberConvertBigIntOperator()
                   : ToNumberOperator())
            : ToNumericOperator();
    Node* code = node->opcode() == IrOpcode::kJSToNumber
                     ? ToNumberCode()
                     : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
                            ? ToNumberConvertBigIntCode()
                            : ToNumericCode());
4072 4073
    vfalse0 = efalse0 = if_false0 = graph()->NewNode(
        op, code, value, context, frame_state, efalse0, if_false0);
4074 4075

    // Update potential {IfException} uses of {node} to point to the above
4076
    // stub call node instead.
4077 4078 4079 4080 4081 4082
    Node* on_exception = nullptr;
    if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
      NodeProperties::ReplaceControlInput(on_exception, vfalse0);
      NodeProperties::ReplaceEffectInput(on_exception, efalse0);
      if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
    }
4083 4084 4085 4086 4087 4088 4089 4090

    Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = efalse0;
    Node* vtrue1;
    {
4091 4092
      vtrue1 =
          graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
4093 4094 4095 4096 4097 4098 4099 4100 4101 4102 4103 4104 4105 4106 4107 4108 4109 4110 4111 4112 4113 4114 4115 4116 4117 4118 4119 4120 4121 4122 4123 4124
      vtrue1 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue1);
    }

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* efalse1 = efalse0;
    Node* vfalse1;
    {
      vfalse1 = efalse1 = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
          efalse1, if_false1);
    }

    if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
    efalse0 =
        graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
    vfalse0 =
        graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                         vtrue1, vfalse1, if_false0);
  }

  control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                           vtrue0, vfalse0, control);

  // Replace effect and control uses appropriately.
  for (Edge edge : node->use_edges()) {
    if (NodeProperties::IsControlEdge(edge)) {
      if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
        edge.from()->ReplaceUses(control);
        edge.from()->Kill();
      } else {
4125
        DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
4126
        edge.UpdateTo(control);
4127 4128 4129 4130 4131 4132 4133 4134 4135
      }
    } else if (NodeProperties::IsEffectEdge(edge)) {
      edge.UpdateTo(effect);
    }
  }

  selector->DeferReplacement(node, value);
}

4136
void SimplifiedLowering::DoJSToNumberOrNumericTruncatesToWord32(
4137
    Node* node, RepresentationSelector* selector) {
4138
  DCHECK(node->opcode() == IrOpcode::kJSToNumber ||
4139
         node->opcode() == IrOpcode::kJSToNumberConvertBigInt ||
4140
         node->opcode() == IrOpcode::kJSToNumeric);
4141 4142 4143 4144 4145 4146 4147 4148 4149 4150 4151 4152
  Node* value = node->InputAt(0);
  Node* context = node->InputAt(1);
  Node* frame_state = node->InputAt(2);
  Node* effect = node->InputAt(3);
  Node* control = node->InputAt(4);

  Node* check0 = graph()->NewNode(simplified()->ObjectIsSmi(), value);
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* etrue0 = effect;
4153 4154
  Node* vtrue0 =
      graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), value);
4155 4156 4157 4158 4159

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0;
  {
4160 4161 4162 4163 4164 4165 4166 4167 4168 4169 4170
    Operator const* op =
        node->opcode() == IrOpcode::kJSToNumber
            ? (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
                   ? ToNumberConvertBigIntOperator()
                   : ToNumberOperator())
            : ToNumericOperator();
    Node* code = node->opcode() == IrOpcode::kJSToNumber
                     ? ToNumberCode()
                     : (node->opcode() == IrOpcode::kJSToNumberConvertBigInt
                            ? ToNumberConvertBigIntCode()
                            : ToNumericCode());
4171 4172
    vfalse0 = efalse0 = if_false0 = graph()->NewNode(
        op, code, value, context, frame_state, efalse0, if_false0);
4173 4174

    // Update potential {IfException} uses of {node} to point to the above
4175
    // stub call node instead.
4176 4177 4178 4179 4180 4181
    Node* on_exception = nullptr;
    if (NodeProperties::IsExceptionalCall(node, &on_exception)) {
      NodeProperties::ReplaceControlInput(on_exception, vfalse0);
      NodeProperties::ReplaceEffectInput(on_exception, efalse0);
      if_false0 = graph()->NewNode(common()->IfSuccess(), vfalse0);
    }
4182 4183 4184 4185 4186 4187

    Node* check1 = graph()->NewNode(simplified()->ObjectIsSmi(), vfalse0);
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = efalse0;
4188 4189
    Node* vtrue1 =
        graph()->NewNode(simplified()->ChangeTaggedSignedToInt32(), vfalse0);
4190 4191 4192 4193 4194 4195 4196 4197

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* efalse1 = efalse0;
    Node* vfalse1;
    {
      vfalse1 = efalse1 = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), efalse0,
          efalse1, if_false1);
4198
      vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
4199 4200 4201 4202 4203 4204 4205 4206 4207 4208 4209 4210 4211 4212 4213 4214 4215 4216 4217 4218 4219
    }

    if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
    efalse0 =
        graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);
    vfalse0 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                               vtrue1, vfalse1, if_false0);
  }

  control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                           vtrue0, vfalse0, control);

  // Replace effect and control uses appropriately.
  for (Edge edge : node->use_edges()) {
    if (NodeProperties::IsControlEdge(edge)) {
      if (edge.from()->opcode() == IrOpcode::kIfSuccess) {
        edge.from()->ReplaceUses(control);
        edge.from()->Kill();
      } else {
4220
        DCHECK_NE(IrOpcode::kIfException, edge.from()->opcode());
4221
        edge.UpdateTo(control);
4222 4223 4224 4225 4226 4227 4228 4229
      }
    } else if (NodeProperties::IsEffectEdge(edge)) {
      edge.UpdateTo(effect);
    }
  }

  selector->DeferReplacement(node, value);
}
4230

4231 4232 4233 4234 4235 4236
Node* SimplifiedLowering::Float64Round(Node* const node) {
  Node* const one = jsgraph()->Float64Constant(1.0);
  Node* const one_half = jsgraph()->Float64Constant(0.5);
  Node* const input = node->InputAt(0);

  // Round up towards Infinity, and adjust if the difference exceeds 0.5.
4237 4238
  Node* result = graph()->NewNode(machine()->Float64RoundUp().placeholder(),
                                  node->InputAt(0));
4239 4240 4241 4242 4243 4244 4245 4246
  return graph()->NewNode(
      common()->Select(MachineRepresentation::kFloat64),
      graph()->NewNode(
          machine()->Float64LessThanOrEqual(),
          graph()->NewNode(machine()->Float64Sub(), result, one_half), input),
      result, graph()->NewNode(machine()->Float64Sub(), result, one));
}

4247 4248 4249 4250 4251 4252 4253 4254 4255 4256 4257 4258 4259
Node* SimplifiedLowering::Float64Sign(Node* const node) {
  Node* const minus_one = jsgraph()->Float64Constant(-1.0);
  Node* const zero = jsgraph()->Float64Constant(0.0);
  Node* const one = jsgraph()->Float64Constant(1.0);

  Node* const input = node->InputAt(0);

  return graph()->NewNode(
      common()->Select(MachineRepresentation::kFloat64),
      graph()->NewNode(machine()->Float64LessThan(), input, zero), minus_one,
      graph()->NewNode(
          common()->Select(MachineRepresentation::kFloat64),
          graph()->NewNode(machine()->Float64LessThan(), zero, input), one,
jarin's avatar
jarin committed
4260
          input));
4261 4262
}

4263 4264 4265
Node* SimplifiedLowering::Int32Abs(Node* const node) {
  Node* const input = node->InputAt(0);

4266 4267 4268 4269 4270 4271 4272 4273 4274 4275
  // Generate case for absolute integer value.
  //
  //    let sign = input >> 31 in
  //    (input ^ sign) - sign

  Node* sign = graph()->NewNode(machine()->Word32Sar(), input,
                                jsgraph()->Int32Constant(31));
  return graph()->NewNode(machine()->Int32Sub(),
                          graph()->NewNode(machine()->Word32Xor(), input, sign),
                          sign);
4276 4277
}

4278 4279 4280
Node* SimplifiedLowering::Int32Div(Node* const node) {
  Int32BinopMatcher m(node);
  Node* const zero = jsgraph()->Int32Constant(0);
4281
  Node* const minus_one = jsgraph()->Int32Constant(-1);
4282 4283 4284 4285 4286 4287 4288
  Node* const lhs = m.left().node();
  Node* const rhs = m.right().node();

  if (m.right().Is(-1)) {
    return graph()->NewNode(machine()->Int32Sub(), zero, lhs);
  } else if (m.right().Is(0)) {
    return rhs;
4289
  } else if (machine()->Int32DivIsSafe() || m.right().HasResolvedValue()) {
4290 4291 4292
    return graph()->NewNode(machine()->Int32Div(), lhs, rhs, graph()->start());
  }

4293 4294 4295 4296 4297 4298 4299 4300 4301 4302 4303 4304 4305 4306 4307
  // General case for signed integer division.
  //
  //    if 0 < rhs then
  //      lhs / rhs
  //    else
  //      if rhs < -1 then
  //        lhs / rhs
  //      else if rhs == 0 then
  //        0
  //      else
  //        0 - lhs
  //
  // Note: We do not use the Diamond helper class here, because it really hurts
  // readability with nested diamonds.
  const Operator* const merge_op = common()->Merge(2);
4308 4309
  const Operator* const phi_op =
      common()->Phi(MachineRepresentation::kWord32, 2);
4310 4311 4312 4313 4314 4315 4316 4317 4318 4319 4320 4321 4322

  Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
  Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
                                   graph()->start());

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* true0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* false0;
  {
    Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4323

4324 4325 4326 4327 4328 4329 4330 4331 4332 4333 4334 4335 4336 4337 4338 4339 4340 4341 4342 4343 4344 4345
    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* true1 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true1);

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* false1;
    {
      Node* check2 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
      Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);

      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
      Node* true2 = zero;

      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
      Node* false2 = graph()->NewNode(machine()->Int32Sub(), zero, lhs);

      if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
      false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
    }

    if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
    false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
  }
4346

4347 4348
  Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
  return graph()->NewNode(phi_op, true0, false0, merge0);
4349 4350 4351 4352 4353
}

Node* SimplifiedLowering::Int32Mod(Node* const node) {
  Int32BinopMatcher m(node);
  Node* const zero = jsgraph()->Int32Constant(0);
4354
  Node* const minus_one = jsgraph()->Int32Constant(-1);
4355 4356 4357 4358 4359
  Node* const lhs = m.left().node();
  Node* const rhs = m.right().node();

  if (m.right().Is(-1) || m.right().Is(0)) {
    return zero;
4360
  } else if (m.right().HasResolvedValue()) {
4361 4362 4363
    return graph()->NewNode(machine()->Int32Mod(), lhs, rhs, graph()->start());
  }

4364 4365 4366 4367 4368 4369 4370 4371 4372 4373 4374 4375 4376 4377 4378 4379 4380 4381 4382 4383 4384
  // General case for signed integer modulus, with optimization for (unknown)
  // power of 2 right hand side.
  //
  //   if 0 < rhs then
  //     msk = rhs - 1
  //     if rhs & msk != 0 then
  //       lhs % rhs
  //     else
  //       if lhs < 0 then
  //         -(-lhs & msk)
  //       else
  //         lhs & msk
  //   else
  //     if rhs < -1 then
  //       lhs % rhs
  //     else
  //       zero
  //
  // Note: We do not use the Diamond helper class here, because it really hurts
  // readability with nested diamonds.
  const Operator* const merge_op = common()->Merge(2);
4385 4386
  const Operator* const phi_op =
      common()->Phi(MachineRepresentation::kWord32, 2);
4387 4388 4389 4390 4391 4392 4393 4394 4395 4396 4397 4398 4399 4400 4401 4402 4403 4404 4405 4406 4407 4408 4409 4410 4411 4412 4413 4414 4415 4416 4417 4418 4419 4420 4421 4422

  Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
  Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kTrue), check0,
                                   graph()->start());

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* true0;
  {
    Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);

    Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* false1;
    {
      Node* check2 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
      Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                       check2, if_false1);

      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
      Node* true2 = graph()->NewNode(
          machine()->Int32Sub(), zero,
          graph()->NewNode(machine()->Word32And(),
                           graph()->NewNode(machine()->Int32Sub(), zero, lhs),
                           msk));

      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
      Node* false2 = graph()->NewNode(machine()->Word32And(), lhs, msk);

      if_false1 = graph()->NewNode(merge_op, if_true2, if_false2);
      false1 = graph()->NewNode(phi_op, true2, false2, if_false1);
    }
4423

4424 4425 4426
    if_true0 = graph()->NewNode(merge_op, if_true1, if_false1);
    true0 = graph()->NewNode(phi_op, true1, false1, if_true0);
  }
4427

4428 4429 4430 4431 4432 4433 4434 4435 4436 4437 4438 4439 4440 4441 4442 4443 4444 4445 4446
  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* false0;
  {
    Node* check1 = graph()->NewNode(machine()->Int32LessThan(), rhs, minus_one);
    Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
                                     check1, if_false0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* true1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* false1 = zero;

    if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
    false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
  }

  Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
  return graph()->NewNode(phi_op, true0, false0, merge0);
4447 4448
}

4449 4450 4451 4452 4453 4454 4455 4456 4457 4458 4459 4460 4461 4462 4463
Node* SimplifiedLowering::Int32Sign(Node* const node) {
  Node* const minus_one = jsgraph()->Int32Constant(-1);
  Node* const zero = jsgraph()->Int32Constant(0);
  Node* const one = jsgraph()->Int32Constant(1);

  Node* const input = node->InputAt(0);

  return graph()->NewNode(
      common()->Select(MachineRepresentation::kWord32),
      graph()->NewNode(machine()->Int32LessThan(), input, zero), minus_one,
      graph()->NewNode(
          common()->Select(MachineRepresentation::kWord32),
          graph()->NewNode(machine()->Int32LessThan(), zero, input), one,
          zero));
}
4464 4465 4466 4467 4468 4469 4470 4471 4472

Node* SimplifiedLowering::Uint32Div(Node* const node) {
  Uint32BinopMatcher m(node);
  Node* const zero = jsgraph()->Uint32Constant(0);
  Node* const lhs = m.left().node();
  Node* const rhs = m.right().node();

  if (m.right().Is(0)) {
    return zero;
4473
  } else if (machine()->Uint32DivIsSafe() || m.right().HasResolvedValue()) {
4474 4475 4476 4477
    return graph()->NewNode(machine()->Uint32Div(), lhs, rhs, graph()->start());
  }

  Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
4478 4479
  Diamond d(graph(), common(), check, BranchHint::kFalse);
  Node* div = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, d.if_false);
4480
  return d.Phi(MachineRepresentation::kWord32, zero, div);
4481 4482 4483 4484
}

Node* SimplifiedLowering::Uint32Mod(Node* const node) {
  Uint32BinopMatcher m(node);
4485
  Node* const minus_one = jsgraph()->Int32Constant(-1);
4486 4487 4488 4489 4490 4491
  Node* const zero = jsgraph()->Uint32Constant(0);
  Node* const lhs = m.left().node();
  Node* const rhs = m.right().node();

  if (m.right().Is(0)) {
    return zero;
4492
  } else if (m.right().HasResolvedValue()) {
4493 4494 4495
    return graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, graph()->start());
  }

4496 4497 4498
  // General case for unsigned integer modulus, with optimization for (unknown)
  // power of 2 right hand side.
  //
4499 4500 4501
  //   if rhs == 0 then
  //     zero
  //   else
4502 4503 4504 4505 4506 4507 4508 4509 4510
  //     msk = rhs - 1
  //     if rhs & msk != 0 then
  //       lhs % rhs
  //     else
  //       lhs & msk
  //
  // Note: We do not use the Diamond helper class here, because it really hurts
  // readability with nested diamonds.
  const Operator* const merge_op = common()->Merge(2);
4511 4512
  const Operator* const phi_op =
      common()->Phi(MachineRepresentation::kWord32, 2);
4513

4514 4515
  Node* check0 = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
  Node* branch0 = graph()->NewNode(common()->Branch(BranchHint::kFalse), check0,
4516 4517 4518
                                   graph()->start());

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
4519 4520 4521 4522
  Node* true0 = zero;

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* false0;
4523 4524 4525 4526
  {
    Node* msk = graph()->NewNode(machine()->Int32Add(), rhs, minus_one);

    Node* check1 = graph()->NewNode(machine()->Word32And(), rhs, msk);
4527
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);
4528 4529 4530 4531 4532 4533 4534

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* true1 = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, if_true1);

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* false1 = graph()->NewNode(machine()->Word32And(), lhs, msk);

4535 4536
    if_false0 = graph()->NewNode(merge_op, if_true1, if_false1);
    false0 = graph()->NewNode(phi_op, true1, false1, if_false0);
4537 4538 4539 4540
  }

  Node* merge0 = graph()->NewNode(merge_op, if_true0, if_false0);
  return graph()->NewNode(phi_op, true0, false0, merge0);
4541 4542
}

4543 4544 4545 4546 4547 4548 4549 4550 4551 4552 4553 4554 4555 4556 4557 4558 4559 4560 4561 4562 4563
void SimplifiedLowering::DoMax(Node* node, Operator const* op,
                               MachineRepresentation rep) {
  Node* const lhs = node->InputAt(0);
  Node* const rhs = node->InputAt(1);

  node->ReplaceInput(0, graph()->NewNode(op, lhs, rhs));
  DCHECK_EQ(rhs, node->InputAt(1));
  node->AppendInput(graph()->zone(), lhs);
  NodeProperties::ChangeOp(node, common()->Select(rep));
}

void SimplifiedLowering::DoMin(Node* node, Operator const* op,
                               MachineRepresentation rep) {
  Node* const lhs = node->InputAt(0);
  Node* const rhs = node->InputAt(1);

  node->InsertInput(graph()->zone(), 0, graph()->NewNode(op, lhs, rhs));
  DCHECK_EQ(lhs, node->InputAt(1));
  DCHECK_EQ(rhs, node->InputAt(2));
  NodeProperties::ChangeOp(node, common()->Select(rep));
}
4564

4565 4566 4567 4568 4569 4570 4571 4572 4573 4574 4575 4576 4577 4578 4579 4580 4581 4582 4583 4584 4585 4586 4587 4588 4589 4590 4591 4592
void SimplifiedLowering::DoIntegral32ToBit(Node* node) {
  Node* const input = node->InputAt(0);
  Node* const zero = jsgraph()->Int32Constant(0);
  Operator const* const op = machine()->Word32Equal();

  node->ReplaceInput(0, graph()->NewNode(op, input, zero));
  node->AppendInput(graph()->zone(), zero);
  NodeProperties::ChangeOp(node, op);
}

void SimplifiedLowering::DoOrderedNumberToBit(Node* node) {
  Node* const input = node->InputAt(0);

  node->ReplaceInput(0, graph()->NewNode(machine()->Float64Equal(), input,
                                         jsgraph()->Float64Constant(0.0)));
  node->AppendInput(graph()->zone(), jsgraph()->Int32Constant(0));
  NodeProperties::ChangeOp(node, machine()->Word32Equal());
}

void SimplifiedLowering::DoNumberToBit(Node* node) {
  Node* const input = node->InputAt(0);

  node->ReplaceInput(0, jsgraph()->Float64Constant(0.0));
  node->AppendInput(graph()->zone(),
                    graph()->NewNode(machine()->Float64Abs(), input));
  NodeProperties::ChangeOp(node, machine()->Float64LessThan());
}

4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 4603 4604 4605 4606 4607 4608 4609 4610 4611 4612 4613 4614 4615 4616 4617 4618 4619 4620 4621 4622 4623 4624 4625 4626 4627 4628 4629 4630 4631 4632 4633 4634 4635 4636 4637 4638 4639 4640 4641 4642 4643 4644 4645 4646 4647 4648 4649 4650 4651 4652 4653 4654 4655 4656 4657
void SimplifiedLowering::DoIntegerToUint8Clamped(Node* node) {
  Node* const input = node->InputAt(0);
  Node* const min = jsgraph()->Float64Constant(0.0);
  Node* const max = jsgraph()->Float64Constant(255.0);

  node->ReplaceInput(
      0, graph()->NewNode(machine()->Float64LessThan(), min, input));
  node->AppendInput(
      graph()->zone(),
      graph()->NewNode(
          common()->Select(MachineRepresentation::kFloat64),
          graph()->NewNode(machine()->Float64LessThan(), input, max), input,
          max));
  node->AppendInput(graph()->zone(), min);
  NodeProperties::ChangeOp(node,
                           common()->Select(MachineRepresentation::kFloat64));
}

void SimplifiedLowering::DoNumberToUint8Clamped(Node* node) {
  Node* const input = node->InputAt(0);
  Node* const min = jsgraph()->Float64Constant(0.0);
  Node* const max = jsgraph()->Float64Constant(255.0);

  node->ReplaceInput(
      0, graph()->NewNode(
             common()->Select(MachineRepresentation::kFloat64),
             graph()->NewNode(machine()->Float64LessThan(), min, input),
             graph()->NewNode(
                 common()->Select(MachineRepresentation::kFloat64),
                 graph()->NewNode(machine()->Float64LessThan(), input, max),
                 input, max),
             min));
  NodeProperties::ChangeOp(node,
                           machine()->Float64RoundTiesEven().placeholder());
}

void SimplifiedLowering::DoSigned32ToUint8Clamped(Node* node) {
  Node* const input = node->InputAt(0);
  Node* const min = jsgraph()->Int32Constant(0);
  Node* const max = jsgraph()->Int32Constant(255);

  node->ReplaceInput(
      0, graph()->NewNode(machine()->Int32LessThanOrEqual(), input, max));
  node->AppendInput(
      graph()->zone(),
      graph()->NewNode(common()->Select(MachineRepresentation::kWord32),
                       graph()->NewNode(machine()->Int32LessThan(), input, min),
                       min, input));
  node->AppendInput(graph()->zone(), max);
  NodeProperties::ChangeOp(node,
                           common()->Select(MachineRepresentation::kWord32));
}

void SimplifiedLowering::DoUnsigned32ToUint8Clamped(Node* node) {
  Node* const input = node->InputAt(0);
  Node* const max = jsgraph()->Uint32Constant(255u);

  node->ReplaceInput(
      0, graph()->NewNode(machine()->Uint32LessThanOrEqual(), input, max));
  node->AppendInput(graph()->zone(), input);
  node->AppendInput(graph()->zone(), max);
  NodeProperties::ChangeOp(node,
                           common()->Select(MachineRepresentation::kWord32));
}

4658 4659
Node* SimplifiedLowering::ToNumberCode() {
  if (!to_number_code_.is_set()) {
4660
    Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumber);
4661 4662 4663 4664 4665
    to_number_code_.set(jsgraph()->HeapConstant(callable.code()));
  }
  return to_number_code_.get();
}

4666 4667 4668 4669 4670 4671 4672 4673 4674 4675
Node* SimplifiedLowering::ToNumberConvertBigIntCode() {
  if (!to_number_convert_big_int_code_.is_set()) {
    Callable callable =
        Builtins::CallableFor(isolate(), Builtins::kToNumberConvertBigInt);
    to_number_convert_big_int_code_.set(
        jsgraph()->HeapConstant(callable.code()));
  }
  return to_number_convert_big_int_code_.get();
}

4676 4677 4678
Node* SimplifiedLowering::ToNumericCode() {
  if (!to_numeric_code_.is_set()) {
    Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
4679
    to_numeric_code_.set(jsgraph()->HeapConstant(callable.code()));
4680 4681 4682 4683
  }
  return to_numeric_code_.get();
}

4684 4685
Operator const* SimplifiedLowering::ToNumberOperator() {
  if (!to_number_operator_.is_set()) {
4686
    Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumber);
4687
    CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4688 4689 4690 4691
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        graph()->zone(), callable.descriptor(),
        callable.descriptor().GetStackParameterCount(), flags,
        Operator::kNoProperties);
4692
    to_number_operator_.set(common()->Call(call_descriptor));
4693 4694 4695 4696
  }
  return to_number_operator_.get();
}

4697 4698 4699 4700 4701
Operator const* SimplifiedLowering::ToNumberConvertBigIntOperator() {
  if (!to_number_convert_big_int_operator_.is_set()) {
    Callable callable =
        Builtins::CallableFor(isolate(), Builtins::kToNumberConvertBigInt);
    CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4702 4703 4704 4705
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        graph()->zone(), callable.descriptor(),
        callable.descriptor().GetStackParameterCount(), flags,
        Operator::kNoProperties);
4706 4707 4708 4709 4710
    to_number_convert_big_int_operator_.set(common()->Call(call_descriptor));
  }
  return to_number_convert_big_int_operator_.get();
}

4711 4712 4713 4714
Operator const* SimplifiedLowering::ToNumericOperator() {
  if (!to_numeric_operator_.is_set()) {
    Callable callable = Builtins::CallableFor(isolate(), Builtins::kToNumeric);
    CallDescriptor::Flags flags = CallDescriptor::kNeedsFrameState;
4715 4716 4717 4718
    auto call_descriptor = Linkage::GetStubCallDescriptor(
        graph()->zone(), callable.descriptor(),
        callable.descriptor().GetStackParameterCount(), flags,
        Operator::kNoProperties);
4719
    to_numeric_operator_.set(common()->Call(call_descriptor));
4720 4721 4722 4723
  }
  return to_numeric_operator_.get();
}

4724 4725
#undef TRACE

4726 4727 4728
}  // namespace compiler
}  // namespace internal
}  // namespace v8