text: // 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
  