// Copyright 2022 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/branch-condition-duplicator.h" #include "src/compiler/backend/instruction-codes.h" #include "src/compiler/graph.h" #include "src/compiler/node-properties.h" #include "src/compiler/opcodes.h" namespace v8 { namespace internal { namespace compiler { namespace { bool IsBranch(Node* node) { return node->opcode() == IrOpcode::kBranch; } bool CanDuplicate(Node* node) { // We only allow duplication of comparisons and "cheap" binary operations // (cheap = not multiplication or division). The idea is that those // instructions set the ZF flag, and thus do not require a "== 0" to be added // before the branch. Duplicating other nodes, on the other hand, makes little // sense, because a "== 0" would need to be inserted in branches anyways. switch (node->opcode()) { #define BRANCH_CASE(op) \ case IrOpcode::k##op: \ break; MACHINE_COMPARE_BINOP_LIST(BRANCH_CASE) case IrOpcode::kInt32Add: case IrOpcode::kInt32Sub: case IrOpcode::kWord32And: case IrOpcode::kWord32Or: case IrOpcode::kInt64Add: case IrOpcode::kInt64Sub: case IrOpcode::kWord64And: case IrOpcode::kWord64Or: case IrOpcode::kWord32Shl: case IrOpcode::kWord32Shr: case IrOpcode::kWord64Shl: case IrOpcode::kWord64Shr: break; default: return false; } // We do not duplicate nodes if all their inputs are used a single time, // because this would keep those inputs alive, thus increasing register // pressure. int all_inputs_have_only_a_single_use = true; for (Node* input : node->inputs()) { if (input->UseCount() > 1) { all_inputs_have_only_a_single_use = false; } } if (all_inputs_have_only_a_single_use) { return false; } return true; } } // namespace Node* BranchConditionDuplicator::DuplicateNode(Node* node) { return graph_->CloneNode(node); } void BranchConditionDuplicator::DuplicateConditionIfNeeded(Node* node) { if (!IsBranch(node)) return; Node* condNode = node->InputAt(0); if (condNode->UseCount() > 1 && CanDuplicate(condNode)) { node->ReplaceInput(0, DuplicateNode(condNode)); } } void BranchConditionDuplicator::Enqueue(Node* node) { if (seen_.Get(node)) return; seen_.Set(node, true); to_visit_.push(node); } void BranchConditionDuplicator::VisitNode(Node* node) { DuplicateConditionIfNeeded(node); for (int i = 0; i < node->op()->ControlInputCount(); i++) { Enqueue(NodeProperties::GetControlInput(node, i)); } } void BranchConditionDuplicator::ProcessGraph() { Enqueue(graph_->end()); while (!to_visit_.empty()) { Node* node = to_visit_.front(); to_visit_.pop(); VisitNode(node); } } BranchConditionDuplicator::BranchConditionDuplicator(Zone* zone, Graph* graph) : graph_(graph), to_visit_(zone), seen_(graph, 2) {} void BranchConditionDuplicator::Reduce() { ProcessGraph(); } } // namespace compiler } // namespace internal } // namespace v8