普通文本  |  3774行  |  150.12 KB

// Copyright 2015 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/effect-control-linearizer.h"

#include "src/code-factory.h"
#include "src/compiler/access-builder.h"
#include "src/compiler/compiler-source-position-table.h"
#include "src/compiler/js-graph.h"
#include "src/compiler/linkage.h"
#include "src/compiler/node-matchers.h"
#include "src/compiler/node-properties.h"
#include "src/compiler/node.h"
#include "src/compiler/schedule.h"

namespace v8 {
namespace internal {
namespace compiler {

EffectControlLinearizer::EffectControlLinearizer(
    JSGraph* js_graph, Schedule* schedule, Zone* temp_zone,
    SourcePositionTable* source_positions)
    : js_graph_(js_graph),
      schedule_(schedule),
      temp_zone_(temp_zone),
      source_positions_(source_positions) {}

Graph* EffectControlLinearizer::graph() const { return js_graph_->graph(); }
CommonOperatorBuilder* EffectControlLinearizer::common() const {
  return js_graph_->common();
}
SimplifiedOperatorBuilder* EffectControlLinearizer::simplified() const {
  return js_graph_->simplified();
}
MachineOperatorBuilder* EffectControlLinearizer::machine() const {
  return js_graph_->machine();
}

namespace {

struct BlockEffectControlData {
  Node* current_effect = nullptr;       // New effect.
  Node* current_control = nullptr;      // New control.
  Node* current_frame_state = nullptr;  // New frame state.
};

class BlockEffectControlMap {
 public:
  explicit BlockEffectControlMap(Zone* temp_zone) : map_(temp_zone) {}

  BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) {
    return map_[std::make_pair(from->rpo_number(), to->rpo_number())];
  }

  const BlockEffectControlData& For(BasicBlock* from, BasicBlock* to) const {
    return map_.at(std::make_pair(from->rpo_number(), to->rpo_number()));
  }

 private:
  typedef std::pair<int32_t, int32_t> Key;
  typedef ZoneMap<Key, BlockEffectControlData> Map;

  Map map_;
};

// Effect phis that need to be updated after the first pass.
struct PendingEffectPhi {
  Node* effect_phi;
  BasicBlock* block;

