Commit 3442a5f9 authored by titzer's avatar titzer Committed by Commit bot

[turbofan] First version of loop peeling.

BUG=

Review URL: https://codereview.chromium.org/816053002

Cr-Commit-Position: refs/heads/master@{#26149}
parent 76d62e83
......@@ -529,6 +529,7 @@ source_set("v8_base") {
"src/compiler/linkage.h",
"src/compiler/load-elimination.cc",
"src/compiler/load-elimination.h",
"src/compiler/loop-peeling.cc",
"src/compiler/loop-analysis.cc",
"src/compiler/loop-analysis.h",
"src/compiler/machine-operator-reducer.cc",
......
......@@ -457,10 +457,7 @@ class ControlReducerImpl {
// Gather phis and effect phis to be edited.
ZoneVector<Node*> phis(zone_);
for (Node* const use : node->uses()) {
if (use->opcode() == IrOpcode::kPhi ||
use->opcode() == IrOpcode::kEffectPhi) {
phis.push_back(use);
}
if (IrOpcode::IsPhiOpcode(use->opcode())) phis.push_back(use);
}
if (live == 1) {
......
......@@ -129,7 +129,7 @@ class JSONGraphNodeWriter {
os_ << "{\"id\":" << SafeId(node) << ",\"label\":\"" << Escaped(label, "\"")
<< "\"";
IrOpcode::Value opcode = node->opcode();
if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
if (IrOpcode::IsPhiOpcode(opcode)) {
os_ << ",\"rankInputs\":[0," << NodeProperties::FirstControlIndex(node)
<< "]";
os_ << ",\"rankWithInput\":[" << NodeProperties::FirstControlIndex(node)
......@@ -325,8 +325,7 @@ void GraphVisualizer::PrintNode(Node* node, bool gray) {
static bool IsLikelyBackEdge(Node* from, int index, Node* to) {
if (from->opcode() == IrOpcode::kPhi ||
from->opcode() == IrOpcode::kEffectPhi) {
if (IrOpcode::IsPhiOpcode(from->opcode())) {
Node* control = NodeProperties::GetControlInput(from, 0);
return control != NULL && control->opcode() != IrOpcode::kMerge &&
control != to && index != 0;
......
// Copyright 2013 the V8 project authors. All rights reserved.
// 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.
......@@ -196,8 +196,7 @@ class LoopFinderImpl {
if (node->opcode() == IrOpcode::kLoop) {
// found the loop node first.
loop_num = CreateLoopInfo(node);
} else if (node->opcode() == IrOpcode::kPhi ||
node->opcode() == IrOpcode::kEffectPhi) {
} else if (IrOpcode::IsPhiOpcode(node->opcode())) {
// found a phi first.
Node* merge = node->InputAt(node->InputCount() - 1);
if (merge->opcode() == IrOpcode::kLoop) {
......@@ -235,8 +234,7 @@ class LoopFinderImpl {
// Setup loop mark for phis attached to loop header.
for (Node* use : node->uses()) {
if (use->opcode() == IrOpcode::kPhi ||
use->opcode() == IrOpcode::kEffectPhi) {
if (IrOpcode::IsPhiOpcode(use->opcode())) {
SetBackwardMark(use, loop_num);
loop_tree_->node_to_loop_num_[use->id()] = loop_num;
}
......@@ -291,8 +289,7 @@ class LoopFinderImpl {
bool IsBackedge(Node* use, Edge& edge) {
if (LoopNum(use) <= 0) return false;
if (edge.index() == kAssumedLoopEntryIndex) return false;
if (use->opcode() == IrOpcode::kPhi ||
use->opcode() == IrOpcode::kEffectPhi) {
if (IrOpcode::IsPhiOpcode(use->opcode())) {
return !NodeProperties::IsControlEdge(edge);
}
return true;
......
......@@ -37,6 +37,7 @@ class LoopTree : public ZoneObject {
size_t HeaderSize() const { return body_start_ - header_start_; }
size_t BodySize() const { return body_end_ - body_start_; }
size_t TotalSize() const { return body_end_ - header_start_; }
size_t depth() const { return static_cast<size_t>(depth_); }
private:
friend class LoopTree;
......@@ -94,6 +95,22 @@ class LoopTree : public ZoneObject {
&loop_nodes_[0] + loop->body_end_);
}
// Return a range which can iterate over the nodes of {loop}.
NodeRange LoopNodes(Loop* loop) {
return NodeRange(&loop_nodes_[0] + loop->header_start_,
&loop_nodes_[0] + loop->body_end_);
}
// Return the node that represents the control, i.e. the loop node itself.
Node* GetLoopControl(Loop* loop) {
// TODO(turbofan): make the loop control node always first?
for (Node* node : HeaderNodes(loop)) {
if (node->opcode() == IrOpcode::kLoop) return node;
}
UNREACHABLE();
return NULL;
}
private:
friend class LoopFinderImpl;
......@@ -127,6 +144,7 @@ class LoopFinder {
static LoopTree* BuildLoopTree(Graph* graph, Zone* temp_zone);
};
} // namespace compiler
} // namespace internal
} // namespace v8
......
This diff is collapsed.
// 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.
#ifndef V8_COMPILER_LOOP_PEELING_H_
#define V8_COMPILER_LOOP_PEELING_H_
#include "src/compiler/loop-analysis.h"
namespace v8 {
namespace internal {
namespace compiler {
// Represents the output of peeling a loop, which is basically the mapping
// from the body of the loop to the corresponding nodes in the peeled
// iteration.
class PeeledIteration : public ZoneObject {
public:
// Maps {node} to its corresponding copy in the peeled iteration, if
// the node was part of the body of the loop. Returns {node} otherwise.
Node* map(Node* node);
protected:
PeeledIteration() {}
};
class CommonOperatorBuilder;
// Implements loop peeling.
class LoopPeeler {
public:
static PeeledIteration* Peel(Graph* graph, CommonOperatorBuilder* common,
LoopTree* loop_tree, LoopTree::Loop* loop,
Zone* tmp_zone);
};
} // namespace compiler
} // namespace internal
} // namespace v8
#endif // V8_COMPILER_LOOP_PEELING_H_
......@@ -284,7 +284,7 @@ class Edge FINAL {
explicit Edge(Node::Input* input) : input_(input) { DCHECK_NOT_NULL(input); }
Node::Input* const input_;
Node::Input* input_;
};
......
......@@ -294,6 +294,10 @@ class IrOpcode {
static bool IsConstantOpcode(Value value) {
return kInt32Constant <= value && value <= kHeapConstant;
}
static bool IsPhiOpcode(Value val) {
return val == kPhi || val == kEffectPhi;
}
};
} // namespace compiler
......
......@@ -9,12 +9,10 @@
// TurboFan structures OSR graphs in a way that separates almost all phases of
// compilation from OSR implementation details. This is accomplished with
// special
// control nodes that are added at graph building time. In particular, the graph
// is built in such a way that typing still computes the best types and
// optimizations and lowering work unchanged. All that remains is to deconstruct
// the OSR artifacts before scheduling. The helper class below performs the
// necessary graph rewriting.
// special control nodes that are added at graph building time. In particular,
// the graph is built in such a way that typing still computes the best types
// and optimizations and lowering work unchanged. All that remains is to
// deconstruct the OSR artifacts before scheduling and code generation.
// Graphs built for OSR from the AstGraphBuilder are structured as follows:
// Start
......@@ -36,20 +34,20 @@
// end
// The control structure expresses the relationship that the loop has a separate
// entrypoint which corresponds to entering the loop directly from start.
// entrypoint which corresponds to entering the loop directly from the middle
// of unoptimized code.
// Similarly, the values that come in from unoptimized code are represented with
// {OsrValue} nodes that merge into any phis associated with the OSR loop.
// The nodes {A} and {B} represent values in the "normal" graph that correspond
// to the values of those phis before the loop and on any backedges,
// respectively.
// In the above diagram, nodes {A} and {B} represent values in the "normal"
// graph that correspond to the values of those phis before the loop and on any
// backedges, respectively.
// To deconstruct OSR, we simply replace the uses of the {OsrNormalEntry}
// control
// node with {Dead} and {OsrLoopEntry} with start and run the {ControlReducer}.
// Control reduction propagates the dead control forward, essentially "killing"
// all the code before the OSR loop. The entrypoint to the loop corresponding
// to the "normal" entry path will also be removed, as well as the inputs to
// the loop phis, resulting in the reduced graph:
// control node with {Dead} and {OsrLoopEntry} with start and run the
// {ControlReducer}. Control reduction propagates the dead control forward,
// essentially "killing" all the code before the OSR loop. The entrypoint to the
// loop corresponding to the "normal" entry path will also be removed, as well
// as the inputs to the loop phis, resulting in the reduced graph:
// Start
// Dead |^-------------------------+
......
......@@ -27,6 +27,8 @@
#include "src/compiler/js-typed-lowering.h"
#include "src/compiler/jump-threading.h"
#include "src/compiler/load-elimination.h"
#include "src/compiler/loop-analysis.h"
#include "src/compiler/loop-peeling.h"
#include "src/compiler/machine-operator-reducer.h"
#include "src/compiler/move-optimizer.h"
#include "src/compiler/osr.h"
......@@ -504,6 +506,23 @@ struct LateControlReductionPhase : ControlReductionPhase {
};
struct StressLoopPeelingPhase {
static const char* phase_name() { return "stress loop peeling"; }
void Run(PipelineData* data, Zone* temp_zone) {
SourcePositionTable::Scope pos(data->source_positions(),
SourcePosition::Unknown());
// Peel the first outer loop for testing.
// TODO(titzer): peel all loops? the N'th loop? Innermost loops?
LoopTree* loop_tree = LoopFinder::BuildLoopTree(data->graph(), temp_zone);
if (loop_tree != NULL && loop_tree->outer_loops().size() > 0) {
LoopPeeler::Peel(data->graph(), data->common(), loop_tree,
loop_tree->outer_loops()[0], temp_zone);
}
}
};
struct GenericLoweringPhase {
static const char* phase_name() { return "generic lowering"; }
......@@ -828,6 +847,11 @@ Handle<Code> Pipeline::GenerateCode() {
Run<TypedLoweringPhase>();
RunPrintAndVerify("Lowered typed");
if (FLAG_turbo_stress_loop_peeling) {
Run<StressLoopPeelingPhase>();
RunPrintAndVerify("Loop peeled", true);
}
if (info()->is_osr()) {
Run<OsrDeconstructionPhase>();
RunPrintAndVerify("OSR deconstruction");
......
......@@ -1328,7 +1328,7 @@ class ScheduleLateNodeVisitor {
BasicBlock* GetBlockForUse(Edge edge) {
Node* use = edge.from();
IrOpcode::Value opcode = use->opcode();
if (opcode == IrOpcode::kPhi || opcode == IrOpcode::kEffectPhi) {
if (IrOpcode::IsPhiOpcode(opcode)) {
// If the use is from a coupled (i.e. floating) phi, compute the common
// dominator of its uses. This will not recurse more than one level.
if (scheduler_->GetPlacement(use) == Scheduler::kCoupled) {
......@@ -1438,10 +1438,8 @@ void Scheduler::FuseFloatingControl(BasicBlock* block, Node* node) {
NodeVector propagation_roots(control_flow_builder_->control_);
for (Node* node : control_flow_builder_->control_) {
for (Node* use : node->uses()) {
if (use->opcode() == IrOpcode::kPhi ||
use->opcode() == IrOpcode::kEffectPhi) {
if (IrOpcode::IsPhiOpcode(use->opcode()))
propagation_roots.push_back(use);
}
}
}
if (FLAG_trace_turbo_scheduler) {
......
......@@ -414,6 +414,8 @@ DEFINE_BOOL(turbo_verify_allocation, DEBUG_BOOL,
DEFINE_BOOL(turbo_move_optimization, true, "optimize gap moves in TurboFan")
DEFINE_BOOL(turbo_jt, true, "enable jump threading in TurboFan")
DEFINE_BOOL(turbo_osr, false, "enable OSR in TurboFan")
DEFINE_BOOL(turbo_stress_loop_peeling, false,
"stress loop peeling optimization")
DEFINE_INT(typed_array_max_size_in_heap, 64,
"threshold for in-heap typed array")
......
......@@ -32,6 +32,7 @@ class GraphTest : public TestWithContext, public TestWithZone {
~GraphTest() OVERRIDE;
protected:
Node* start() { return graph()->start(); }
Node* Parameter(int32_t index = 0);
Node* Float32Constant(volatile float value);
Node* Float64Constant(volatile double value);
......
This diff is collapsed.
......@@ -94,11 +94,36 @@ class IsBranchMatcher FINAL : public NodeMatcher {
};
class IsMergeMatcher FINAL : public NodeMatcher {
class IsControl1Matcher FINAL : public NodeMatcher {
public:
IsControl1Matcher(IrOpcode::Value opcode,
const Matcher<Node*>& control_matcher)
: NodeMatcher(opcode), control_matcher_(control_matcher) {}
void DescribeTo(std::ostream* os) const FINAL {
NodeMatcher::DescribeTo(os);
*os << " whose control (";
control_matcher_.DescribeTo(os);
*os << ")";
}
bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
return (NodeMatcher::MatchAndExplain(node, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
"control", control_matcher_, listener));
}
private:
const Matcher<Node*> control_matcher_;
};
class IsControl2Matcher FINAL : public NodeMatcher {
public:
IsMergeMatcher(const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher)
: NodeMatcher(IrOpcode::kMerge),
IsControl2Matcher(IrOpcode::Value opcode,
const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher)
: NodeMatcher(opcode),
control0_matcher_(control0_matcher),
control1_matcher_(control1_matcher) {}
......@@ -125,27 +150,42 @@ class IsMergeMatcher FINAL : public NodeMatcher {
};
class IsControl1Matcher FINAL : public NodeMatcher {
class IsControl3Matcher FINAL : public NodeMatcher {
public:
IsControl1Matcher(IrOpcode::Value opcode,
const Matcher<Node*>& control_matcher)
: NodeMatcher(opcode), control_matcher_(control_matcher) {}
IsControl3Matcher(IrOpcode::Value opcode,
const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher,
const Matcher<Node*>& control2_matcher)
: NodeMatcher(opcode),
control0_matcher_(control0_matcher),
control1_matcher_(control1_matcher),
control2_matcher_(control2_matcher) {}
void DescribeTo(std::ostream* os) const FINAL {
NodeMatcher::DescribeTo(os);
*os << " whose control (";
control_matcher_.DescribeTo(os);
*os << " whose control0 (";
control0_matcher_.DescribeTo(os);
*os << ") and control1 (";
control1_matcher_.DescribeTo(os);
*os << ") and control2 (";
control2_matcher_.DescribeTo(os);
*os << ")";
}
bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
return (NodeMatcher::MatchAndExplain(node, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
"control", control_matcher_, listener));
PrintMatchAndExplain(NodeProperties::GetControlInput(node, 0),
"control0", control0_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node, 1),
"control1", control1_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node, 2),
"control2", control2_matcher_, listener));
}
private:
const Matcher<Node*> control_matcher_;
const Matcher<Node*> control0_matcher_;
const Matcher<Node*> control1_matcher_;
const Matcher<Node*> control2_matcher_;
};
......@@ -180,6 +220,44 @@ class IsFinishMatcher FINAL : public NodeMatcher {
};
class IsReturnMatcher FINAL : public NodeMatcher {
public:
IsReturnMatcher(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher)
: NodeMatcher(IrOpcode::kReturn),
value_matcher_(value_matcher),
effect_matcher_(effect_matcher),
control_matcher_(control_matcher) {}
void DescribeTo(std::ostream* os) const FINAL {
NodeMatcher::DescribeTo(os);
*os << " whose value (";
value_matcher_.DescribeTo(os);
*os << ") and effect (";
effect_matcher_.DescribeTo(os);
*os << ") and control (";
control_matcher_.DescribeTo(os);
*os << ")";
}
bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
return (NodeMatcher::MatchAndExplain(node, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
"value", value_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetEffectInput(node), "effect",
effect_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
"control", control_matcher_, listener));
}
private:
const Matcher<Node*> value_matcher_;
const Matcher<Node*> effect_matcher_;
const Matcher<Node*> control_matcher_;
};
template <typename T>
class IsConstantMatcher FINAL : public NodeMatcher {
public:
......@@ -294,6 +372,58 @@ class IsPhiMatcher FINAL : public NodeMatcher {
};
class IsPhi2Matcher FINAL : public NodeMatcher {
public:
IsPhi2Matcher(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& control_matcher)
: NodeMatcher(IrOpcode::kPhi),
type_matcher_(type_matcher),
value0_matcher_(value0_matcher),
value1_matcher_(value1_matcher),
value2_matcher_(value2_matcher),
control_matcher_(control_matcher) {}
void DescribeTo(std::ostream* os) const FINAL {
NodeMatcher::DescribeTo(os);
*os << " whose type (";
type_matcher_.DescribeTo(os);
*os << "), value0 (";
value0_matcher_.DescribeTo(os);
*os << "), value1 (";
value1_matcher_.DescribeTo(os);
*os << "), value2 (";
value2_matcher_.DescribeTo(os);
*os << ") and control (";
control_matcher_.DescribeTo(os);
*os << ")";
}
bool MatchAndExplain(Node* node, MatchResultListener* listener) const FINAL {
return (NodeMatcher::MatchAndExplain(node, listener) &&
PrintMatchAndExplain(OpParameter<MachineType>(node), "type",
type_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 0),
"value0", value0_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 1),
"value1", value1_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetValueInput(node, 2),
"value2", value2_matcher_, listener) &&
PrintMatchAndExplain(NodeProperties::GetControlInput(node),
"control", control_matcher_, listener));
}
private:
const Matcher<MachineType> type_matcher_;
const Matcher<Node*> value0_matcher_;
const Matcher<Node*> value1_matcher_;
const Matcher<Node*> value2_matcher_;
const Matcher<Node*> control_matcher_;
};
class IsEffectPhiMatcher FINAL : public NodeMatcher {
public:
IsEffectPhiMatcher(const Matcher<Node*>& effect0_matcher,
......@@ -1029,7 +1159,23 @@ Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher) {
return MakeMatcher(new IsMergeMatcher(control0_matcher, control1_matcher));
return MakeMatcher(new IsControl2Matcher(IrOpcode::kMerge, control0_matcher,
control1_matcher));
}
Matcher<Node*> IsLoop(const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher) {
return MakeMatcher(new IsControl2Matcher(IrOpcode::kLoop, control0_matcher,
control1_matcher));
}
Matcher<Node*> IsLoop(const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher,
const Matcher<Node*>& control2_matcher) {
return MakeMatcher(new IsControl3Matcher(IrOpcode::kLoop, control0_matcher,
control1_matcher, control2_matcher));
}
......@@ -1055,6 +1201,14 @@ Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
}
Matcher<Node*> IsReturn(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher) {
return MakeMatcher(
new IsReturnMatcher(value_matcher, effect_matcher, control_matcher));
}
Matcher<Node*> IsExternalConstant(
const Matcher<ExternalReference>& value_matcher) {
return MakeMatcher(new IsConstantMatcher<ExternalReference>(
......@@ -1117,6 +1271,17 @@ Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
}
Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& merge_matcher) {
return MakeMatcher(new IsPhi2Matcher(type_matcher, value0_matcher,
value1_matcher, value2_matcher,
merge_matcher));
}
Matcher<Node*> IsEffectPhi(const Matcher<Node*>& effect0_matcher,
const Matcher<Node*>& effect1_matcher,
const Matcher<Node*>& merge_matcher) {
......
......@@ -35,11 +35,19 @@ Matcher<Node*> IsBranch(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsMerge(const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher);
Matcher<Node*> IsLoop(const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher);
Matcher<Node*> IsLoop(const Matcher<Node*>& control0_matcher,
const Matcher<Node*>& control1_matcher,
const Matcher<Node*>& control2_matcher);
Matcher<Node*> IsIfTrue(const Matcher<Node*>& control_matcher);
Matcher<Node*> IsIfFalse(const Matcher<Node*>& control_matcher);
Matcher<Node*> IsValueEffect(const Matcher<Node*>& value_matcher);
Matcher<Node*> IsFinish(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher);
Matcher<Node*> IsReturn(const Matcher<Node*>& value_matcher,
const Matcher<Node*>& effect_matcher,
const Matcher<Node*>& control_matcher);
Matcher<Node*> IsExternalConstant(
const Matcher<ExternalReference>& value_matcher);
Matcher<Node*> IsHeapConstant(
......@@ -57,6 +65,11 @@ Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& merge_matcher);
Matcher<Node*> IsPhi(const Matcher<MachineType>& type_matcher,
const Matcher<Node*>& value0_matcher,
const Matcher<Node*>& value1_matcher,
const Matcher<Node*>& value2_matcher,
const Matcher<Node*>& merge_matcher);
Matcher<Node*> IsEffectPhi(const Matcher<Node*>& effect0_matcher,
const Matcher<Node*>& effect1_matcher,
const Matcher<Node*>& merge_matcher);
......
......@@ -54,6 +54,7 @@
'compiler/js-operator-unittest.cc',
'compiler/js-typed-lowering-unittest.cc',
'compiler/load-elimination-unittest.cc',
'compiler/loop-peeling-unittest.cc',
'compiler/machine-operator-reducer-unittest.cc',
'compiler/machine-operator-unittest.cc',
'compiler/move-optimizer-unittest.cc',
......
......@@ -481,6 +481,8 @@
'../../src/compiler/load-elimination.h',
'../../src/compiler/loop-analysis.cc',
'../../src/compiler/loop-analysis.h',
'../../src/compiler/loop-peeling.cc',
'../../src/compiler/loop-peeling.h',
'../../src/compiler/machine-operator-reducer.cc',
'../../src/compiler/machine-operator-reducer.h',
'../../src/compiler/machine-operator.cc',
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment