Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(86)

Unified Diff: src/compiler/control-reducer.cc

Issue 1196623002: [ubsan] Fix HeapObjectMatcher to avoid invalid casts. (Closed) Base URL: https://chromium.googlesource.com/v8/v8.git@master
Patch Set: REBASE Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/compiler/common-operator-reducer.cc ('k') | src/compiler/js-builtin-reducer.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/compiler/control-reducer.cc
diff --git a/src/compiler/control-reducer.cc b/src/compiler/control-reducer.cc
new file mode 100644
index 0000000000000000000000000000000000000000..47ea66c2df01b3a1d004fa7df0648b5dde011064
--- /dev/null
+++ b/src/compiler/control-reducer.cc
@@ -0,0 +1,327 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/common-operator-reducer.h"
+#include "src/compiler/control-reducer.h"
conradw 2015/06/19 21:38:53 I think this file was reintroduced by mistake with
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-reducer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-marker.h"
+#include "src/compiler/node-matchers.h"
+#include "src/compiler/node-properties.h"
+#include "src/zone-containers.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+#define TRACE(...) \
+ do { \
+ if (FLAG_trace_turbo_reduction) PrintF(__VA_ARGS__); \
+ } while (false)
+
+enum Decision { kFalse, kUnknown, kTrue };
+
+class ControlReducerImpl final : public AdvancedReducer {
+ public:
+ Zone* zone_;
+ JSGraph* jsgraph_;
+ int max_phis_for_select_;
+
+ ControlReducerImpl(Editor* editor, Zone* zone, JSGraph* jsgraph)
+ : AdvancedReducer(editor),
+ zone_(zone),
+ jsgraph_(jsgraph),
+ max_phis_for_select_(0) {}
+
+ Graph* graph() { return jsgraph_->graph(); }
+ CommonOperatorBuilder* common() { return jsgraph_->common(); }
+ Node* dead() { return jsgraph_->DeadControl(); }
+
+ //===========================================================================
+ // Reducer implementation: perform reductions on a node.
+ //===========================================================================
+ Reduction Reduce(Node* node) override {
+ if (node->op()->ControlInputCount() == 1 ||
+ node->opcode() == IrOpcode::kLoop) {
+ // If a node has only one control input and it is dead, replace with dead.
+ Node* control = NodeProperties::GetControlInput(node);
+ if (control->opcode() == IrOpcode::kDeadControl) {
+ TRACE("ControlDead: #%d:%s\n", node->id(), node->op()->mnemonic());
+ return Replace(control);
+ }
+ }
+
+ Node* result = node;
+ // Reduce branches, phis, and merges.
+ switch (node->opcode()) {
+ case IrOpcode::kBranch:
+ result = ReduceBranch(node);
+ break;
+ case IrOpcode::kIfTrue:
+ result = ReduceIfProjection(node, kTrue);
+ break;
+ case IrOpcode::kIfFalse:
+ result = ReduceIfProjection(node, kFalse);
+ break;
+ case IrOpcode::kLoop: // fallthrough
+ case IrOpcode::kMerge:
+ result = ReduceMerge(node);
+ break;
+ case IrOpcode::kEnd:
+ result = ReduceEnd(node);
+ break;
+ default:
+ break;
+ }
+
+ return result == node ? NoChange() : Replace(result);
+ }
+
+ // Try to statically fold a condition.
+ Decision DecideCondition(Node* cond) {
+ switch (cond->opcode()) {
+ case IrOpcode::kInt32Constant:
+ return Int32Matcher(cond).Is(0) ? kFalse : kTrue;
+ case IrOpcode::kInt64Constant:
+ return Int64Matcher(cond).Is(0) ? kFalse : kTrue;
+ case IrOpcode::kHeapConstant: {
+ Handle<HeapObject> object = HeapObjectMatcher(cond).Value().handle();
+ return object->BooleanValue() ? kTrue : kFalse;
+ }
+ default:
+ break;
+ }
+ return kUnknown;
+ }
+
+ // Reduce branches.
+ Node* ReduceBranch(Node* branch) {
+ if (DecideCondition(branch->InputAt(0)) != kUnknown) {
+ for (Node* use : branch->uses()) Revisit(use);
+ }
+ return branch;
+ }
+
+ // Reduce end by trimming away dead inputs.
+ Node* ReduceEnd(Node* node) {
+ // Count the number of live inputs.
+ int live = 0;
+ for (int index = 0; index < node->InputCount(); ++index) {
+ // Skip dead inputs.
+ if (node->InputAt(index)->opcode() == IrOpcode::kDeadControl) continue;
+ // Compact live inputs.
+ if (index != live) node->ReplaceInput(live, node->InputAt(index));
+ ++live;
+ }
+
+ TRACE("ReduceEnd: #%d:%s (%d of %d live)\n", node->id(),
+ node->op()->mnemonic(), live, node->InputCount());
+
+ if (live == 0) return dead(); // No remaining inputs.
+
+ if (live < node->InputCount()) {
+ node->set_op(common()->End(live));
+ node->TrimInputCount(live);
+ }
+
+ return node;
+ }
+
+ // Reduce merges by trimming away dead inputs from the merge and phis.
+ Node* ReduceMerge(Node* node) {
+ // Count the number of live inputs.
+ int live = 0;
+ int index = 0;
+ int live_index = 0;
+ for (Node* const input : node->inputs()) {
+ if (input->opcode() != IrOpcode::kDeadControl) {
+ live++;
+ live_index = index;
+ }
+ index++;
+ }
+
+ TRACE("ReduceMerge: #%d:%s (%d of %d live)\n", node->id(),
+ node->op()->mnemonic(), live, index);
+
+ if (live == 0) return dead(); // no remaining inputs.
+
+ // Gather terminates, phis and effect phis to be edited.
+ NodeVector phis(zone_);
+ Node* terminate = nullptr;
+ for (Node* const use : node->uses()) {
+ if (NodeProperties::IsPhi(use)) {
+ phis.push_back(use);
+ } else if (use->opcode() == IrOpcode::kTerminate) {
+ DCHECK_NULL(terminate);
+ terminate = use;
+ }
+ }
+
+ if (live == 1) {
+ // All phis are redundant. Replace them with their live input.
+ for (Node* const phi : phis) {
+ Replace(phi, phi->InputAt(live_index));
+ }
+ // The terminate is not needed anymore.
+ if (terminate) Replace(terminate, dead());
+ // The merge itself is redundant.
+ return node->InputAt(live_index);
+ }
+
+ DCHECK_LE(2, live);
+
+ if (live < node->InputCount()) {
+ // Edit phis in place, removing dead inputs and revisiting them.
+ for (Node* const phi : phis) {
+ TRACE(" PhiInMerge: #%d:%s (%d live)\n", phi->id(),
+ phi->op()->mnemonic(), live);
+ RemoveDeadInputs(node, phi);
+ Revisit(phi);
+ }
+ // Edit the merge in place, removing dead inputs.
+ RemoveDeadInputs(node, node);
+ }
+
+ DCHECK_EQ(live, node->InputCount());
+
+ // Try to remove dead diamonds or introduce selects.
+ if (live == 2 && CheckPhisForSelect(phis)) {
+ DiamondMatcher matcher(node);
+ if (matcher.Matched() && matcher.IfProjectionsAreOwned()) {
+ // Dead diamond, i.e. neither the IfTrue nor the IfFalse nodes
+ // have uses except for the Merge. Remove the branch if there
+ // are no phis or replace phis with selects.
+ Node* control = NodeProperties::GetControlInput(matcher.Branch());
+ if (phis.size() == 0) {
+ // No phis. Remove the branch altogether.
+ TRACE(" DeadDiamond: #%d:Branch #%d:IfTrue #%d:IfFalse\n",
+ matcher.Branch()->id(), matcher.IfTrue()->id(),
+ matcher.IfFalse()->id());
+ return control;
+ } else {
+ // A small number of phis. Replace with selects.
+ Node* cond = matcher.Branch()->InputAt(0);
+ for (Node* phi : phis) {
+ Node* select = graph()->NewNode(
+ common()->Select(OpParameter<MachineType>(phi),
+ BranchHintOf(matcher.Branch()->op())),
+ cond, matcher.TrueInputOf(phi), matcher.FalseInputOf(phi));
+ TRACE(" MatchSelect: #%d:Branch #%d:IfTrue #%d:IfFalse -> #%d\n",
+ matcher.Branch()->id(), matcher.IfTrue()->id(),
+ matcher.IfFalse()->id(), select->id());
+ Replace(phi, select);
+ }
+ return control;
+ }
+ }
+ }
+
+ return node;
+ }
+
+ bool CheckPhisForSelect(const NodeVector& phis) {
+ if (phis.size() > static_cast<size_t>(max_phis_for_select_)) return false;
+ for (Node* phi : phis) {
+ if (phi->opcode() != IrOpcode::kPhi) return false; // no EffectPhis.
+ }
+ return true;
+ }
+
+ // Reduce if projections if the branch has a constant input.
+ Node* ReduceIfProjection(Node* node, Decision decision) {
+ Node* branch = node->InputAt(0);
+ DCHECK_EQ(IrOpcode::kBranch, branch->opcode());
+ Decision result = DecideCondition(branch->InputAt(0));
+ if (result == decision) {
+ // Fold a branch by replacing IfTrue/IfFalse with the branch control.
+ TRACE(" BranchReduce: #%d:%s => #%d:%s\n", branch->id(),
+ branch->op()->mnemonic(), node->id(), node->op()->mnemonic());
+ return branch->InputAt(1);
+ }
+ return result == kUnknown ? node : dead();
+ }
+
+ // Remove inputs to {node} corresponding to the dead inputs to {merge}
+ // and compact the remaining inputs, updating the operator.
+ void RemoveDeadInputs(Node* merge, Node* node) {
+ int live = 0;
+ for (int i = 0; i < merge->InputCount(); i++) {
+ // skip dead inputs.
+ if (merge->InputAt(i)->opcode() == IrOpcode::kDeadControl) continue;
+ // compact live inputs.
+ if (live != i) node->ReplaceInput(live, node->InputAt(i));
+ live++;
+ }
+ // compact remaining inputs.
+ int total = live;
+ for (int i = merge->InputCount(); i < node->InputCount(); i++) {
+ if (total != i) node->ReplaceInput(total, node->InputAt(i));
+ total++;
+ }
+ DCHECK_EQ(total, live + node->InputCount() - merge->InputCount());
+ DCHECK_NE(total, node->InputCount());
+ node->TrimInputCount(total);
+ node->set_op(common()->ResizeMergeOrPhi(node->op(), live));
+ }
+};
+
+
+void ControlReducer::ReduceGraph(Zone* zone, JSGraph* jsgraph,
+ int max_phis_for_select) {
+ GraphReducer graph_reducer(zone, jsgraph->graph());
+ CommonOperatorReducer common(&graph_reducer, jsgraph->graph(),
+ jsgraph->common(), jsgraph->machine());
+ ControlReducerImpl impl(&graph_reducer, zone, jsgraph);
+ impl.max_phis_for_select_ = max_phis_for_select;
+ graph_reducer.AddReducer(&impl);
+ graph_reducer.AddReducer(&common);
+ graph_reducer.ReduceGraph();
+}
+
+
+namespace {
+
+class DummyEditor final : public AdvancedReducer::Editor {
+ public:
+ void Replace(Node* node, Node* replacement) final {
+ node->ReplaceUses(replacement);
+ }
+ void Revisit(Node* node) final {}
+ void ReplaceWithValue(Node* node, Node* value, Node* effect,
+ Node* control) final {}
+};
+
+} // namespace
+
+
+Node* ControlReducer::ReduceMerge(JSGraph* jsgraph, Node* node,
+ int max_phis_for_select) {
+ Zone zone;
+ DummyEditor editor;
+ ControlReducerImpl impl(&editor, &zone, jsgraph);
+ impl.max_phis_for_select_ = max_phis_for_select;
+ return impl.ReduceMerge(node);
+}
+
+
+Node* ControlReducer::ReduceIfNodeForTesting(JSGraph* jsgraph, Node* node) {
+ Zone zone;
+ DummyEditor editor;
+ ControlReducerImpl impl(&editor, &zone, jsgraph);
+ switch (node->opcode()) {
+ case IrOpcode::kIfTrue:
+ return impl.ReduceIfProjection(node, kTrue);
+ case IrOpcode::kIfFalse:
+ return impl.ReduceIfProjection(node, kFalse);
+ default:
+ return node;
+ }
+}
+
+} // namespace compiler
+} // namespace internal
+} // namespace v8
« no previous file with comments | « src/compiler/common-operator-reducer.cc ('k') | src/compiler/js-builtin-reducer.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698