  PendingEffectPhi(Node* effect_phi, BasicBlock* block)
      : effect_phi(effect_phi), block(block) {}
};

void UpdateEffectPhi(Node* node, BasicBlock* block,
                     BlockEffectControlMap* block_effects) {
  // Update all inputs to an effect phi with the effects from the given
  // block->effect map.
  DCHECK_EQ(IrOpcode::kEffectPhi, node->opcode());
  DCHECK_EQ(static_cast<size_t>(node->op()->EffectInputCount()),
            block->PredecessorCount());
  for (int i = 0; i < node->op()->EffectInputCount(); i++) {
    Node* input = node->InputAt(i);
    BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
    const BlockEffectControlData& block_effect =
        block_effects->For(predecessor, block);
    if (input != block_effect.current_effect) {
      node->ReplaceInput(i, block_effect.current_effect);
    }
  }
}

void UpdateBlockControl(BasicBlock* block,
                        BlockEffectControlMap* block_effects) {
  Node* control = block->NodeAt(0);
  DCHECK(NodeProperties::IsControl(control));

  // Do not rewire the end node.
  if (control->opcode() == IrOpcode::kEnd) return;

  // Update all inputs to the given control node with the correct control.
  DCHECK(control->opcode() == IrOpcode::kMerge ||
         static_cast<size_t>(control->op()->ControlInputCount()) ==
             block->PredecessorCount());
  if (static_cast<size_t>(control->op()->ControlInputCount()) !=
      block->PredecessorCount()) {
    return;  // We already re-wired the control inputs of this node.
  }
  for (int i = 0; i < control->op()->ControlInputCount(); i++) {
    Node* input = NodeProperties::GetControlInput(control, i);
    BasicBlock* predecessor = block->PredecessorAt(static_cast<size_t>(i));
    const BlockEffectControlData& block_effect =
        block_effects->For(predecessor, block);
    if (input != block_effect.current_control) {
      NodeProperties::ReplaceControlInput(control, block_effect.current_control,
                                          i);
    }
  }
}

bool HasIncomingBackEdges(BasicBlock* block) {
  for (BasicBlock* pred : block->predecessors()) {
    if (pred->rpo_number() >= block->rpo_number()) {
      return true;
    }
  }
  return false;
}

void RemoveRegionNode(Node* node) {
  DCHECK(IrOpcode::kFinishRegion == node->opcode() ||
         IrOpcode::kBeginRegion == node->opcode());
  // Update the value/context uses to the value input of the finish node and
  // the effect uses to the effect input.
  for (Edge edge : node->use_edges()) {
    DCHECK(!edge.from()->IsDead());
    if (NodeProperties::IsEffectEdge(edge)) {
      edge.UpdateTo(NodeProperties::GetEffectInput(node));
    } else {
      DCHECK(!NodeProperties::IsControlEdge(edge));
      DCHECK(!NodeProperties::IsFrameStateEdge(edge));
      edge.UpdateTo(node->InputAt(0));
    }
  }
  node->Kill();
}

void TryCloneBranch(Node* node, BasicBlock* block, Graph* graph,
                    CommonOperatorBuilder* common,
                    BlockEffectControlMap* block_effects,
                    SourcePositionTable* source_positions) {
  DCHECK_EQ(IrOpcode::kBranch, node->opcode());

  // This optimization is a special case of (super)block cloning. It takes an
  // input graph as shown below and clones the Branch node for every predecessor
  // to the Merge, essentially removing the Merge completely. This avoids
  // materializing the bit for the Phi and may offer potential for further
  // branch folding optimizations (i.e. because one or more inputs to the Phi is
  // a constant). Note that there may be more Phi nodes hanging off the Merge,
  // but we can only a certain subset of them currently (actually only Phi and
  // EffectPhi nodes whose uses have either the IfTrue or IfFalse as control
  // input).

  //   Control1 ... ControlN
  //      ^            ^
  //      |            |   Cond1 ... CondN
  //      +----+  +----+     ^         ^
  //           |  |          |         |
  //           |  |     +----+         |
  //          Merge<--+ | +------------+
  //            ^      \|/
  //            |      Phi
  //            |       |
  //          Branch----+
  //            ^
  //            |
  //      +-----+-----+
  //      |           |
  //    IfTrue     IfFalse
  //      ^           ^
  //      |           |

  // The resulting graph (modulo the Phi and EffectPhi nodes) looks like this:

  // Control1 Cond1 ... ControlN CondN
  //    ^      ^           ^      ^
  //    \      /           \      /
  //     Branch     ...     Branch
  //       ^                  ^
  //       |                  |
  //   +---+---+          +---+----+
  //   |       |          |        |
  // IfTrue IfFalse ... IfTrue  IfFalse
  //   ^       ^          ^        ^
  //   |       |          |        |
  //   +--+ +-------------+        |
  //      | |  +--------------+ +--+
  //      | |                 | |
  //     Merge               Merge
  //       ^                   ^
  //       |                   |

  SourcePositionTable::Scope scope(source_positions,
                                   source_positions->GetSourcePosition(node));
  Node* branch = node;
  Node* cond = NodeProperties::GetValueInput(branch, 0);
  if (!cond->OwnedBy(branch) || cond->opcode() != IrOpcode::kPhi) return;
  Node* merge = NodeProperties::GetControlInput(branch);
  if (merge->opcode() != IrOpcode::kMerge ||
      NodeProperties::GetControlInput(cond) != merge) {
    return;
  }
  // Grab the IfTrue/IfFalse projections of the Branch.
  BranchMatcher matcher(branch);
  // Check/collect other Phi/EffectPhi nodes hanging off the Merge.
  NodeVector phis(graph->zone());
  for (Node* const use : merge->uses()) {
    if (use == branch || use == cond) continue;
    // We cannot currently deal with non-Phi/EffectPhi nodes hanging off the
    // Merge. Ideally, we would just clone the nodes (and everything that
    // depends on it to some distant join point), but that requires knowledge
    // about dominance/post-dominance.
    if (!NodeProperties::IsPhi(use)) return;
    for (Edge edge : use->use_edges()) {
      // Right now we can only handle Phi/EffectPhi nodes whose uses are
      // directly control-dependend on either the IfTrue or the IfFalse
      // successor, because we know exactly how to update those uses.
      if (edge.from()->op()->ControlInputCount() != 1) return;
      Node* control = NodeProperties::GetControlInput(edge.from());
      if (NodeProperties::IsPhi(edge.from())) {
        control = NodeProperties::GetControlInput(control, edge.index());
      }
      if (control != matcher.IfTrue() && control != matcher.IfFalse()) return;
    }
    phis.push_back(use);
  }
  BranchHint const hint = BranchHintOf(branch->op());
  int const input_count = merge->op()->ControlInputCount();
  DCHECK_LE(1, input_count);
  Node** const inputs = graph->zone()->NewArray<Node*>(2 * input_count);
  Node** const merge_true_inputs = &inputs[0];
  Node** const merge_false_inputs = &inputs[input_count];
  for (int index = 0; index < input_count; ++index) {
    Node* cond1 = NodeProperties::GetValueInput(cond, index);
    Node* control1 = NodeProperties::GetControlInput(merge, index);
    Node* branch1 = graph->NewNode(common->Branch(hint), cond1, control1);
    merge_true_inputs[index] = graph->NewNode(common->IfTrue(), branch1);
    merge_false_inputs[index] = graph->NewNode(common->IfFalse(), branch1);
  }
  Node* const merge_true = matcher.IfTrue();
  Node* const merge_false = matcher.IfFalse();
  merge_true->TrimInputCount(0);
  merge_false->TrimInputCount(0);
  for (int i = 0; i < input_count; ++i) {
    merge_true->AppendInput(graph->zone(), merge_true_inputs[i]);
    merge_false->AppendInput(graph->zone(), merge_false_inputs[i]);
  }
  DCHECK_EQ(2u, block->SuccessorCount());
  NodeProperties::ChangeOp(matcher.IfTrue(), common->Merge(input_count));
  NodeProperties::ChangeOp(matcher.IfFalse(), common->Merge(input_count));
  int const true_index =
      block->SuccessorAt(0)->NodeAt(0) == matcher.IfTrue() ? 0 : 1;
  BlockEffectControlData* true_block_data =
      &block_effects->For(block, block->SuccessorAt(true_index));
  BlockEffectControlData* false_block_data =
      &block_effects->For(block, block->SuccessorAt(true_index ^ 1));
  for (Node* const phi : phis) {
    for (int index = 0; index < input_count; ++index) {
      inputs[index] = phi->InputAt(index);
    }
    inputs[input_count] = merge_true;
    Node* phi_true = graph->NewNode(phi->op(), input_count + 1, inputs);
    inputs[input_count] = merge_false;
    Node* phi_false = graph->NewNode(phi->op(), input_count + 1, inputs);
    if (phi->UseCount() == 0) {
      DCHECK_EQ(phi->opcode(), IrOpcode::kEffectPhi);
    } else {
      for (Edge edge : phi->use_edges()) {
        Node* control = NodeProperties::GetControlInput(edge.from());
        if (NodeProperties::IsPhi(edge.from())) {
          control = NodeProperties::GetControlInput(control, edge.index());
        }
        DCHECK(control == matcher.IfTrue() || control == matcher.IfFalse());
        edge.UpdateTo((control == matcher.IfTrue()) ? phi_true : phi_false);
      }
    }
    if (phi->opcode() == IrOpcode::kEffectPhi) {
      true_block_data->current_effect = phi_true;
      false_block_data->current_effect = phi_false;
    }
    phi->Kill();
  }
  // Fix up IfTrue and IfFalse and kill all dead nodes.
  if (branch == block->control_input()) {
    true_block_data->current_control = merge_true;
    false_block_data->current_control = merge_false;
  }
  branch->Kill();
  cond->Kill();
  merge->Kill();
}
}  // namespace

void EffectControlLinearizer::Run() {
  BlockEffectControlMap block_effects(temp_zone());
  ZoneVector<PendingEffectPhi> pending_effect_phis(temp_zone());
  ZoneVector<BasicBlock*> pending_block_controls(temp_zone());
  NodeVector inputs_buffer(temp_zone());

  for (BasicBlock* block : *(schedule()->rpo_order())) {
    size_t instr = 0;

    // The control node should be the first.
    Node* control = block->NodeAt(instr);
    DCHECK(NodeProperties::IsControl(control));
    // Update the control inputs.
    if (HasIncomingBackEdges(block)) {
      // If there are back edges, we need to update later because we have not
      // computed the control yet. This should only happen for loops.
      DCHECK_EQ(IrOpcode::kLoop, control->opcode());
      pending_block_controls.push_back(block);
    } else {
      // If there are no back edges, we can update now.
      UpdateBlockControl(block, &block_effects);
    }
    instr++;

    // Iterate over the phis and update the effect phis.
    Node* effect = nullptr;
    Node* terminate = nullptr;
    for (; instr < block->NodeCount(); instr++) {
      Node* node = block->NodeAt(instr);
      // Only go through the phis and effect phis.
      if (node->opcode() == IrOpcode::kEffectPhi) {
        // There should be at most one effect phi in a block.
        DCHECK_NULL(effect);
        // IfException blocks should not have effect phis.
        DCHECK_NE(IrOpcode::kIfException, control->opcode());
        effect = node;

        // Make sure we update the inputs to the incoming blocks' effects.
        if (HasIncomingBackEdges(block)) {
          // In case of loops, we do not update the effect phi immediately
          // because the back predecessor has not been handled yet. We just
          // record the effect phi for later processing.
          pending_effect_phis.push_back(PendingEffectPhi(node, block));
        } else {
          UpdateEffectPhi(node, block, &block_effects);
        }
      } else if (node->opcode() == IrOpcode::kPhi) {
        // Just skip phis.
      } else if (node->opcode() == IrOpcode::kTerminate) {
        DCHECK(terminate == nullptr);
        terminate = node;
      } else {
        break;
      }
    }

    if (effect == nullptr) {
      // There was no effect phi.
      DCHECK(!HasIncomingBackEdges(block));
      if (block == schedule()->start()) {
        // Start block => effect is start.
        DCHECK_EQ(graph()->start(), control);
        effect = graph()->start();
      } else if (control->opcode() == IrOpcode::kEnd) {
        // End block is just a dummy, no effect needed.
        DCHECK_EQ(BasicBlock::kNone, block->control());
        DCHECK_EQ(1u, block->size());
        effect = nullptr;
      } else {
        // If all the predecessors have the same effect, we can use it as our
        // current effect.
        effect =
            block_effects.For(block->PredecessorAt(0), block).current_effect;
        for (size_t i = 1; i < block->PredecessorCount(); ++i) {
          if (block_effects.For(block->PredecessorAt(i), block)
                  .current_effect != effect) {
            effect = nullptr;
            break;
          }
        }
        if (effect == nullptr) {
          DCHECK_NE(IrOpcode::kIfException, control->opcode());
          // The input blocks do not have the same effect. We have
          // to create an effect phi node.
          inputs_buffer.clear();
          inputs_buffer.resize(block->PredecessorCount(), jsgraph()->Dead());
          inputs_buffer.push_back(control);
          effect = graph()->NewNode(
              common()->EffectPhi(static_cast<int>(block->PredecessorCount())),
              static_cast<int>(inputs_buffer.size()), &(inputs_buffer.front()));
          // For loops, we update the effect phi node later to break cycles.
          if (control->opcode() == IrOpcode::kLoop) {
            pending_effect_phis.push_back(PendingEffectPhi(effect, block));
          } else {
            UpdateEffectPhi(effect, block, &block_effects);
          }
        } else if (control->opcode() == IrOpcode::kIfException) {
          // The IfException is connected into the effect chain, so we need
          // to update the effect here.
          NodeProperties::ReplaceEffectInput(control, effect);
          effect = control;
        }
      }
    }

    // Fixup the Terminate node.
    if (terminate != nullptr) {
      NodeProperties::ReplaceEffectInput(terminate, effect);
    }

    // The frame state at block entry is determined by the frame states leaving
    // all predecessors. In case there is no frame state dominating this block,
    // we can rely on a checkpoint being present before the next deoptimization.
    // TODO(mstarzinger): Eventually we will need to go hunt for a frame state
    // once deoptimizing nodes roam freely through the schedule.
    Node* frame_state = nullptr;
    if (block != schedule()->start()) {
      // If all the predecessors have the same effect, we can use it
      // as our current effect.
      frame_state =
          block_effects.For(block->PredecessorAt(0), block).current_frame_state;
      for (size_t i = 1; i < block->PredecessorCount(); i++) {
        if (block_effects.For(block->PredecessorAt(i), block)
                .current_frame_state != frame_state) {
          frame_state = nullptr;
          break;
        }
      }
    }

    // Process the ordinary instructions.
    for (; instr < block->NodeCount(); instr++) {
      Node* node = block->NodeAt(instr);
      ProcessNode(node, &frame_state, &effect, &control);
    }

    switch (block->control()) {
      case BasicBlock::kGoto:
      case BasicBlock::kNone:
        break;

      case BasicBlock::kCall:
      case BasicBlock::kTailCall:
      case BasicBlock::kSwitch:
      case BasicBlock::kReturn:
      case BasicBlock::kDeoptimize:
      case BasicBlock::kThrow:
        ProcessNode(block->control_input(), &frame_state, &effect, &control);
        break;

      case BasicBlock::kBranch:
        ProcessNode(block->control_input(), &frame_state, &effect, &control);
        TryCloneBranch(block->control_input(), block, graph(), common(),
                       &block_effects, source_positions_);
        break;
    }

    // Store the effect, control and frame state for later use.
    for (BasicBlock* successor : block->successors()) {
      BlockEffectControlData* data = &block_effects.For(block, successor);
      if (data->current_effect == nullptr) {
        data->current_effect = effect;
      }
      if (data->current_control == nullptr) {
        data->current_control = control;
      }
      data->current_frame_state = frame_state;
    }
  }

  // Update the incoming edges of the effect phis that could not be processed
  // during the first pass (because they could have incoming back edges).
  for (const PendingEffectPhi& pending_effect_phi : pending_effect_phis) {
    UpdateEffectPhi(pending_effect_phi.effect_phi, pending_effect_phi.block,
                    &block_effects);
  }
  for (BasicBlock* pending_block_control : pending_block_controls) {
    UpdateBlockControl(pending_block_control, &block_effects);
  }
}

namespace {

void TryScheduleCallIfSuccess(Node* node, Node** control) {
  // Schedule the call's IfSuccess node if there is no exception use.
  if (!NodeProperties::IsExceptionalCall(node)) {
    for (Edge edge : node->use_edges()) {
      if (NodeProperties::IsControlEdge(edge) &&
          edge.from()->opcode() == IrOpcode::kIfSuccess) {
        *control = edge.from();
      }
    }
  }
}

}  // namespace

void EffectControlLinearizer::ProcessNode(Node* node, Node** frame_state,
                                          Node** effect, Node** control) {
  SourcePositionTable::Scope scope(source_positions_,
                                   source_positions_->GetSourcePosition(node));

  // If the node needs to be wired into the effect/control chain, do this
  // here. Pass current frame state for lowering to eager deoptimization.
  if (TryWireInStateEffect(node, *frame_state, effect, control)) {
    return;
  }

  // If the node has a visible effect, then there must be a checkpoint in the
  // effect chain before we are allowed to place another eager deoptimization
  // point. We zap the frame state to ensure this invariant is maintained.
  if (region_observability_ == RegionObservability::kObservable &&
      !node->op()->HasProperty(Operator::kNoWrite)) {
    *frame_state = nullptr;
  }

  // Remove the end markers of 'atomic' allocation region because the
  // region should be wired-in now.
  if (node->opcode() == IrOpcode::kFinishRegion) {
    // Reset the current region observability.
    region_observability_ = RegionObservability::kObservable;
    // Update the value uses to the value input of the finish node and
    // the effect uses to the effect input.
    return RemoveRegionNode(node);
  }
  if (node->opcode() == IrOpcode::kBeginRegion) {
    // Determine the observability for this region and use that for all
    // nodes inside the region (i.e. ignore the absence of kNoWrite on
    // StoreField and other operators).
    DCHECK_NE(RegionObservability::kNotObservable, region_observability_);
    region_observability_ = RegionObservabilityOf(node->op());
    // Update the value uses to the value input of the finish node and
    // the effect uses to the effect input.
    return RemoveRegionNode(node);
  }

  // Special treatment for checkpoint nodes.
  if (node->opcode() == IrOpcode::kCheckpoint) {
    // Unlink the check point; effect uses will be updated to the incoming
    // effect that is passed. The frame state is preserved for lowering.
    DCHECK_EQ(RegionObservability::kObservable, region_observability_);
    *frame_state = NodeProperties::GetFrameStateInput(node);
    return;
  }

  if (node->opcode() == IrOpcode::kIfSuccess) {
    // We always schedule IfSuccess with its call, so skip it here.
    DCHECK_EQ(IrOpcode::kCall, node->InputAt(0)->opcode());
    // The IfSuccess node should not belong to an exceptional call node
    // because such IfSuccess nodes should only start a basic block (and
    // basic block start nodes are not handled in the ProcessNode method).
    DCHECK(!NodeProperties::IsExceptionalCall(node->InputAt(0)));
    return;
  }

  // If the node takes an effect, replace with the current one.
  if (node->op()->EffectInputCount() > 0) {
    DCHECK_EQ(1, node->op()->EffectInputCount());
    Node* input_effect = NodeProperties::GetEffectInput(node);

    if (input_effect != *effect) {
      NodeProperties::ReplaceEffectInput(node, *effect);
    }

    // If the node produces an effect, update our current effect. (However,
    // ignore new effect chains started with ValueEffect.)
    if (node->op()->EffectOutputCount() > 0) {
      DCHECK_EQ(1, node->op()->EffectOutputCount());
      *effect = node;
    }
  } else {
    // New effect chain is only started with a Start or ValueEffect node.
    DCHECK(node->op()->EffectOutputCount() == 0 ||
           node->opcode() == IrOpcode::kStart);
  }

  // Rewire control inputs.
  for (int i = 0; i < node->op()->ControlInputCount(); i++) {
    NodeProperties::ReplaceControlInput(node, *control, i);
  }
  // Update the current control and wire IfSuccess right after calls.
  if (node->op()->ControlOutputCount() > 0) {
    *control = node;
    if (node->opcode() == IrOpcode::kCall) {
      // Schedule the call's IfSuccess node (if there is no exception use).
      TryScheduleCallIfSuccess(node, control);
    }
  }
}

bool EffectControlLinearizer::TryWireInStateEffect(Node* node,
                                                   Node* frame_state,
                                                   Node** effect,
                                                   Node** control) {
  ValueEffectControl state(nullptr, nullptr, nullptr);
  switch (node->opcode()) {
    case IrOpcode::kChangeBitToTagged:
      state = LowerChangeBitToTagged(node, *effect, *control);
      break;
    case IrOpcode::kChangeInt31ToTaggedSigned:
      state = LowerChangeInt31ToTaggedSigned(node, *effect, *control);
      break;
    case IrOpcode::kChangeInt32ToTagged:
      state = LowerChangeInt32ToTagged(node, *effect, *control);
      break;
    case IrOpcode::kChangeUint32ToTagged:
      state = LowerChangeUint32ToTagged(node, *effect, *control);
      break;
    case IrOpcode::kChangeFloat64ToTagged:
      state = LowerChangeFloat64ToTagged(node, *effect, *control);
      break;
    case IrOpcode::kChangeFloat64ToTaggedPointer:
      state = LowerChangeFloat64ToTaggedPointer(node, *effect, *control);
      break;
    case IrOpcode::kChangeTaggedSignedToInt32:
      state = LowerChangeTaggedSignedToInt32(node, *effect, *control);
      break;
    case IrOpcode::kChangeTaggedToBit:
      state = LowerChangeTaggedToBit(node, *effect, *control);
      break;
    case IrOpcode::kChangeTaggedToInt32:
      state = LowerChangeTaggedToInt32(node, *effect, *control);
      break;
    case IrOpcode::kChangeTaggedToUint32:
      state = LowerChangeTaggedToUint32(node, *effect, *control);
      break;
    case IrOpcode::kChangeTaggedToFloat64:
      state = LowerChangeTaggedToFloat64(node, *effect, *control);
      break;
    case IrOpcode::kTruncateTaggedToBit:
      state = LowerTruncateTaggedToBit(node, *effect, *control);
      break;
    case IrOpcode::kTruncateTaggedToFloat64:
      state = LowerTruncateTaggedToFloat64(node, *effect, *control);
      break;
    case IrOpcode::kCheckBounds:
      state = LowerCheckBounds(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckMaps:
      state = LowerCheckMaps(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckNumber:
      state = LowerCheckNumber(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckString:
      state = LowerCheckString(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckIf:
      state = LowerCheckIf(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedInt32Add:
      state = LowerCheckedInt32Add(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedInt32Sub:
      state = LowerCheckedInt32Sub(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedInt32Div:
      state = LowerCheckedInt32Div(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedInt32Mod:
      state = LowerCheckedInt32Mod(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedUint32Div:
      state = LowerCheckedUint32Div(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedUint32Mod:
      state = LowerCheckedUint32Mod(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedInt32Mul:
      state = LowerCheckedInt32Mul(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedInt32ToTaggedSigned:
      state =
          LowerCheckedInt32ToTaggedSigned(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedUint32ToInt32:
      state = LowerCheckedUint32ToInt32(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedUint32ToTaggedSigned:
      state = LowerCheckedUint32ToTaggedSigned(node, frame_state, *effect,
                                               *control);
      break;
    case IrOpcode::kCheckedFloat64ToInt32:
      state = LowerCheckedFloat64ToInt32(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedTaggedSignedToInt32:
      state =
          LowerCheckedTaggedSignedToInt32(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedTaggedToInt32:
      state = LowerCheckedTaggedToInt32(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedTaggedToFloat64:
      state = LowerCheckedTaggedToFloat64(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckedTaggedToTaggedSigned:
      state = LowerCheckedTaggedToTaggedSigned(node, frame_state, *effect,
                                               *control);
      break;
    case IrOpcode::kCheckedTaggedToTaggedPointer:
      state = LowerCheckedTaggedToTaggedPointer(node, frame_state, *effect,
                                                *control);
      break;
    case IrOpcode::kTruncateTaggedToWord32:
      state = LowerTruncateTaggedToWord32(node, *effect, *control);
      break;
    case IrOpcode::kCheckedTruncateTaggedToWord32:
      state = LowerCheckedTruncateTaggedToWord32(node, frame_state, *effect,
                                                 *control);
      break;
    case IrOpcode::kObjectIsCallable:
      state = LowerObjectIsCallable(node, *effect, *control);
      break;
    case IrOpcode::kObjectIsNumber:
      state = LowerObjectIsNumber(node, *effect, *control);
      break;
    case IrOpcode::kObjectIsReceiver:
      state = LowerObjectIsReceiver(node, *effect, *control);
      break;
    case IrOpcode::kObjectIsSmi:
      state = LowerObjectIsSmi(node, *effect, *control);
      break;
    case IrOpcode::kObjectIsString:
      state = LowerObjectIsString(node, *effect, *control);
      break;
    case IrOpcode::kObjectIsUndetectable:
      state = LowerObjectIsUndetectable(node, *effect, *control);
      break;
    case IrOpcode::kArrayBufferWasNeutered:
      state = LowerArrayBufferWasNeutered(node, *effect, *control);
      break;
    case IrOpcode::kStringFromCharCode:
      state = LowerStringFromCharCode(node, *effect, *control);
      break;
    case IrOpcode::kStringFromCodePoint:
      state = LowerStringFromCodePoint(node, *effect, *control);
      break;
    case IrOpcode::kStringCharCodeAt:
      state = LowerStringCharCodeAt(node, *effect, *control);
      break;
    case IrOpcode::kStringEqual:
      state = LowerStringEqual(node, *effect, *control);
      break;
    case IrOpcode::kStringLessThan:
      state = LowerStringLessThan(node, *effect, *control);
      break;
    case IrOpcode::kStringLessThanOrEqual:
      state = LowerStringLessThanOrEqual(node, *effect, *control);
      break;
    case IrOpcode::kCheckFloat64Hole:
      state = LowerCheckFloat64Hole(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kCheckTaggedHole:
      state = LowerCheckTaggedHole(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kConvertTaggedHoleToUndefined:
      state = LowerConvertTaggedHoleToUndefined(node, *effect, *control);
      break;
    case IrOpcode::kPlainPrimitiveToNumber:
      state = LowerPlainPrimitiveToNumber(node, *effect, *control);
      break;
    case IrOpcode::kPlainPrimitiveToWord32:
      state = LowerPlainPrimitiveToWord32(node, *effect, *control);
      break;
    case IrOpcode::kPlainPrimitiveToFloat64:
      state = LowerPlainPrimitiveToFloat64(node, *effect, *control);
      break;
    case IrOpcode::kEnsureWritableFastElements:
      state = LowerEnsureWritableFastElements(node, *effect, *control);
      break;
    case IrOpcode::kMaybeGrowFastElements:
      state = LowerMaybeGrowFastElements(node, frame_state, *effect, *control);
      break;
    case IrOpcode::kTransitionElementsKind:
      state = LowerTransitionElementsKind(node, *effect, *control);
      break;
    case IrOpcode::kLoadTypedElement:
      state = LowerLoadTypedElement(node, *effect, *control);
      break;
    case IrOpcode::kStoreTypedElement:
      state = LowerStoreTypedElement(node, *effect, *control);
      break;
    case IrOpcode::kFloat64RoundUp:
      state = LowerFloat64RoundUp(node, *effect, *control);
      break;
    case IrOpcode::kFloat64RoundDown:
      state = LowerFloat64RoundDown(node, *effect, *control);
      break;
    case IrOpcode::kFloat64RoundTruncate:
      state = LowerFloat64RoundTruncate(node, *effect, *control);
      break;
    case IrOpcode::kFloat64RoundTiesEven:
      state = LowerFloat64RoundTiesEven(node, *effect, *control);
      break;
    default:
      return false;
  }
  NodeProperties::ReplaceUses(node, state.value, state.effect, state.control);
  *effect = state.effect;
  *control = state.control;
  return true;
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeFloat64ToTagged(Node* node, Node* effect,
                                                    Node* control) {
  Node* value = node->InputAt(0);
  return AllocateHeapNumberWithValue(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeFloat64ToTaggedPointer(Node* node,
                                                           Node* effect,
                                                           Node* control) {
  Node* value = node->InputAt(0);
  return AllocateHeapNumberWithValue(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeBitToTagged(Node* node, Node* effect,
                                                Node* control) {
  Node* value = node->InputAt(0);

  Node* branch = graph()->NewNode(common()->Branch(), value, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* vtrue = jsgraph()->TrueConstant();

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* vfalse = jsgraph()->FalseConstant();

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                           vtrue, vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeInt31ToTaggedSigned(Node* node,
                                                        Node* effect,
                                                        Node* control) {
  Node* value = node->InputAt(0);
  value = ChangeInt32ToSmi(value);
  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeInt32ToTagged(Node* node, Node* effect,
                                                  Node* control) {
  Node* value = node->InputAt(0);

  if (machine()->Is64()) {
    return ValueEffectControl(ChangeInt32ToSmi(value), effect, control);
  }

  Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value,
                               control);

  Node* ovf = graph()->NewNode(common()->Projection(1), add, control);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), ovf, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  ValueEffectControl alloc =
      AllocateHeapNumberWithValue(ChangeInt32ToFloat64(value), effect, if_true);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* vfalse = graph()->NewNode(common()->Projection(0), add, if_false);

  Node* merge = graph()->NewNode(common()->Merge(2), alloc.control, if_false);
  Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                               alloc.value, vfalse, merge);
  Node* ephi =
      graph()->NewNode(common()->EffectPhi(2), alloc.effect, effect, merge);

  return ValueEffectControl(phi, ephi, merge);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeUint32ToTagged(Node* node, Node* effect,
                                                   Node* control) {
  Node* value = node->InputAt(0);

  Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value,
                                 SmiMaxValueConstant());
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* vtrue = ChangeUint32ToSmi(value);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  ValueEffectControl alloc = AllocateHeapNumberWithValue(
      ChangeUint32ToFloat64(value), effect, if_false);

  Node* merge = graph()->NewNode(common()->Merge(2), if_true, alloc.control);
  Node* phi = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                               vtrue, alloc.value, merge);
  Node* ephi =
      graph()->NewNode(common()->EffectPhi(2), effect, alloc.effect, merge);

  return ValueEffectControl(phi, ephi, merge);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeTaggedSignedToInt32(Node* node,
                                                        Node* effect,
                                                        Node* control) {
  Node* value = node->InputAt(0);
  value = ChangeSmiToInt32(value);
  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeTaggedToBit(Node* node, Node* effect,
                                                Node* control) {
  Node* value = node->InputAt(0);
  value = graph()->NewNode(machine()->WordEqual(), value,
                           jsgraph()->TrueConstant());
  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerTruncateTaggedToBit(Node* node, Node* effect,
                                                  Node* control) {
  Node* value = node->InputAt(0);
  Node* zero = jsgraph()->Int32Constant(0);
  Node* fzero = jsgraph()->Float64Constant(0.0);

  // Collect effect/control/value triples.
  int count = 0;
  Node* values[6];
  Node* effects[6];
  Node* controls[5];

  // Check if {value} is a Smi.
  Node* check_smi = ObjectIsSmi(value);
  Node* branch_smi = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                      check_smi, control);

  // If {value} is a Smi, then we only need to check that it's not zero.
  Node* if_smi = graph()->NewNode(common()->IfTrue(), branch_smi);
  Node* esmi = effect;
  {
    controls[count] = if_smi;
    effects[count] = esmi;
    values[count] =
        graph()->NewNode(machine()->Word32Equal(),
                         graph()->NewNode(machine()->WordEqual(), value,
                                          jsgraph()->IntPtrConstant(0)),
                         zero);
    count++;
  }
  control = graph()->NewNode(common()->IfFalse(), branch_smi);

  // Load the map instance type of {value}.
  Node* value_map = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
  Node* value_instance_type = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
      effect, control);

  // Check if {value} is an Oddball.
  Node* check_oddball =
      graph()->NewNode(machine()->Word32Equal(), value_instance_type,
                       jsgraph()->Int32Constant(ODDBALL_TYPE));
  Node* branch_oddball = graph()->NewNode(common()->Branch(BranchHint::kTrue),
                                          check_oddball, control);

  // The only Oddball {value} that is trueish is true itself.
  Node* if_oddball = graph()->NewNode(common()->IfTrue(), branch_oddball);
  Node* eoddball = effect;
  {
    controls[count] = if_oddball;
    effects[count] = eoddball;
    values[count] = graph()->NewNode(machine()->WordEqual(), value,
                                     jsgraph()->TrueConstant());
    count++;
  }
  control = graph()->NewNode(common()->IfFalse(), branch_oddball);

  // Check if {value} is a String.
  Node* check_string =
      graph()->NewNode(machine()->Int32LessThan(), value_instance_type,
                       jsgraph()->Int32Constant(FIRST_NONSTRING_TYPE));
  Node* branch_string =
      graph()->NewNode(common()->Branch(), check_string, control);

  // For String {value}, we need to check that the length is not zero.
  Node* if_string = graph()->NewNode(common()->IfTrue(), branch_string);
  Node* estring = effect;
  {
    // Load the {value} length.
    Node* value_length = estring = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForStringLength()), value,
        estring, if_string);

    controls[count] = if_string;
    effects[count] = estring;
    values[count] =
        graph()->NewNode(machine()->Word32Equal(),
                         graph()->NewNode(machine()->WordEqual(), value_length,
                                          jsgraph()->IntPtrConstant(0)),
                         zero);
    count++;
  }
  control = graph()->NewNode(common()->IfFalse(), branch_string);

  // Check if {value} is a HeapNumber.
  Node* check_heapnumber =
      graph()->NewNode(machine()->Word32Equal(), value_instance_type,
                       jsgraph()->Int32Constant(HEAP_NUMBER_TYPE));
  Node* branch_heapnumber =
      graph()->NewNode(common()->Branch(), check_heapnumber, control);

  // For HeapNumber {value}, just check that its value is not 0.0, -0.0 or NaN.
  Node* if_heapnumber = graph()->NewNode(common()->IfTrue(), branch_heapnumber);
  Node* eheapnumber = effect;
  {
    // Load the raw value of {value}.
    Node* value_value = eheapnumber = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
        eheapnumber, if_heapnumber);

    // Check if {value} is not one of 0, -0, or NaN.
    controls[count] = if_heapnumber;
    effects[count] = eheapnumber;
    values[count] = graph()->NewNode(
        machine()->Float64LessThan(), fzero,
        graph()->NewNode(machine()->Float64Abs(), value_value));
    count++;
  }
  control = graph()->NewNode(common()->IfFalse(), branch_heapnumber);

  // The {value} is either a JSReceiver, a Symbol or some Simd128Value. In
  // those cases we can just the undetectable bit on the map, which will only
  // be set for certain JSReceivers, i.e. document.all.
  {
    // Load the {value} map bit field.
    Node* value_map_bitfield = effect = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForMapBitField()), value_map,
        effect, control);

    controls[count] = control;
    effects[count] = effect;
    values[count] = graph()->NewNode(
        machine()->Word32Equal(),
        graph()->NewNode(machine()->Word32And(), value_map_bitfield,
                         jsgraph()->Int32Constant(1 << Map::kIsUndetectable)),
        zero);
    count++;
  }

  // Merge the different controls.
  control = graph()->NewNode(common()->Merge(count), count, controls);
  effects[count] = control;
  effect = graph()->NewNode(common()->EffectPhi(count), count + 1, effects);
  values[count] = control;
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, count),
                           count + 1, values);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeTaggedToInt32(Node* node, Node* effect,
                                                  Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = ChangeSmiToInt32(value);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
    vfalse = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
        efalse, if_false);
    vfalse = graph()->NewNode(machine()->ChangeFloat64ToInt32(), vfalse);
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                           vtrue, vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeTaggedToUint32(Node* node, Node* effect,
                                                   Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = ChangeSmiToInt32(value);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
    vfalse = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
        efalse, if_false);
    vfalse = graph()->NewNode(machine()->ChangeFloat64ToUint32(), vfalse);
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                           vtrue, vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerChangeTaggedToFloat64(Node* node, Node* effect,
                                                    Node* control) {
  return LowerTruncateTaggedToFloat64(node, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerTruncateTaggedToFloat64(Node* node, Node* effect,
                                                      Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue;
  {
    vtrue = ChangeSmiToInt32(value);
    vtrue = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue);
  }

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
    vfalse = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
        efalse, if_false);
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                           vtrue, vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckBounds(Node* node, Node* frame_state,
                                          Node* effect, Node* control) {
  Node* index = node->InputAt(0);
  Node* limit = node->InputAt(1);

  Node* check = graph()->NewNode(machine()->Uint32LessThan(), index, limit);
  control = effect = graph()->NewNode(
      common()->DeoptimizeUnless(DeoptimizeReason::kOutOfBounds), check,
      frame_state, effect, control);

  return ValueEffectControl(index, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckMaps(Node* node, Node* frame_state,
                                        Node* effect, Node* control) {
  Node* value = node->InputAt(0);

  // Load the current map of the {value}.
  Node* value_map = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);

  int const map_count = node->op()->ValueInputCount() - 1;
  Node** controls = temp_zone()->NewArray<Node*>(map_count);
  Node** effects = temp_zone()->NewArray<Node*>(map_count + 1);

  for (int i = 0; i < map_count; ++i) {
    Node* map = node->InputAt(1 + i);

    Node* check = graph()->NewNode(machine()->WordEqual(), value_map, map);
    if (i == map_count - 1) {
      controls[i] = effects[i] = graph()->NewNode(
          common()->DeoptimizeUnless(DeoptimizeReason::kWrongMap), check,
          frame_state, effect, control);
    } else {
      control = graph()->NewNode(common()->Branch(), check, control);
      controls[i] = graph()->NewNode(common()->IfTrue(), control);
      control = graph()->NewNode(common()->IfFalse(), control);
      effects[i] = effect;
    }
  }

  control = graph()->NewNode(common()->Merge(map_count), map_count, controls);
  effects[map_count] = control;
  effect =
      graph()->NewNode(common()->EffectPhi(map_count), map_count + 1, effects);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckNumber(Node* node, Node* frame_state,
                                          Node* effect, Node* control) {
  Node* value = node->InputAt(0);

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

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* etrue0 = effect;

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  {
    Node* value_map = efalse0 =
        graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                         value, efalse0, if_false0);
    Node* check1 = graph()->NewNode(machine()->WordEqual(), value_map,
                                    jsgraph()->HeapNumberMapConstant());
    if_false0 = efalse0 = graph()->NewNode(
        common()->DeoptimizeUnless(DeoptimizeReason::kNotAHeapNumber), check1,
        frame_state, efalse0, if_false0);
  }

  control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckString(Node* node, Node* frame_state,
                                          Node* effect, Node* control) {
  Node* value = node->InputAt(0);

  Node* check0 = ObjectIsSmi(value);
  control = effect =
      graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kSmi), check0,
                       frame_state, effect, control);

  Node* value_map = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);
  Node* value_instance_type = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
      effect, control);

  Node* check1 =
      graph()->NewNode(machine()->Uint32LessThan(), value_instance_type,
                       jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
  control = effect = graph()->NewNode(
      common()->DeoptimizeUnless(DeoptimizeReason::kWrongInstanceType), check1,
      frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckIf(Node* node, Node* frame_state,
                                      Node* effect, Node* control) {
  Node* value = node->InputAt(0);

  control = effect =
      graph()->NewNode(common()->DeoptimizeUnless(DeoptimizeReason::kNoReason),
                       value, frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedInt32Add(Node* node, Node* frame_state,
                                              Node* effect, Node* control) {
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  Node* value =
      graph()->NewNode(machine()->Int32AddWithOverflow(), lhs, rhs, control);

  Node* check = graph()->NewNode(common()->Projection(1), value, control);
  control = effect =
      graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow),
                       check, frame_state, effect, control);

  value = graph()->NewNode(common()->Projection(0), value, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedInt32Sub(Node* node, Node* frame_state,
                                              Node* effect, Node* control) {
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  Node* value =
      graph()->NewNode(machine()->Int32SubWithOverflow(), lhs, rhs, control);

  Node* check = graph()->NewNode(common()->Projection(1), value, control);
  control = effect =
      graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow),
                       check, frame_state, effect, control);

  value = graph()->NewNode(common()->Projection(0), value, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedInt32Div(Node* node, Node* frame_state,
                                              Node* effect, Node* control) {
  Node* zero = jsgraph()->Int32Constant(0);
  Node* minusone = jsgraph()->Int32Constant(-1);
  Node* minint = jsgraph()->Int32Constant(std::numeric_limits<int32_t>::min());

  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  // Check if {rhs} is positive (and not zero).
  Node* check0 = graph()->NewNode(machine()->Int32LessThan(), zero, rhs);
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* etrue0 = effect;
  Node* vtrue0;
  {
    // Fast case, no additional checking required.
    vtrue0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_true0);
  }

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0;
  {
    // Check if {rhs} is zero.
    Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
    if_false0 = efalse0 = graph()->NewNode(
        common()->DeoptimizeIf(DeoptimizeReason::kDivisionByZero), check,
        frame_state, efalse0, if_false0);

    // Check if {lhs} is zero, as that would produce minus zero.
    check = graph()->NewNode(machine()->Word32Equal(), lhs, zero);
    if_false0 = efalse0 =
        graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kMinusZero),
                         check, frame_state, efalse0, if_false0);

    // Check if {lhs} is kMinInt and {rhs} is -1, in which case we'd have
    // to return -kMinInt, which is not representable.
    Node* check1 = graph()->NewNode(machine()->Word32Equal(), lhs, minint);
    Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                     check1, if_false0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = efalse0;
    {
      // Check if {rhs} is -1.
      Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, minusone);
      if_true1 = etrue1 =
          graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow),
                           check, frame_state, etrue1, if_true1);
    }

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* efalse1 = efalse0;

    if_false0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
    efalse0 =
        graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_false0);

    // Perform the actual integer division.
    vfalse0 = graph()->NewNode(machine()->Int32Div(), lhs, rhs, if_false0);
  }

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

  // Check if the remainder is non-zero.
  Node* check =
      graph()->NewNode(machine()->Word32Equal(), lhs,
                       graph()->NewNode(machine()->Int32Mul(), rhs, value));
  control = effect = graph()->NewNode(
      common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecision), check,
      frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedInt32Mod(Node* node, Node* frame_state,
                                              Node* effect, Node* control) {
  Node* zero = jsgraph()->Int32Constant(0);
  Node* one = jsgraph()->Int32Constant(1);

  // General case for signed integer modulus, with optimization for (unknown)
  // power of 2 right hand side.
  //
  //   if rhs <= 0 then
  //     rhs = -rhs
  //     deopt if rhs == 0
  //   if lhs < 0 then
  //     let res = lhs % rhs in
  //     deopt if res == 0
  //     res
  //   else
  //     let msk = rhs - 1 in
  //     if rhs & msk == 0 then
  //       lhs & msk
  //     else
  //       lhs % rhs
  //
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  // Check if {rhs} is not strictly positive.
  Node* check0 = graph()->NewNode(machine()->Int32LessThanOrEqual(), rhs, zero);
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* etrue0 = effect;
  Node* vtrue0;
  {
    // Negate {rhs}, might still produce a negative result in case of
    // -2^31, but that is handled safely below.
    vtrue0 = graph()->NewNode(machine()->Int32Sub(), zero, rhs);

    // Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
    Node* check = graph()->NewNode(machine()->Word32Equal(), vtrue0, zero);
    if_true0 = etrue0 = graph()->NewNode(
        common()->DeoptimizeIf(DeoptimizeReason::kDivisionByZero), check,
        frame_state, etrue0, if_true0);
  }

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0 = rhs;

  // At this point {rhs} is either greater than zero or -2^31, both are
  // fine for the code that follows.
  control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue0, efalse0, control);
  rhs = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                         vtrue0, vfalse0, control);

  // Check if {lhs} is negative.
  Node* check1 = graph()->NewNode(machine()->Int32LessThan(), lhs, zero);
  Node* branch1 =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, control);

  Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
  Node* etrue1 = effect;
  Node* vtrue1;
  {
    // Compute the remainder using {lhs % msk}.
    vtrue1 = graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_true1);

    // Check if we would have to return -0.
    Node* check = graph()->NewNode(machine()->Word32Equal(), vtrue1, zero);
    if_true1 = etrue1 =
        graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kMinusZero),
                         check, frame_state, etrue1, if_true1);
  }

  Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
  Node* efalse1 = effect;
  Node* vfalse1;
  {
    Node* msk = graph()->NewNode(machine()->Int32Sub(), rhs, one);

    // Check if {rhs} minus one is a valid mask.
    Node* check2 = graph()->NewNode(
        machine()->Word32Equal(),
        graph()->NewNode(machine()->Word32And(), rhs, msk), zero);
    Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);

    // Compute the remainder using {lhs & msk}.
    Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
    Node* vtrue2 = graph()->NewNode(machine()->Word32And(), lhs, msk);

    // Compute the remainder using the generic {lhs % rhs}.
    Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
    Node* vfalse2 =
        graph()->NewNode(machine()->Int32Mod(), lhs, rhs, if_false2);

    if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
    vfalse1 = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                               vtrue2, vfalse2, if_false1);
  }

  control = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, control);
  Node* value =
      graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), vtrue1,
                       vfalse1, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedUint32Div(Node* node, Node* frame_state,
                                               Node* effect, Node* control) {
  Node* zero = jsgraph()->Int32Constant(0);

  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  // Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
  Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
  control = effect = graph()->NewNode(
      common()->DeoptimizeIf(DeoptimizeReason::kDivisionByZero), check,
      frame_state, effect, control);

  // Perform the actual unsigned integer division.
  Node* value = graph()->NewNode(machine()->Uint32Div(), lhs, rhs, control);

  // Check if the remainder is non-zero.
  check = graph()->NewNode(machine()->Word32Equal(), lhs,
                           graph()->NewNode(machine()->Int32Mul(), rhs, value));
  control = effect = graph()->NewNode(
      common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecision), check,
      frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedUint32Mod(Node* node, Node* frame_state,
                                               Node* effect, Node* control) {
  Node* zero = jsgraph()->Int32Constant(0);

  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  // Ensure that {rhs} is not zero, otherwise we'd have to return NaN.
  Node* check = graph()->NewNode(machine()->Word32Equal(), rhs, zero);
  control = effect = graph()->NewNode(
      common()->DeoptimizeIf(DeoptimizeReason::kDivisionByZero), check,
      frame_state, effect, control);

  // Perform the actual unsigned integer modulus.
  Node* value = graph()->NewNode(machine()->Uint32Mod(), lhs, rhs, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedInt32Mul(Node* node, Node* frame_state,
                                              Node* effect, Node* control) {
  CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
  Node* zero = jsgraph()->Int32Constant(0);
  Node* lhs = node->InputAt(0);
  Node* rhs = node->InputAt(1);

  Node* projection =
      graph()->NewNode(machine()->Int32MulWithOverflow(), lhs, rhs, control);

  Node* check = graph()->NewNode(common()->Projection(1), projection, control);
  control = effect =
      graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow),
                       check, frame_state, effect, control);

  Node* value = graph()->NewNode(common()->Projection(0), projection, control);

  if (mode == CheckForMinusZeroMode::kCheckForMinusZero) {
    Node* check_zero = graph()->NewNode(machine()->Word32Equal(), value, zero);
    Node* branch_zero = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                         check_zero, control);

    Node* if_zero = graph()->NewNode(common()->IfTrue(), branch_zero);
    Node* e_if_zero = effect;
    {
      // We may need to return negative zero.
      Node* or_inputs = graph()->NewNode(machine()->Word32Or(), lhs, rhs);
      Node* check_or =
          graph()->NewNode(machine()->Int32LessThan(), or_inputs, zero);
      if_zero = e_if_zero =
          graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kMinusZero),
                           check_or, frame_state, e_if_zero, if_zero);
    }

    Node* if_not_zero = graph()->NewNode(common()->IfFalse(), branch_zero);
    Node* e_if_not_zero = effect;

    control = graph()->NewNode(common()->Merge(2), if_zero, if_not_zero);
    effect = graph()->NewNode(common()->EffectPhi(2), e_if_zero, e_if_not_zero,
                              control);
  }

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedInt32ToTaggedSigned(Node* node,
                                                         Node* frame_state,
                                                         Node* effect,
                                                         Node* control) {
  DCHECK(SmiValuesAre31Bits());
  Node* value = node->InputAt(0);

  Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), value, value,
                               control);

  Node* check = graph()->NewNode(common()->Projection(1), add, control);
  control = effect =
      graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kOverflow),
                       check, frame_state, effect, control);

  value = graph()->NewNode(common()->Projection(0), add, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedUint32ToInt32(Node* node,
                                                   Node* frame_state,
                                                   Node* effect,
                                                   Node* control) {
  Node* value = node->InputAt(0);
  Node* max_int = jsgraph()->Int32Constant(std::numeric_limits<int32_t>::max());
  Node* is_safe =
      graph()->NewNode(machine()->Uint32LessThanOrEqual(), value, max_int);
  control = effect = graph()->NewNode(
      common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecision), is_safe,
      frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedUint32ToTaggedSigned(Node* node,
                                                          Node* frame_state,
                                                          Node* effect,
                                                          Node* control) {
  Node* value = node->InputAt(0);
  Node* check = graph()->NewNode(machine()->Uint32LessThanOrEqual(), value,
                                 SmiMaxValueConstant());
  control = effect = graph()->NewNode(
      common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecision), check,
      frame_state, effect, control);
  value = ChangeUint32ToSmi(value);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::BuildCheckedFloat64ToInt32(CheckForMinusZeroMode mode,
                                                    Node* value,
                                                    Node* frame_state,
                                                    Node* effect,
                                                    Node* control) {
  Node* value32 = graph()->NewNode(machine()->RoundFloat64ToInt32(), value);
  Node* check_same = graph()->NewNode(
      machine()->Float64Equal(), value,
      graph()->NewNode(machine()->ChangeInt32ToFloat64(), value32));
  control = effect = graph()->NewNode(
      common()->DeoptimizeUnless(DeoptimizeReason::kLostPrecisionOrNaN),
      check_same, frame_state, effect, control);

  if (mode == CheckForMinusZeroMode::kCheckForMinusZero) {
    // Check if {value} is -0.
    Node* check_zero = graph()->NewNode(machine()->Word32Equal(), value32,
                                        jsgraph()->Int32Constant(0));
    Node* branch_zero = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                         check_zero, control);

    Node* if_zero = graph()->NewNode(common()->IfTrue(), branch_zero);
    Node* if_notzero = graph()->NewNode(common()->IfFalse(), branch_zero);

    // In case of 0, we need to check the high bits for the IEEE -0 pattern.
    Node* check_negative = graph()->NewNode(
        machine()->Int32LessThan(),
        graph()->NewNode(machine()->Float64ExtractHighWord32(), value),
        jsgraph()->Int32Constant(0));

    Node* deopt_minus_zero =
        graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kMinusZero),
                         check_negative, frame_state, effect, if_zero);

    control =
        graph()->NewNode(common()->Merge(2), deopt_minus_zero, if_notzero);
    effect = graph()->NewNode(common()->EffectPhi(2), deopt_minus_zero, effect,
                              control);
  }

  return ValueEffectControl(value32, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedFloat64ToInt32(Node* node,
                                                    Node* frame_state,
                                                    Node* effect,
                                                    Node* control) {
  CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
  Node* value = node->InputAt(0);

  return BuildCheckedFloat64ToInt32(mode, value, frame_state, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedTaggedSignedToInt32(Node* node,
                                                         Node* frame_state,
                                                         Node* effect,
                                                         Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  control = effect =
      graph()->NewNode(common()->DeoptimizeUnless(DeoptimizeReason::kNotASmi),
                       check, frame_state, effect, control);
  value = ChangeSmiToInt32(value);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedTaggedToInt32(Node* node,
                                                   Node* frame_state,
                                                   Node* effect,
                                                   Node* control) {
  CheckForMinusZeroMode mode = CheckMinusZeroModeOf(node->op());
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  // In the Smi case, just convert to int32.
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = ChangeSmiToInt32(value);

  // In the non-Smi case, check the heap numberness, load the number and convert
  // to int32.
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    Node* value_map = efalse =
        graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                         value, efalse, if_false);
    Node* check = graph()->NewNode(machine()->WordEqual(), value_map,
                                   jsgraph()->HeapNumberMapConstant());
    if_false = efalse = graph()->NewNode(
        common()->DeoptimizeUnless(DeoptimizeReason::kNotAHeapNumber), check,
        frame_state, efalse, if_false);
    vfalse = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
        efalse, if_false);
    ValueEffectControl state =
        BuildCheckedFloat64ToInt32(mode, vfalse, frame_state, efalse, if_false);
    if_false = state.control;
    efalse = state.effect;
    vfalse = state.value;
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                           vtrue, vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::BuildCheckedHeapNumberOrOddballToFloat64(
    CheckTaggedInputMode mode, Node* value, Node* frame_state, Node* effect,
    Node* control) {
  Node* value_map = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMap()), value, effect, control);

  Node* check_number = graph()->NewNode(machine()->WordEqual(), value_map,
                                        jsgraph()->HeapNumberMapConstant());

  switch (mode) {
    case CheckTaggedInputMode::kNumber: {
      control = effect = graph()->NewNode(
          common()->DeoptimizeUnless(DeoptimizeReason::kNotAHeapNumber),
          check_number, frame_state, effect, control);
      break;
    }
    case CheckTaggedInputMode::kNumberOrOddball: {
      Node* branch =
          graph()->NewNode(common()->Branch(), check_number, control);

      Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
      Node* etrue = effect;

      Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
      // For oddballs also contain the numeric value, let us just check that
      // we have an oddball here.
      Node* efalse = effect;
      Node* instance_type = efalse = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
          value_map, efalse, if_false);
      Node* check_oddball =
          graph()->NewNode(machine()->Word32Equal(), instance_type,
                           jsgraph()->Int32Constant(ODDBALL_TYPE));
      if_false = efalse = graph()->NewNode(
          common()->DeoptimizeUnless(DeoptimizeReason::kNotANumberOrOddball),
          check_oddball, frame_state, efalse, if_false);
      STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);

      control = graph()->NewNode(common()->Merge(2), if_true, if_false);
      effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
      break;
    }
  }

  value = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
      effect, control);
  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedTaggedToFloat64(Node* node,
                                                     Node* frame_state,
                                                     Node* effect,
                                                     Node* control) {
  CheckTaggedInputMode mode = CheckTaggedInputModeOf(node->op());
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch = graph()->NewNode(common()->Branch(), check, control);

  // In the Smi case, just convert to int32 and then float64.
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = ChangeSmiToInt32(value);
  vtrue = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue);

  // Otherwise, check heap numberness and load the number.
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  ValueEffectControl number_state = BuildCheckedHeapNumberOrOddballToFloat64(
      mode, value, frame_state, effect, if_false);

  Node* merge =
      graph()->NewNode(common()->Merge(2), if_true, number_state.control);
  Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), etrue,
                                      number_state.effect, merge);
  Node* result =
      graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2), vtrue,
                       number_state.value, merge);

