summaryrefslogtreecommitdiff
path: root/deps/v8/src/compiler/branch-condition-duplicator.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/compiler/branch-condition-duplicator.h')
-rw-r--r--deps/v8/src/compiler/branch-condition-duplicator.h85
1 files changed, 85 insertions, 0 deletions
diff --git a/deps/v8/src/compiler/branch-condition-duplicator.h b/deps/v8/src/compiler/branch-condition-duplicator.h
new file mode 100644
index 0000000000..76e97bc291
--- /dev/null
+++ b/deps/v8/src/compiler/branch-condition-duplicator.h
@@ -0,0 +1,85 @@
+// 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.
+
+#ifndef V8_COMPILER_BRANCH_CONDITION_DUPLICATOR_H_
+#define V8_COMPILER_BRANCH_CONDITION_DUPLICATOR_H_
+
+#include "src/base/macros.h"
+#include "src/compiler/node-marker.h"
+#include "src/compiler/node.h"
+#include "src/zone/zone.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+// Forward declare.
+class Graph;
+
+// BranchConditionDuplicator makes sure that the condition nodes of branches are
+// used only once. When it finds a branch node whose condition has multiples
+// uses, this condition is duplicated.
+//
+// Doing this enables the InstructionSelector to generate more efficient code
+// for branches. For instance, consider this code:
+//
+// if (a + b == 0) { /* some code */ }
+// if (a + b == 0) { /* more code */ }
+//
+// Then the generated code will be something like (using registers "ra" for "a"
+// and "rb" for "b", and "rt" a temporary register):
+//
+// add ra, rb ; a + b
+// cmp ra, 0 ; (a + b) == 0
+// sete rt ; rt = (a + b) == 0
+// cmp rt, 0 ; rt == 0
+// jz
+// ...
+// cmp rt, 0 ; rt == 0
+// jz
+//
+// As you can see, TurboFan materialized the == bit into a temporary register.
+// However, since the "add" instruction sets the ZF flag (on x64), it can be
+// used to determine wether the jump should be taken or not. The code we'd like
+// to generate instead if thus:
+//
+// add ra, rb
+// jnz
+// ...
+// add ra, rb
+// jnz
+//
+// However, this requires to generate twice the instruction "add ra, rb". Due to
+// how virtual registers are assigned in TurboFan (there is a map from node ID
+// to virtual registers), both "add" instructions will use the same virtual
+// register as output, which will break SSA.
+//
+// In order to overcome this issue, BranchConditionDuplicator duplicates branch
+// conditions that are used more than once, so that they can be generated right
+// before each branch without worrying about breaking SSA.
+
+class V8_EXPORT_PRIVATE BranchConditionDuplicator final {
+ public:
+ BranchConditionDuplicator(Zone* zone, Graph* graph);
+ ~BranchConditionDuplicator() = default;
+
+ void Reduce();
+
+ Node* DuplicateNode(Node* node);
+ void DuplicateConditionIfNeeded(Node* node);
+ void Enqueue(Node* node);
+ void VisitNode(Node* node);
+ void ProcessGraph();
+
+ private:
+ Graph* const graph_;
+ ZoneQueue<Node*> to_visit_;
+ NodeMarker<bool> seen_;
+};
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
+
+#endif // V8_COMPILER_BRANCH_CONDITION_DUPLICATOR_H_