  return ValueEffectControl(result, effect_phi, merge);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedTaggedToTaggedSigned(Node* node,
                                                          Node* frame_state,
                                                          Node* effect,
                                                          Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  control = effect =
      graph()->NewNode(common()->DeoptimizeUnless(DeoptimizeReason::kNotASmi),
                       check, frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedTaggedToTaggedPointer(Node* node,
                                                           Node* frame_state,
                                                           Node* effect,
                                                           Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  control = effect =
      graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kSmi), check,
                       frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerTruncateTaggedToWord32(Node* node, Node* effect,
                                                     Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = ChangeSmiToInt32(value);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    STATIC_ASSERT(HeapNumber::kValueOffset == Oddball::kToNumberRawOffset);
    vfalse = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForHeapNumberValue()), value,
        efalse, if_false);
    vfalse = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse);
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                           vtrue, vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckedTruncateTaggedToWord32(Node* node,
                                                            Node* frame_state,
                                                            Node* effect,
                                                            Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  // In the Smi case, just convert to int32.
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = ChangeSmiToInt32(value);

  // Otherwise, check that it's a heap number or oddball and truncate the value
  // to int32.
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  ValueEffectControl false_state = BuildCheckedHeapNumberOrOddballToFloat64(
      CheckTaggedInputMode::kNumberOrOddball, value, frame_state, effect,
      if_false);
  false_state.value =
      graph()->NewNode(machine()->TruncateFloat64ToWord32(), false_state.value);

  Node* merge =
      graph()->NewNode(common()->Merge(2), if_true, false_state.control);
  Node* effect_phi = graph()->NewNode(common()->EffectPhi(2), etrue,
                                      false_state.effect, merge);
  Node* result =
      graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2), vtrue,
                       false_state.value, merge);

  return ValueEffectControl(result, effect_phi, merge);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerObjectIsCallable(Node* node, Node* effect,
                                               Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = jsgraph()->Int32Constant(0);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    Node* value_map = efalse =
        graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                         value, efalse, if_false);
    Node* value_bit_field = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForMapBitField()), value_map,
        efalse, if_false);
    vfalse = graph()->NewNode(
        machine()->Word32Equal(),
        jsgraph()->Int32Constant(1 << Map::kIsCallable),
        graph()->NewNode(
            machine()->Word32And(), value_bit_field,
            jsgraph()->Int32Constant((1 << Map::kIsCallable) |
                                     (1 << Map::kIsUndetectable))));
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue,
                           vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerObjectIsNumber(Node* node, Node* effect,
                                             Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch = graph()->NewNode(common()->Branch(), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = jsgraph()->Int32Constant(1);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    Node* value_map = efalse =
        graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                         value, efalse, if_false);
    vfalse = graph()->NewNode(machine()->WordEqual(), value_map,
                              jsgraph()->HeapNumberMapConstant());
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue,
                           vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerObjectIsReceiver(Node* node, Node* effect,
                                               Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = jsgraph()->Int32Constant(0);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    STATIC_ASSERT(LAST_TYPE == LAST_JS_RECEIVER_TYPE);
    Node* value_map = efalse =
        graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                         value, efalse, if_false);
    Node* value_instance_type = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
        efalse, if_false);
    vfalse = graph()->NewNode(machine()->Uint32LessThanOrEqual(),
                              jsgraph()->Uint32Constant(FIRST_JS_RECEIVER_TYPE),
                              value_instance_type);
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue,
                           vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerObjectIsSmi(Node* node, Node* effect,
                                          Node* control) {
  Node* value = node->InputAt(0);
  value = ObjectIsSmi(value);
  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerObjectIsString(Node* node, Node* effect,
                                             Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = jsgraph()->Int32Constant(0);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    Node* value_map = efalse =
        graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                         value, efalse, if_false);
    Node* value_instance_type = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForMapInstanceType()), value_map,
        efalse, if_false);
    vfalse = graph()->NewNode(machine()->Uint32LessThan(), value_instance_type,
                              jsgraph()->Uint32Constant(FIRST_NONSTRING_TYPE));
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue,
                           vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerObjectIsUndetectable(Node* node, Node* effect,
                                                   Node* control) {
  Node* value = node->InputAt(0);

  Node* check = ObjectIsSmi(value);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = jsgraph()->Int32Constant(0);

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    Node* value_map = efalse =
        graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                         value, efalse, if_false);
    Node* value_bit_field = efalse = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForMapBitField()), value_map,
        efalse, if_false);
    vfalse = graph()->NewNode(
        machine()->Word32Equal(),
        graph()->NewNode(
            machine()->Word32Equal(), jsgraph()->Int32Constant(0),
            graph()->NewNode(
                machine()->Word32And(), value_bit_field,
                jsgraph()->Int32Constant(1 << Map::kIsUndetectable))),
        jsgraph()->Int32Constant(0));
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kBit, 2), vtrue,
                           vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerArrayBufferWasNeutered(Node* node, Node* effect,
                                                     Node* control) {
  Node* value = node->InputAt(0);

  Node* value_bit_field = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForJSArrayBufferBitField()), value,
      effect, control);
  value = graph()->NewNode(
      machine()->Word32Equal(),
      graph()->NewNode(machine()->Word32Equal(),
                       graph()->NewNode(machine()->Word32And(), value_bit_field,
                                        jsgraph()->Int32Constant(
                                            JSArrayBuffer::WasNeutered::kMask)),
                       jsgraph()->Int32Constant(0)),
      jsgraph()->Int32Constant(0));

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringCharCodeAt(Node* node, Node* effect,
                                               Node* control) {
  Node* subject = node->InputAt(0);
  Node* index = node->InputAt(1);

  // We may need to loop several times for ConsString/SlicedString {subject}s.
  Node* loop =
      graph()->NewNode(common()->Loop(4), control, control, control, control);
  Node* lsubject =
      graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 4),
                       subject, subject, subject, subject, loop);
  Node* lindex =
      graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 4), index,
                       index, index, index, loop);
  Node* leffect = graph()->NewNode(common()->EffectPhi(4), effect, effect,
                                   effect, effect, loop);

  control = loop;
  effect = leffect;

  // Determine the instance type of {lsubject}.
  Node* lsubject_map = effect =
      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                       lsubject, effect, control);
  Node* lsubject_instance_type = effect = graph()->NewNode(
      simplified()->LoadField(AccessBuilder::ForMapInstanceType()),
      lsubject_map, effect, control);

  // Check if {lsubject} is a SeqString.
  Node* check0 = graph()->NewNode(
      machine()->Word32Equal(),
      graph()->NewNode(machine()->Word32And(), lsubject_instance_type,
                       jsgraph()->Int32Constant(kStringRepresentationMask)),
      jsgraph()->Int32Constant(kSeqStringTag));
  Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* etrue0 = effect;
  Node* vtrue0;
  {
    // Check if the {lsubject} is a TwoByteSeqString or a OneByteSeqString.
    Node* check1 = graph()->NewNode(
        machine()->Word32Equal(),
        graph()->NewNode(machine()->Word32And(), lsubject_instance_type,
                         jsgraph()->Int32Constant(kStringEncodingMask)),
        jsgraph()->Int32Constant(kTwoByteStringTag));
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = etrue0;
    Node* vtrue1 = etrue1 =
        graph()->NewNode(simplified()->LoadElement(
                             AccessBuilder::ForSeqTwoByteStringCharacter()),
                         lsubject, lindex, etrue1, if_true1);

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* efalse1 = etrue0;
    Node* vfalse1 = efalse1 =
        graph()->NewNode(simplified()->LoadElement(
                             AccessBuilder::ForSeqOneByteStringCharacter()),
                         lsubject, lindex, efalse1, if_false1);

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

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0;
  {
    // Check if the {lsubject} is a ConsString.
    Node* check1 = graph()->NewNode(
        machine()->Word32Equal(),
        graph()->NewNode(machine()->Word32And(), lsubject_instance_type,
                         jsgraph()->Int32Constant(kStringRepresentationMask)),
        jsgraph()->Int32Constant(kConsStringTag));
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = efalse0;
    {
      // Load the right hand side of the {lsubject} ConsString.
      Node* lsubject_second = etrue1 = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForConsStringSecond()),
          lsubject, etrue1, if_true1);

      // Check whether the right hand side is the empty string (i.e. if
      // this is really a flat string in a cons string). If that is not
      // the case we flatten the string first.
      Node* check2 = graph()->NewNode(machine()->WordEqual(), lsubject_second,
                                      jsgraph()->EmptyStringConstant());
      Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
                                       check2, if_true1);

      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
      Node* etrue2 = etrue1;
      Node* vtrue2 = etrue2 = graph()->NewNode(
          simplified()->LoadField(AccessBuilder::ForConsStringFirst()),
          lsubject, etrue2, if_true2);

      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
      Node* efalse2 = etrue1;
      Node* vfalse2;
      {
        // Flatten the {lsubject} ConsString first.
        Operator::Properties properties =
            Operator::kNoDeopt | Operator::kNoThrow;
        Runtime::FunctionId id = Runtime::kFlattenString;
        CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
            graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
        vfalse2 = efalse2 = graph()->NewNode(
            common()->Call(desc), jsgraph()->CEntryStubConstant(1), lsubject,
            jsgraph()->ExternalConstant(ExternalReference(id, isolate())),
            jsgraph()->Int32Constant(1), jsgraph()->NoContextConstant(),
            efalse2, if_false2);
      }

      // Retry the {loop} with the new subject.
      loop->ReplaceInput(1, if_true2);
      lindex->ReplaceInput(1, lindex);
      leffect->ReplaceInput(1, etrue2);
      lsubject->ReplaceInput(1, vtrue2);
      loop->ReplaceInput(2, if_false2);
      lindex->ReplaceInput(2, lindex);
      leffect->ReplaceInput(2, efalse2);
      lsubject->ReplaceInput(2, vfalse2);
    }

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* efalse1 = efalse0;
    Node* vfalse1;
    {
      // Check if the {lsubject} is an ExternalString.
      Node* check2 = graph()->NewNode(
          machine()->Word32Equal(),
          graph()->NewNode(machine()->Word32And(), lsubject_instance_type,
                           jsgraph()->Int32Constant(kStringRepresentationMask)),
          jsgraph()->Int32Constant(kExternalStringTag));
      Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
                                       check2, if_false1);

      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
      Node* etrue2 = efalse1;
      Node* vtrue2;
      {
        // Check if the {lsubject} is a short external string.
        Node* check3 = graph()->NewNode(
            machine()->Word32Equal(),
            graph()->NewNode(
                machine()->Word32And(), lsubject_instance_type,
                jsgraph()->Int32Constant(kShortExternalStringMask)),
            jsgraph()->Int32Constant(0));
        Node* branch3 = graph()->NewNode(common()->Branch(BranchHint::kTrue),
                                         check3, if_true2);

        Node* if_true3 = graph()->NewNode(common()->IfTrue(), branch3);
        Node* etrue3 = etrue2;
        Node* vtrue3;
        {
          // Load the actual resource data from the {lsubject}.
          Node* lsubject_resource_data = etrue3 = graph()->NewNode(
              simplified()->LoadField(
                  AccessBuilder::ForExternalStringResourceData()),
              lsubject, etrue3, if_true3);

          // Check if the {lsubject} is a TwoByteExternalString or a
          // OneByteExternalString.
          Node* check4 = graph()->NewNode(
              machine()->Word32Equal(),
              graph()->NewNode(machine()->Word32And(), lsubject_instance_type,
                               jsgraph()->Int32Constant(kStringEncodingMask)),
              jsgraph()->Int32Constant(kTwoByteStringTag));
          Node* branch4 =
              graph()->NewNode(common()->Branch(), check4, if_true3);

          Node* if_true4 = graph()->NewNode(common()->IfTrue(), branch4);
          Node* etrue4 = etrue3;
          Node* vtrue4 = etrue4 = graph()->NewNode(
              simplified()->LoadElement(
                  AccessBuilder::ForExternalTwoByteStringCharacter()),
              lsubject_resource_data, lindex, etrue4, if_true4);

          Node* if_false4 = graph()->NewNode(common()->IfFalse(), branch4);
          Node* efalse4 = etrue3;
          Node* vfalse4 = efalse4 = graph()->NewNode(
              simplified()->LoadElement(
                  AccessBuilder::ForExternalOneByteStringCharacter()),
              lsubject_resource_data, lindex, efalse4, if_false4);

          if_true3 = graph()->NewNode(common()->Merge(2), if_true4, if_false4);
          etrue3 = graph()->NewNode(common()->EffectPhi(2), etrue4, efalse4,
                                    if_true3);
          vtrue3 =
              graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                               vtrue4, vfalse4, if_true3);
        }

        Node* if_false3 = graph()->NewNode(common()->IfFalse(), branch3);
        Node* efalse3 = etrue2;
        Node* vfalse3;
        {
          // The {lsubject} might be compressed, call the runtime.
          Operator::Properties properties =
              Operator::kNoDeopt | Operator::kNoThrow;
          Runtime::FunctionId id = Runtime::kExternalStringGetChar;
          CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
              graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags);
          vfalse3 = efalse3 = graph()->NewNode(
              common()->Call(desc), jsgraph()->CEntryStubConstant(1), lsubject,
              ChangeInt32ToSmi(lindex),
              jsgraph()->ExternalConstant(ExternalReference(id, isolate())),
              jsgraph()->Int32Constant(2), jsgraph()->NoContextConstant(),
              efalse3, if_false3);
          vfalse3 = ChangeSmiToInt32(vfalse3);
        }

        if_true2 = graph()->NewNode(common()->Merge(2), if_true3, if_false3);
        etrue2 =
            graph()->NewNode(common()->EffectPhi(2), etrue3, efalse3, if_true2);
        vtrue2 =
            graph()->NewNode(common()->Phi(MachineRepresentation::kWord32, 2),
                             vtrue3, vfalse3, if_true2);
      }

      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
      Node* efalse2 = efalse1;
      {
        // The {lsubject} is a SlicedString, continue with its parent.
        Node* lsubject_parent = efalse2 = graph()->NewNode(
            simplified()->LoadField(AccessBuilder::ForSlicedStringParent()),
            lsubject, efalse2, if_false2);
        Node* lsubject_offset = efalse2 = graph()->NewNode(
            simplified()->LoadField(AccessBuilder::ForSlicedStringOffset()),
            lsubject, efalse2, if_false2);
        Node* lsubject_index = graph()->NewNode(
            machine()->Int32Add(), lindex, ChangeSmiToInt32(lsubject_offset));

        // Retry the {loop} with the parent subject.
        loop->ReplaceInput(3, if_false2);
        leffect->ReplaceInput(3, efalse2);
        lindex->ReplaceInput(3, lsubject_index);
        lsubject->ReplaceInput(3, lsubject_parent);
      }

      if_false1 = if_true2;
      efalse1 = etrue2;
      vfalse1 = vtrue2;
    }

    if_false0 = if_false1;
    efalse0 = efalse1;
    vfalse0 = vfalse1;
  }

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

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringFromCharCode(Node* node, Node* effect,
                                                 Node* control) {
  Node* value = node->InputAt(0);

  // Compute the character code.
  Node* code =
      graph()->NewNode(machine()->Word32And(), value,
                       jsgraph()->Int32Constant(String::kMaxUtf16CodeUnit));

  // Check if the {code} is a one-byte char code.
  Node* check0 =
      graph()->NewNode(machine()->Int32LessThanOrEqual(), code,
                       jsgraph()->Int32Constant(String::kMaxOneByteCharCode));
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* etrue0 = effect;

  // Load the isolate wide single character string cache.
  Node* cache =
      jsgraph()->HeapConstant(factory()->single_character_string_cache());

  // Compute the {cache} index for {code}.
  Node* index = machine()->Is32()
                    ? code
                    : graph()->NewNode(machine()->ChangeUint32ToUint64(), code);

  // Check if we have an entry for the {code} in the single character string
  // cache already.
  Node* entry = etrue0 = graph()->NewNode(
      simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()), cache,
      index, etrue0, if_true0);

  Node* check1 = graph()->NewNode(machine()->WordEqual(), entry,
                                  jsgraph()->UndefinedConstant());
  Node* branch1 =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check1, if_true0);

  // Use the {entry} from the {cache}.
  Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
  Node* efalse1 = etrue0;
  Node* vfalse1 = entry;

  // Let %StringFromCharCode handle this case.
  // TODO(turbofan): At some point we may consider adding a stub for this
  // deferred case, so that we don't need to call to C++ here.
  Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
  Node* etrue1 = etrue0;
  Node* vtrue1;
  {
    if_true1 = graph()->NewNode(common()->Merge(2), if_true1, if_false0);
    etrue1 =
        graph()->NewNode(common()->EffectPhi(2), etrue1, efalse0, if_true1);
    Operator::Properties properties = Operator::kNoDeopt | Operator::kNoThrow;
    Runtime::FunctionId id = Runtime::kStringCharFromCode;
    CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
        graph()->zone(), id, 1, properties, CallDescriptor::kNoFlags);
    vtrue1 = etrue1 = graph()->NewNode(
        common()->Call(desc), jsgraph()->CEntryStubConstant(1),
        ChangeInt32ToSmi(code),
        jsgraph()->ExternalConstant(ExternalReference(id, isolate())),
        jsgraph()->Int32Constant(1), jsgraph()->NoContextConstant(), etrue1,
        if_true1);
  }

  control = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, control);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                           vtrue1, vfalse1, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringFromCodePoint(Node* node, Node* effect,
                                                  Node* control) {
  Node* value = node->InputAt(0);
  Node* code = value;

  Node* etrue0 = effect;
  Node* vtrue0;

  // Check if the {code} is a single code unit
  Node* check0 = graph()->NewNode(machine()->Uint32LessThanOrEqual(), code,
                                  jsgraph()->Uint32Constant(0xFFFF));
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  {
    // Check if the {code} is a one byte character
    Node* check1 = graph()->NewNode(
        machine()->Uint32LessThanOrEqual(), code,
        jsgraph()->Uint32Constant(String::kMaxOneByteCharCode));
    Node* branch1 =
        graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = etrue0;
    Node* vtrue1;
    {
      // Load the isolate wide single character string cache.
      Node* cache =
          jsgraph()->HeapConstant(factory()->single_character_string_cache());

      // Compute the {cache} index for {code}.
      Node* index =
          machine()->Is32()
              ? code
              : graph()->NewNode(machine()->ChangeUint32ToUint64(), code);

      // Check if we have an entry for the {code} in the single character string
      // cache already.
      Node* entry = etrue1 = graph()->NewNode(
          simplified()->LoadElement(AccessBuilder::ForFixedArrayElement()),
          cache, index, etrue1, if_true1);

      Node* check2 = graph()->NewNode(machine()->WordEqual(), entry,
                                      jsgraph()->UndefinedConstant());
      Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                       check2, if_true1);

      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
      Node* etrue2 = etrue1;
      Node* vtrue2;
      {
        // Allocate a new SeqOneByteString for {code}.
        vtrue2 = etrue2 = graph()->NewNode(
            simplified()->Allocate(NOT_TENURED),
            jsgraph()->Int32Constant(SeqOneByteString::SizeFor(1)), etrue2,
            if_true2);
        etrue2 = graph()->NewNode(
            simplified()->StoreField(AccessBuilder::ForMap()), vtrue2,
            jsgraph()->HeapConstant(factory()->one_byte_string_map()), etrue2,
            if_true2);
        etrue2 = graph()->NewNode(
            simplified()->StoreField(AccessBuilder::ForNameHashField()), vtrue2,
            jsgraph()->IntPtrConstant(Name::kEmptyHashField), etrue2, if_true2);
        etrue2 = graph()->NewNode(
            simplified()->StoreField(AccessBuilder::ForStringLength()), vtrue2,
            jsgraph()->SmiConstant(1), etrue2, if_true2);
        etrue2 = graph()->NewNode(
            machine()->Store(StoreRepresentation(MachineRepresentation::kWord8,
                                                 kNoWriteBarrier)),
            vtrue2, jsgraph()->IntPtrConstant(SeqOneByteString::kHeaderSize -
                                              kHeapObjectTag),
            code, etrue2, if_true2);

        // Remember it in the {cache}.
        etrue2 = graph()->NewNode(
            simplified()->StoreElement(AccessBuilder::ForFixedArrayElement()),
            cache, index, vtrue2, etrue2, if_true2);
      }

      // Use the {entry} from the {cache}.
      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
      Node* efalse2 = etrue0;
      Node* vfalse2 = entry;

      if_true1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
      etrue1 =
          graph()->NewNode(common()->EffectPhi(2), etrue2, efalse2, if_true1);
      vtrue1 =
          graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                           vtrue2, vfalse2, if_true1);
    }

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* efalse1 = effect;
    Node* vfalse1;
    {
      // Allocate a new SeqTwoByteString for {code}.
      vfalse1 = efalse1 = graph()->NewNode(
          simplified()->Allocate(NOT_TENURED),
          jsgraph()->Int32Constant(SeqTwoByteString::SizeFor(1)), efalse1,
          if_false1);
      efalse1 = graph()->NewNode(
          simplified()->StoreField(AccessBuilder::ForMap()), vfalse1,
          jsgraph()->HeapConstant(factory()->string_map()), efalse1, if_false1);
      efalse1 = graph()->NewNode(
          simplified()->StoreField(AccessBuilder::ForNameHashField()), vfalse1,
          jsgraph()->IntPtrConstant(Name::kEmptyHashField), efalse1, if_false1);
      efalse1 = graph()->NewNode(
          simplified()->StoreField(AccessBuilder::ForStringLength()), vfalse1,
          jsgraph()->SmiConstant(1), efalse1, if_false1);
      efalse1 = graph()->NewNode(
          machine()->Store(StoreRepresentation(MachineRepresentation::kWord16,
                                               kNoWriteBarrier)),
          vfalse1, jsgraph()->IntPtrConstant(SeqTwoByteString::kHeaderSize -
                                             kHeapObjectTag),
          code, efalse1, if_false1);
    }

    if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
    etrue0 =
        graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0);
    vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                              vtrue1, vfalse1, if_true0);
  }

  // Generate surrogate pair string
  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0;
  {
    switch (UnicodeEncodingOf(node->op())) {
      case UnicodeEncoding::UTF16:
        break;

      case UnicodeEncoding::UTF32: {
        // Convert UTF32 to UTF16 code units, and store as a 32 bit word.
        Node* lead_offset = jsgraph()->Int32Constant(0xD800 - (0x10000 >> 10));

        // lead = (codepoint >> 10) + LEAD_OFFSET
        Node* lead =
            graph()->NewNode(machine()->Int32Add(),
                             graph()->NewNode(machine()->Word32Shr(), code,
                                              jsgraph()->Int32Constant(10)),
                             lead_offset);

        // trail = (codepoint & 0x3FF) + 0xDC00;
        Node* trail =
            graph()->NewNode(machine()->Int32Add(),
                             graph()->NewNode(machine()->Word32And(), code,
                                              jsgraph()->Int32Constant(0x3FF)),
                             jsgraph()->Int32Constant(0xDC00));

        // codpoint = (trail << 16) | lead;
        code = graph()->NewNode(machine()->Word32Or(),
                                graph()->NewNode(machine()->Word32Shl(), trail,
                                                 jsgraph()->Int32Constant(16)),
                                lead);
        break;
      }
    }

    // Allocate a new SeqTwoByteString for {code}.
    vfalse0 = efalse0 =
        graph()->NewNode(simplified()->Allocate(NOT_TENURED),
                         jsgraph()->Int32Constant(SeqTwoByteString::SizeFor(2)),
                         efalse0, if_false0);
    efalse0 = graph()->NewNode(
        simplified()->StoreField(AccessBuilder::ForMap()), vfalse0,
        jsgraph()->HeapConstant(factory()->string_map()), efalse0, if_false0);
    efalse0 = graph()->NewNode(
        simplified()->StoreField(AccessBuilder::ForNameHashField()), vfalse0,
        jsgraph()->IntPtrConstant(Name::kEmptyHashField), efalse0, if_false0);
    efalse0 = graph()->NewNode(
        simplified()->StoreField(AccessBuilder::ForStringLength()), vfalse0,
        jsgraph()->SmiConstant(2), efalse0, if_false0);
    efalse0 = graph()->NewNode(
        machine()->Store(StoreRepresentation(MachineRepresentation::kWord32,
                                             kNoWriteBarrier)),
        vfalse0, jsgraph()->IntPtrConstant(SeqTwoByteString::kHeaderSize -
                                           kHeapObjectTag),
        code, efalse0, 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::kTagged, 2),
                           vtrue0, vfalse0, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringComparison(Callable const& callable,
                                               Node* node, Node* effect,
                                               Node* control) {
  Operator::Properties properties = Operator::kEliminatable;
  CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
  CallDescriptor* desc = Linkage::GetStubCallDescriptor(
      isolate(), graph()->zone(), callable.descriptor(), 0, flags, properties);
  node->InsertInput(graph()->zone(), 0,
                    jsgraph()->HeapConstant(callable.code()));
  node->AppendInput(graph()->zone(), jsgraph()->NoContextConstant());
  node->AppendInput(graph()->zone(), effect);
  NodeProperties::ChangeOp(node, common()->Call(desc));
  return ValueEffectControl(node, node, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringEqual(Node* node, Node* effect,
                                          Node* control) {
  return LowerStringComparison(CodeFactory::StringEqual(isolate()), node,
                               effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringLessThan(Node* node, Node* effect,
                                             Node* control) {
  return LowerStringComparison(CodeFactory::StringLessThan(isolate()), node,
                               effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStringLessThanOrEqual(Node* node, Node* effect,
                                                    Node* control) {
  return LowerStringComparison(CodeFactory::StringLessThanOrEqual(isolate()),
                               node, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckFloat64Hole(Node* node, Node* frame_state,
                                               Node* effect, Node* control) {
  // If we reach this point w/o eliminating the {node} that's marked
  // with allow-return-hole, we cannot do anything, so just deoptimize
  // in case of the hole NaN (similar to Crankshaft).
  Node* value = node->InputAt(0);
  Node* check = graph()->NewNode(
      machine()->Word32Equal(),
      graph()->NewNode(machine()->Float64ExtractHighWord32(), value),
      jsgraph()->Int32Constant(kHoleNanUpper32));
  control = effect =
      graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kHole), check,
                       frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerCheckTaggedHole(Node* node, Node* frame_state,
                                              Node* effect, Node* control) {
  Node* value = node->InputAt(0);
  Node* check = graph()->NewNode(machine()->WordEqual(), value,
                                 jsgraph()->TheHoleConstant());
  control = effect =
      graph()->NewNode(common()->DeoptimizeIf(DeoptimizeReason::kHole), check,
                       frame_state, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerConvertTaggedHoleToUndefined(Node* node,
                                                           Node* effect,
                                                           Node* control) {
  Node* value = node->InputAt(0);
  Node* check = graph()->NewNode(machine()->WordEqual(), value,
                                 jsgraph()->TheHoleConstant());
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);

  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* vtrue = jsgraph()->UndefinedConstant();

  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* vfalse = value;

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  value = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                           vtrue, vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::AllocateHeapNumberWithValue(Node* value, Node* effect,
                                                     Node* control) {
  Node* result = effect = graph()->NewNode(
      simplified()->Allocate(NOT_TENURED),
      jsgraph()->Int32Constant(HeapNumber::kSize), effect, control);
  effect = graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
                            result, jsgraph()->HeapNumberMapConstant(), effect,
                            control);
  effect = graph()->NewNode(
      simplified()->StoreField(AccessBuilder::ForHeapNumberValue()), result,
      value, effect, control);
  return ValueEffectControl(result, effect, control);
}

Node* EffectControlLinearizer::ChangeInt32ToSmi(Node* value) {
  if (machine()->Is64()) {
    value = graph()->NewNode(machine()->ChangeInt32ToInt64(), value);
  }
  return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
}

Node* EffectControlLinearizer::ChangeUint32ToSmi(Node* value) {
  if (machine()->Is64()) {
    value = graph()->NewNode(machine()->ChangeUint32ToUint64(), value);
  }
  return graph()->NewNode(machine()->WordShl(), value, SmiShiftBitsConstant());
}

Node* EffectControlLinearizer::ChangeInt32ToFloat64(Node* value) {
  return graph()->NewNode(machine()->ChangeInt32ToFloat64(), value);
}

Node* EffectControlLinearizer::ChangeUint32ToFloat64(Node* value) {
  return graph()->NewNode(machine()->ChangeUint32ToFloat64(), value);
}

Node* EffectControlLinearizer::ChangeSmiToInt32(Node* value) {
  value = graph()->NewNode(machine()->WordSar(), value, SmiShiftBitsConstant());
  if (machine()->Is64()) {
    value = graph()->NewNode(machine()->TruncateInt64ToInt32(), value);
  }
  return value;
}
Node* EffectControlLinearizer::ObjectIsSmi(Node* value) {
  return graph()->NewNode(
      machine()->WordEqual(),
      graph()->NewNode(machine()->WordAnd(), value,
                       jsgraph()->IntPtrConstant(kSmiTagMask)),
      jsgraph()->IntPtrConstant(kSmiTag));
}

Node* EffectControlLinearizer::SmiMaxValueConstant() {
  return jsgraph()->Int32Constant(Smi::kMaxValue);
}

Node* EffectControlLinearizer::SmiShiftBitsConstant() {
  return jsgraph()->IntPtrConstant(kSmiShiftSize + kSmiTagSize);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerPlainPrimitiveToNumber(Node* node, Node* effect,
                                                     Node* control) {
  Node* value = node->InputAt(0);
  Node* result = effect =
      graph()->NewNode(ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(),
                       value, jsgraph()->NoContextConstant(), effect);
  return ValueEffectControl(result, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerPlainPrimitiveToWord32(Node* node, Node* effect,
                                                     Node* control) {
  Node* value = node->InputAt(0);

  Node* check0 = 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 = ChangeSmiToInt32(value);

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0;
  {
    vfalse0 = efalse0 = graph()->NewNode(
        ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), value,
        jsgraph()->NoContextConstant(), efalse0);

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

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = efalse0;
    Node* vtrue1 = ChangeSmiToInt32(vfalse0);

    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);
      vfalse1 = graph()->NewNode(machine()->TruncateFloat64ToWord32(), vfalse1);
    }

    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);
  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerPlainPrimitiveToFloat64(Node* node, Node* effect,
                                                      Node* control) {
  Node* value = node->InputAt(0);

  Node* check0 = 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;
  {
    vtrue0 = ChangeSmiToInt32(value);
    vtrue0 = graph()->NewNode(machine()->ChangeInt32ToFloat64(), vtrue0);
  }

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0;
  {
    vfalse0 = efalse0 = graph()->NewNode(
        ToNumberOperator(), jsgraph()->ToNumberBuiltinConstant(), value,
        jsgraph()->NoContextConstant(), efalse0);

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

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = efalse0;
    Node* vtrue1;
    {
      vtrue1 = ChangeSmiToInt32(vfalse0);
      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);
  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerEnsureWritableFastElements(Node* node,
                                                         Node* effect,
                                                         Node* control) {
  Node* object = node->InputAt(0);
  Node* elements = node->InputAt(1);

  // Load the current map of {elements}.
  Node* elements_map = effect =
      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()),
                       elements, effect, control);

  // Check if {elements} is not a copy-on-write FixedArray.
  Node* check = graph()->NewNode(machine()->WordEqual(), elements_map,
                                 jsgraph()->FixedArrayMapConstant());
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

  // Nothing to do if the {elements} are not copy-on-write.
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  Node* vtrue = elements;

  // We need to take a copy of the {elements} and set them up for {object}.
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;
  Node* vfalse;
  {
    // We need to create a copy of the {elements} for {object}.
    Operator::Properties properties = Operator::kEliminatable;
    Callable callable = CodeFactory::CopyFastSmiOrObjectElements(isolate());
    CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
    CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
        isolate(), graph()->zone(), callable.descriptor(), 0, flags,
        properties);
    vfalse = efalse = graph()->NewNode(
        common()->Call(desc), jsgraph()->HeapConstant(callable.code()), object,
        jsgraph()->NoContextConstant(), efalse);
  }

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);
  Node* value = graph()->NewNode(
      common()->Phi(MachineRepresentation::kTagged, 2), vtrue, vfalse, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerMaybeGrowFastElements(Node* node,
                                                    Node* frame_state,
                                                    Node* effect,
                                                    Node* control) {
  GrowFastElementsFlags flags = GrowFastElementsFlagsOf(node->op());
  Node* object = node->InputAt(0);
  Node* elements = node->InputAt(1);
  Node* index = node->InputAt(2);
  Node* length = node->InputAt(3);

  Node* check0 = graph()->NewNode((flags & GrowFastElementsFlag::kHoleyElements)
                                      ? machine()->Uint32LessThanOrEqual()
                                      : machine()->Word32Equal(),
                                  length, index);
  Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* etrue0 = effect;
  Node* vtrue0 = elements;
  {
    // Load the length of the {elements} backing store.
    Node* elements_length = etrue0 = graph()->NewNode(
        simplified()->LoadField(AccessBuilder::ForFixedArrayLength()), elements,
        etrue0, if_true0);
    elements_length = ChangeSmiToInt32(elements_length);

    // Check if we need to grow the {elements} backing store.
    Node* check1 =
        graph()->NewNode(machine()->Uint32LessThan(), index, elements_length);
    Node* branch1 =
        graph()->NewNode(common()->Branch(BranchHint::kTrue), check1, if_true0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* etrue1 = etrue0;
    Node* vtrue1 = vtrue0;

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* efalse1 = etrue0;
    Node* vfalse1 = vtrue0;
    {
      // We need to grow the {elements} for {object}.
      Operator::Properties properties = Operator::kEliminatable;
      Callable callable =
          (flags & GrowFastElementsFlag::kDoubleElements)
              ? CodeFactory::GrowFastDoubleElements(isolate())
              : CodeFactory::GrowFastSmiOrObjectElements(isolate());
      CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
      CallDescriptor const* const desc = Linkage::GetStubCallDescriptor(
          isolate(), graph()->zone(), callable.descriptor(), 0, flags,
          properties);
      vfalse1 = efalse1 = graph()->NewNode(
          common()->Call(desc), jsgraph()->HeapConstant(callable.code()),
          object, ChangeInt32ToSmi(index), jsgraph()->NoContextConstant(),
          efalse1);

      // Ensure that we were able to grow the {elements}.
      // TODO(turbofan): We use kSmi as reason here similar to Crankshaft,
      // but maybe we should just introduce a reason that makes sense.
      efalse1 = if_false1 = graph()->NewNode(
          common()->DeoptimizeIf(DeoptimizeReason::kSmi), ObjectIsSmi(vfalse1),
          frame_state, efalse1, if_false1);
    }

    if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
    etrue0 =
        graph()->NewNode(common()->EffectPhi(2), etrue1, efalse1, if_true0);
    vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kTagged, 2),
                              vtrue1, vfalse1, if_true0);

    // For JSArray {object}s we also need to update the "length".
    if (flags & GrowFastElementsFlag::kArrayObject) {
      // Compute the new {length}.
      Node* object_length = ChangeInt32ToSmi(graph()->NewNode(
          machine()->Int32Add(), index, jsgraph()->Int32Constant(1)));

      // Update the "length" property of the {object}.
      etrue0 =
          graph()->NewNode(simplified()->StoreField(
                               AccessBuilder::ForJSArrayLength(FAST_ELEMENTS)),
                           object, object_length, etrue0, if_true0);
    }
  }

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* efalse0 = effect;
  Node* vfalse0 = elements;
  {
    // In case of non-holey {elements}, we need to verify that the {index} is
    // in-bounds, otherwise for holey {elements}, the check above already
    // guards the index (and the operator forces {index} to be unsigned).
    if (!(flags & GrowFastElementsFlag::kHoleyElements)) {
      Node* check1 =
          graph()->NewNode(machine()->Uint32LessThan(), index, length);
      efalse0 = if_false0 = graph()->NewNode(
          common()->DeoptimizeUnless(DeoptimizeReason::kOutOfBounds), check1,
          frame_state, efalse0, if_false0);
    }
  }

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

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerTransitionElementsKind(Node* node, Node* effect,
                                                     Node* control) {
  ElementsTransition const transition = ElementsTransitionOf(node->op());
  Node* object = node->InputAt(0);
  Node* source_map = node->InputAt(1);
  Node* target_map = node->InputAt(2);

  // Load the current map of {object}.
  Node* object_map = effect =
      graph()->NewNode(simplified()->LoadField(AccessBuilder::ForMap()), object,
                       effect, control);

  // Check if {object_map} is the same as {source_map}.
  Node* check =
      graph()->NewNode(machine()->WordEqual(), object_map, source_map);
  Node* branch =
      graph()->NewNode(common()->Branch(BranchHint::kFalse), check, control);

  // Migrate the {object} from {source_map} to {target_map}.
  Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
  Node* etrue = effect;
  {
    switch (transition) {
      case ElementsTransition::kFastTransition: {
        // In-place migration of {object}, just store the {target_map}.
        etrue =
            graph()->NewNode(simplified()->StoreField(AccessBuilder::ForMap()),
                             object, target_map, etrue, if_true);
        break;
      }
      case ElementsTransition::kSlowTransition: {
        // Instance migration, call out to the runtime for {object}.
        Operator::Properties properties =
            Operator::kNoDeopt | Operator::kNoThrow;
        Runtime::FunctionId id = Runtime::kTransitionElementsKind;
        CallDescriptor const* desc = Linkage::GetRuntimeCallDescriptor(
            graph()->zone(), id, 2, properties, CallDescriptor::kNoFlags);
        etrue = graph()->NewNode(
            common()->Call(desc), jsgraph()->CEntryStubConstant(1), object,
            target_map,
            jsgraph()->ExternalConstant(ExternalReference(id, isolate())),
            jsgraph()->Int32Constant(2), jsgraph()->NoContextConstant(), etrue,
            if_true);
        break;
      }
    }
  }

  // Nothing to do if the {object} doesn't have the {source_map}.
  Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
  Node* efalse = effect;

  control = graph()->NewNode(common()->Merge(2), if_true, if_false);
  effect = graph()->NewNode(common()->EffectPhi(2), etrue, efalse, control);

  return ValueEffectControl(nullptr, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerLoadTypedElement(Node* node, Node* effect,
                                               Node* control) {
  ExternalArrayType array_type = ExternalArrayTypeOf(node->op());
  Node* buffer = node->InputAt(0);
  Node* base = node->InputAt(1);
  Node* external = node->InputAt(2);
  Node* index = node->InputAt(3);

  // We need to keep the {buffer} alive so that the GC will not release the
  // ArrayBuffer (if there's any) as long as we are still operating on it.
  effect = graph()->NewNode(common()->Retain(), buffer, effect);

  // Compute the effective storage pointer.
  Node* storage = effect = graph()->NewNode(machine()->UnsafePointerAdd(), base,
                                            external, effect, control);

  // Perform the actual typed element access.
  Node* value = effect = graph()->NewNode(
      simplified()->LoadElement(
          AccessBuilder::ForTypedArrayElement(array_type, true)),
      storage, index, effect, control);

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerStoreTypedElement(Node* node, Node* effect,
                                                Node* control) {
  ExternalArrayType array_type = ExternalArrayTypeOf(node->op());
  Node* buffer = node->InputAt(0);
  Node* base = node->InputAt(1);
  Node* external = node->InputAt(2);
  Node* index = node->InputAt(3);
  Node* value = node->InputAt(4);

  // We need to keep the {buffer} alive so that the GC will not release the
  // ArrayBuffer (if there's any) as long as we are still operating on it.
  effect = graph()->NewNode(common()->Retain(), buffer, effect);

  // Compute the effective storage pointer.
  Node* storage = effect = graph()->NewNode(machine()->UnsafePointerAdd(), base,
                                            external, effect, control);

  // Perform the actual typed element access.
  effect = graph()->NewNode(
      simplified()->StoreElement(
          AccessBuilder::ForTypedArrayElement(array_type, true)),
      storage, index, value, effect, control);

  return ValueEffectControl(nullptr, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerFloat64RoundUp(Node* node, Node* effect,
                                             Node* control) {
  // Nothing to be done if a fast hardware instruction is available.
  if (machine()->Float64RoundUp().IsSupported()) {
    return ValueEffectControl(node, effect, control);
  }

  Node* const one = jsgraph()->Float64Constant(1.0);
  Node* const zero = jsgraph()->Float64Constant(0.0);
  Node* const minus_zero = jsgraph()->Float64Constant(-0.0);
  Node* const two_52 = jsgraph()->Float64Constant(4503599627370496.0E0);
  Node* const minus_two_52 = jsgraph()->Float64Constant(-4503599627370496.0E0);
  Node* const input = node->InputAt(0);

  // General case for ceil.
  //
  //   if 0.0 < input then
  //     if 2^52 <= input then
  //       input
  //     else
  //       let temp1 = (2^52 + input) - 2^52 in
  //       if temp1 < input then
  //         temp1 + 1
  //       else
  //         temp1
  //   else
  //     if input == 0 then
  //       input
  //     else
  //       if input <= -2^52 then
  //         input
  //       else
  //         let temp1 = -0 - input in
  //         let temp2 = (2^52 + temp1) - 2^52 in
  //         let temp3 = (if temp1 < temp2 then temp2 - 1 else temp2) in
  //         -0 - temp3
  //
  // Note: We do not use the Diamond helper class here, because it really hurts
  // readability with nested diamonds.

  Node* check0 = graph()->NewNode(machine()->Float64LessThan(), zero, input);
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* vtrue0;
  {
    Node* check1 =
        graph()->NewNode(machine()->Float64LessThanOrEqual(), two_52, input);
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* vtrue1 = input;

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* vfalse1;
    {
      Node* temp1 = graph()->NewNode(
          machine()->Float64Sub(),
          graph()->NewNode(machine()->Float64Add(), two_52, input), two_52);
      vfalse1 = graph()->NewNode(
          common()->Select(MachineRepresentation::kFloat64),
          graph()->NewNode(machine()->Float64LessThan(), temp1, input),
          graph()->NewNode(machine()->Float64Add(), temp1, one), temp1);
    }

    if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
    vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                              vtrue1, vfalse1, if_true0);
  }

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* vfalse0;
  {
    Node* check1 = graph()->NewNode(machine()->Float64Equal(), input, zero);
    Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                     check1, if_false0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* vtrue1 = input;

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* vfalse1;
    {
      Node* check2 = graph()->NewNode(machine()->Float64LessThanOrEqual(),
                                      input, minus_two_52);
      Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                       check2, if_false1);

      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
      Node* vtrue2 = input;

      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
      Node* vfalse2;
      {
        Node* temp1 =
            graph()->NewNode(machine()->Float64Sub(), minus_zero, input);
        Node* temp2 = graph()->NewNode(
            machine()->Float64Sub(),
            graph()->NewNode(machine()->Float64Add(), two_52, temp1), two_52);
        Node* temp3 = graph()->NewNode(
            common()->Select(MachineRepresentation::kFloat64),
            graph()->NewNode(machine()->Float64LessThan(), temp1, temp2),
            graph()->NewNode(machine()->Float64Sub(), temp2, one), temp2);
        vfalse2 = graph()->NewNode(machine()->Float64Sub(), minus_zero, temp3);
      }

      if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
      vfalse1 =
          graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                           vtrue2, vfalse2, if_false1);
    }

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

  Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
  Node* value =
      graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                       vtrue0, vfalse0, merge0);
  return ValueEffectControl(value, effect, merge0);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::BuildFloat64RoundDown(Node* value, Node* effect,
                                               Node* control) {
  if (machine()->Float64RoundDown().IsSupported()) {
    value = graph()->NewNode(machine()->Float64RoundDown().op(), value);
  } else {
    Node* const one = jsgraph()->Float64Constant(1.0);
    Node* const zero = jsgraph()->Float64Constant(0.0);
    Node* const minus_one = jsgraph()->Float64Constant(-1.0);
    Node* const minus_zero = jsgraph()->Float64Constant(-0.0);
    Node* const two_52 = jsgraph()->Float64Constant(4503599627370496.0E0);
    Node* const minus_two_52 =
        jsgraph()->Float64Constant(-4503599627370496.0E0);
    Node* const input = value;

    // General case for floor.
    //
    //   if 0.0 < input then
    //     if 2^52 <= input then
    //       input
    //     else
    //       let temp1 = (2^52 + input) - 2^52 in
    //       if input < temp1 then
    //         temp1 - 1
    //       else
    //         temp1
    //   else
    //     if input == 0 then
    //       input
    //     else
    //       if input <= -2^52 then
    //         input
    //       else
    //         let temp1 = -0 - input in
    //         let temp2 = (2^52 + temp1) - 2^52 in
    //         if temp2 < temp1 then
    //           -1 - temp2
    //         else
    //           -0 - temp2
    //
    // Note: We do not use the Diamond helper class here, because it really
    // hurts
    // readability with nested diamonds.

    Node* check0 = graph()->NewNode(machine()->Float64LessThan(), zero, input);
    Node* branch0 =
        graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);

    Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
    Node* vtrue0;
    {
      Node* check1 =
          graph()->NewNode(machine()->Float64LessThanOrEqual(), two_52, input);
      Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);

      Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
      Node* vtrue1 = input;

      Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
      Node* vfalse1;
      {
        Node* temp1 = graph()->NewNode(
            machine()->Float64Sub(),
            graph()->NewNode(machine()->Float64Add(), two_52, input), two_52);
        vfalse1 = graph()->NewNode(
            common()->Select(MachineRepresentation::kFloat64),
            graph()->NewNode(machine()->Float64LessThan(), input, temp1),
            graph()->NewNode(machine()->Float64Sub(), temp1, one), temp1);
      }

      if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
      vtrue0 =
          graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                           vtrue1, vfalse1, if_true0);
    }

    Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
    Node* vfalse0;
    {
      Node* check1 = graph()->NewNode(machine()->Float64Equal(), input, zero);
      Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                       check1, if_false0);

      Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
      Node* vtrue1 = input;

      Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
      Node* vfalse1;
      {
        Node* check2 = graph()->NewNode(machine()->Float64LessThanOrEqual(),
                                        input, minus_two_52);
        Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                         check2, if_false1);

        Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
        Node* vtrue2 = input;

        Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
        Node* vfalse2;
        {
          Node* temp1 =
              graph()->NewNode(machine()->Float64Sub(), minus_zero, input);
          Node* temp2 = graph()->NewNode(
              machine()->Float64Sub(),
              graph()->NewNode(machine()->Float64Add(), two_52, temp1), two_52);
          vfalse2 = graph()->NewNode(
              common()->Select(MachineRepresentation::kFloat64),
              graph()->NewNode(machine()->Float64LessThan(), temp2, temp1),
              graph()->NewNode(machine()->Float64Sub(), minus_one, temp2),
              graph()->NewNode(machine()->Float64Sub(), minus_zero, temp2));
        }

        if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
        vfalse1 =
            graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                             vtrue2, vfalse2, if_false1);
      }

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

    control = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
    value = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                             vtrue0, vfalse0, control);
  }
  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerFloat64RoundDown(Node* node, Node* effect,
                                               Node* control) {
  // Nothing to be done if a fast hardware instruction is available.
  if (machine()->Float64RoundDown().IsSupported()) {
    return ValueEffectControl(node, effect, control);
  }

  Node* const input = node->InputAt(0);
  return BuildFloat64RoundDown(input, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerFloat64RoundTiesEven(Node* node, Node* effect,
                                                   Node* control) {
  // Nothing to be done if a fast hardware instruction is available.
  if (machine()->Float64RoundTiesEven().IsSupported()) {
    return ValueEffectControl(node, effect, control);
  }

  Node* const one = jsgraph()->Float64Constant(1.0);
  Node* const two = jsgraph()->Float64Constant(2.0);
  Node* const half = jsgraph()->Float64Constant(0.5);
  Node* const zero = jsgraph()->Float64Constant(0.0);
  Node* const input = node->InputAt(0);

  // Generate case for round ties to even:
  //
  //   let value = floor(input) in
  //   let temp1 = input - value in
  //   if temp1 < 0.5 then
  //     value
  //   else if 0.5 < temp1 then
  //     value + 1.0
  //   else
  //     let temp2 = value % 2.0 in
  //     if temp2 == 0.0 then
  //       value
  //     else
  //       value + 1.0
  //
  // Note: We do not use the Diamond helper class here, because it really hurts
  // readability with nested diamonds.

  ValueEffectControl continuation =
      BuildFloat64RoundDown(input, effect, control);
  Node* value = continuation.value;
  effect = continuation.effect;
  control = continuation.control;

  Node* temp1 = graph()->NewNode(machine()->Float64Sub(), input, value);

  Node* check0 = graph()->NewNode(machine()->Float64LessThan(), temp1, half);
  Node* branch0 = graph()->NewNode(common()->Branch(), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* vtrue0 = value;

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* vfalse0;
  {
    Node* check1 = graph()->NewNode(machine()->Float64LessThan(), half, temp1);
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_false0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* vtrue1 = graph()->NewNode(machine()->Float64Add(), value, one);

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* vfalse1;
    {
      Node* temp2 = graph()->NewNode(machine()->Float64Mod(), value, two);

      Node* check2 = graph()->NewNode(machine()->Float64Equal(), temp2, zero);
      Node* branch2 = graph()->NewNode(common()->Branch(), check2, if_false1);

      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
      Node* vtrue2 = value;

      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
      Node* vfalse2 = graph()->NewNode(machine()->Float64Add(), value, one);

      if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
      vfalse1 =
          graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                           vtrue2, vfalse2, if_false1);
    }

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

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

  return ValueEffectControl(value, effect, control);
}

EffectControlLinearizer::ValueEffectControl
EffectControlLinearizer::LowerFloat64RoundTruncate(Node* node, Node* effect,
                                                   Node* control) {
  // Nothing to be done if a fast hardware instruction is available.
  if (machine()->Float64RoundTruncate().IsSupported()) {
    return ValueEffectControl(node, effect, control);
  }

  Node* const one = jsgraph()->Float64Constant(1.0);
  Node* const zero = jsgraph()->Float64Constant(0.0);
  Node* const minus_zero = jsgraph()->Float64Constant(-0.0);
  Node* const two_52 = jsgraph()->Float64Constant(4503599627370496.0E0);
  Node* const minus_two_52 = jsgraph()->Float64Constant(-4503599627370496.0E0);
  Node* const input = node->InputAt(0);

  // General case for trunc.
  //
  //   if 0.0 < input then
  //     if 2^52 <= input then
  //       input
  //     else
  //       let temp1 = (2^52 + input) - 2^52 in
  //       if input < temp1 then
  //         temp1 - 1
  //       else
  //         temp1
  //   else
  //     if input == 0 then
  //       input
  //     else
  //       if input <= -2^52 then
  //         input
  //       else
  //         let temp1 = -0 - input in
  //         let temp2 = (2^52 + temp1) - 2^52 in
  //         let temp3 = (if temp1 < temp2 then temp2 - 1 else temp2) in
  //         -0 - temp3
  //
  // Note: We do not use the Diamond helper class here, because it really hurts
  // readability with nested diamonds.

  Node* check0 = graph()->NewNode(machine()->Float64LessThan(), zero, input);
  Node* branch0 =
      graph()->NewNode(common()->Branch(BranchHint::kTrue), check0, control);

  Node* if_true0 = graph()->NewNode(common()->IfTrue(), branch0);
  Node* vtrue0;
  {
    Node* check1 =
        graph()->NewNode(machine()->Float64LessThanOrEqual(), two_52, input);
    Node* branch1 = graph()->NewNode(common()->Branch(), check1, if_true0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* vtrue1 = input;

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* vfalse1;
    {
      Node* temp1 = graph()->NewNode(
          machine()->Float64Sub(),
          graph()->NewNode(machine()->Float64Add(), two_52, input), two_52);
      vfalse1 = graph()->NewNode(
          common()->Select(MachineRepresentation::kFloat64),
          graph()->NewNode(machine()->Float64LessThan(), input, temp1),
          graph()->NewNode(machine()->Float64Sub(), temp1, one), temp1);
    }

    if_true0 = graph()->NewNode(common()->Merge(2), if_true1, if_false1);
    vtrue0 = graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                              vtrue1, vfalse1, if_true0);
  }

  Node* if_false0 = graph()->NewNode(common()->IfFalse(), branch0);
  Node* vfalse0;
  {
    Node* check1 = graph()->NewNode(machine()->Float64Equal(), input, zero);
    Node* branch1 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                     check1, if_false0);

    Node* if_true1 = graph()->NewNode(common()->IfTrue(), branch1);
    Node* vtrue1 = input;

    Node* if_false1 = graph()->NewNode(common()->IfFalse(), branch1);
    Node* vfalse1;
    {
      Node* check2 = graph()->NewNode(machine()->Float64LessThanOrEqual(),
                                      input, minus_two_52);
      Node* branch2 = graph()->NewNode(common()->Branch(BranchHint::kFalse),
                                       check2, if_false1);

      Node* if_true2 = graph()->NewNode(common()->IfTrue(), branch2);
      Node* vtrue2 = input;

      Node* if_false2 = graph()->NewNode(common()->IfFalse(), branch2);
      Node* vfalse2;
      {
        Node* temp1 =
            graph()->NewNode(machine()->Float64Sub(), minus_zero, input);
        Node* temp2 = graph()->NewNode(
            machine()->Float64Sub(),
            graph()->NewNode(machine()->Float64Add(), two_52, temp1), two_52);
        Node* temp3 = graph()->NewNode(
            common()->Select(MachineRepresentation::kFloat64),
            graph()->NewNode(machine()->Float64LessThan(), temp1, temp2),
            graph()->NewNode(machine()->Float64Sub(), temp2, one), temp2);
        vfalse2 = graph()->NewNode(machine()->Float64Sub(), minus_zero, temp3);
      }

      if_false1 = graph()->NewNode(common()->Merge(2), if_true2, if_false2);
      vfalse1 =
          graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                           vtrue2, vfalse2, if_false1);
    }

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

  Node* merge0 = graph()->NewNode(common()->Merge(2), if_true0, if_false0);
  Node* value =
      graph()->NewNode(common()->Phi(MachineRepresentation::kFloat64, 2),
                       vtrue0, vfalse0, merge0);
  return ValueEffectControl(value, effect, merge0);
}

Factory* EffectControlLinearizer::factory() const {
  return isolate()->factory();
}

Isolate* EffectControlLinearizer::isolate() const {
  return jsgraph()->isolate();
}

Operator const* EffectControlLinearizer::ToNumberOperator() {
  if (!to_number_operator_.is_set()) {
    Callable callable = CodeFactory::ToNumber(isolate());
    CallDescriptor::Flags flags = CallDescriptor::kNoFlags;
    CallDescriptor* desc = Linkage::GetStubCallDescriptor(
        isolate(), graph()->zone(), callable.descriptor(), 0, flags,
        Operator::kEliminatable);
    to_number_operator_.set(common()->Call(desc));
  }
  return to_number_operator_.get();
}

}  // namespace compiler
}  // namespace internal
}  // namespace v8