Initial implementation of an edge-labeled instruction flow graph.

The flow graph is built by walking the AST.  Edges are labeled with
instructions (AST nodes).  Normal nodes have a single predecessor edge and a
single (labeled) successor edge.  Branch nodes are explicit, they have a
single predecessor edge and a pair of (unlabeled) successor edges.  Merge
nodes are explicit, they have a pair of predecessor edges and a single
(unlabeled) successor edge.

There is a distinguished (normal) entry node and a distinguished (special)
exit node with arbitrarily many predecessor edges and no successor edges.

The graph is intended to support graph-based analysis and transformation.

Review URL: http://codereview.chromium.org/660449

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@4051 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 6b47d262
......@@ -117,6 +117,9 @@ typedef ZoneList<Handle<Object> > ZoneObjectList;
class AstNode: public ZoneObject {
public:
static const int kNoNumber = -1;
AstNode() : num_(kNoNumber) {}
virtual ~AstNode() { }
virtual void Accept(AstVisitor* v) = 0;
......@@ -141,6 +144,13 @@ class AstNode: public ZoneObject {
virtual ObjectLiteral* AsObjectLiteral() { return NULL; }
virtual ArrayLiteral* AsArrayLiteral() { return NULL; }
virtual CompareOperation* AsCompareOperation() { return NULL; }
int num() { return num_; }
void set_num(int n) { num_ = n; }
private:
// Support for ast node numbering.
int num_;
};
......@@ -181,11 +191,8 @@ class Expression: public AstNode {
kTestValue
};
static const int kNoLabel = -1;
Expression()
: bitfields_(0),
num_(kNoLabel),
def_(NULL),
defined_vars_(NULL) {}
......@@ -215,11 +222,6 @@ class Expression: public AstNode {
// Static type information for this expression.
StaticType* type() { return &type_; }
int num() { return num_; }
// AST node numbering ordered by evaluation order.
void set_num(int n) { num_ = n; }
// Data flow information.
DefinitionInfo* var_def() { return def_; }
void set_var_def(DefinitionInfo* def) { def_ = def; }
......@@ -261,7 +263,6 @@ class Expression: public AstNode {
uint32_t bitfields_;
StaticType type_;
int num_;
DefinitionInfo* def_;
ZoneList<DefinitionInfo*>* defined_vars_;
......
......@@ -31,6 +31,7 @@
#include "codegen-inl.h"
#include "compilation-cache.h"
#include "compiler.h"
#include "data-flow.h"
#include "debug.h"
#include "fast-codegen.h"
#include "full-codegen.h"
......@@ -79,6 +80,17 @@ static Handle<Code> MakeCode(Handle<Context> context, CompilationInfo* info) {
return Handle<Code>::null();
}
if (FLAG_use_flow_graph) {
FlowGraphBuilder builder;
builder.Build(function);
#ifdef DEBUG
if (FLAG_print_graph_text) {
builder.graph()->PrintText(builder.postorder());
}
#endif
}
// Generate code and return it. Code generator selection is governed by
// which backends are enabled and whether the function is considered
// run-once code or not:
......@@ -452,6 +464,17 @@ Handle<JSFunction> Compiler::BuildBoilerplate(FunctionLiteral* literal,
return Handle<JSFunction>::null();
}
if (FLAG_use_flow_graph) {
FlowGraphBuilder builder;
builder.Build(literal);
#ifdef DEBUG
if (FLAG_print_graph_text) {
builder.graph()->PrintText(builder.postorder());
}
#endif
}
// Generate code and return it. The way that the compilation mode
// is controlled by the command-line flags is described in
// the static helper function MakeCode.
......
This diff is collapsed.
......@@ -95,6 +95,299 @@ class BitVector {
};
// Forward declarations of Node types.
class Node;
class BranchNode;
class JoinNode;
// Flow graphs have a single entry and single exit. The empty flowgraph is
// represented by both entry and exit being NULL.
class FlowGraph BASE_EMBEDDED {
public:
FlowGraph() : entry_(NULL), exit_(NULL) {}
static FlowGraph Empty() { return FlowGraph(); }
bool is_empty() const { return entry_ == NULL; }
Node* entry() const { return entry_; }
Node* exit() const { return exit_; }
// Add a single instruction to the end of this flowgraph.
void AppendInstruction(AstNode* instruction);
// Add a single node to the end of this flow graph.
void AppendNode(Node* node);
// Add a flow graph fragment to the end of this one.
void AppendGraph(FlowGraph* graph);
// Concatenate an if-then-else flow-graph to this one. Control is split
// and merged, so the graph remains single-entry, single-exit.
void Split(BranchNode* branch,
FlowGraph* left,
FlowGraph* right,
JoinNode* merge);
// Concatenate a forward loop (e.g., while or for loop) flow-graph to this
// one. Control is split by the condition and merged back from the back
// edge at end of the body to the beginning of the condition. The single
// (free) exit of the result graph is the right (false) arm of the branch
// node.
void Loop(JoinNode* merge,
FlowGraph* condition,
BranchNode* branch,
FlowGraph* body);
#ifdef DEBUG
void PrintText(ZoneList<Node*>* postorder);
#endif
private:
Node* entry_;
Node* exit_;
};
// Flow-graph nodes.
class Node: public ZoneObject {
public:
Node() : number_(-1), mark_(false) {}
virtual ~Node() {}
virtual bool IsBlockNode() { return false; }
virtual bool IsJoinNode() { return false; }
virtual void AddPredecessor(Node* predecessor) = 0;
virtual void AddSuccessor(Node* successor) = 0;
bool IsMarkedWith(bool mark) { return mark_ == mark; }
void MarkWith(bool mark) { mark_ = mark; }
// Perform a depth first search and record preorder and postorder
// traversal orders.
virtual void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder) = 0;
int number() { return number_; }
void set_number(int number) { number_ = number; }
#ifdef DEBUG
virtual void AssignNumbers();
virtual void PrintText() = 0;
#endif
private:
int number_;
bool mark_;
DISALLOW_COPY_AND_ASSIGN(Node);
};
// An entry node has no predecessors and a single successor.
class EntryNode: public Node {
public:
EntryNode() : successor_(NULL) {}
void AddPredecessor(Node* predecessor) { UNREACHABLE(); }
void AddSuccessor(Node* successor) {
ASSERT(successor_ == NULL && successor != NULL);
successor_ = successor;
}
void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
#ifdef DEBUG
void PrintText();
#endif
private:
Node* successor_;
DISALLOW_COPY_AND_ASSIGN(EntryNode);
};
// An exit node has a arbitrarily many predecessors and no successors.
class ExitNode: public Node {
public:
ExitNode() : predecessors_(4) {}
void AddPredecessor(Node* predecessor) {
ASSERT(predecessor != NULL);
predecessors_.Add(predecessor);
}
void AddSuccessor(Node* successor) { /* Do nothing. */ }
void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
#ifdef DEBUG
void PrintText();
#endif
private:
ZoneList<Node*> predecessors_;
DISALLOW_COPY_AND_ASSIGN(ExitNode);
};
// Block nodes have a single successor and predecessor and a list of
// instructions.
class BlockNode: public Node {
public:
BlockNode() : predecessor_(NULL), successor_(NULL), instructions_(4) {}
static BlockNode* cast(Node* node) {
ASSERT(node->IsBlockNode());
return reinterpret_cast<BlockNode*>(node);
}
bool IsBlockNode() { return true; }
void AddPredecessor(Node* predecessor) {
ASSERT(predecessor_ == NULL && predecessor != NULL);
predecessor_ = predecessor;
}
void AddSuccessor(Node* successor) {
ASSERT(successor_ == NULL && successor != NULL);
successor_ = successor;
}
void AddInstruction(AstNode* instruction) {
instructions_.Add(instruction);
}
void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
#ifdef DEBUG
void AssignNumbers();
void PrintText();
#endif
private:
Node* predecessor_;
Node* successor_;
ZoneList<AstNode*> instructions_;
DISALLOW_COPY_AND_ASSIGN(BlockNode);
};
// Branch nodes have a single predecessor and a pair of successors.
class BranchNode: public Node {
public:
BranchNode() : predecessor_(NULL), successor0_(NULL), successor1_(NULL) {}
void AddPredecessor(Node* predecessor) {
ASSERT(predecessor_ == NULL && predecessor != NULL);
predecessor_ = predecessor;
}
void AddSuccessor(Node* successor) {
ASSERT(successor1_ == NULL && successor != NULL);
if (successor0_ == NULL) {
successor0_ = successor;
} else {
successor1_ = successor;
}
}
void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
#ifdef DEBUG
void PrintText();
#endif
private:
Node* predecessor_;
Node* successor0_;
Node* successor1_;
DISALLOW_COPY_AND_ASSIGN(BranchNode);
};
// Join nodes have arbitrarily many predecessors and a single successor.
class JoinNode: public Node {
public:
JoinNode() : predecessors_(2), successor_(NULL) {}
static JoinNode* cast(Node* node) {
ASSERT(node->IsJoinNode());
return reinterpret_cast<JoinNode*>(node);
}
bool IsJoinNode() { return true; }
void AddPredecessor(Node* predecessor) {
ASSERT(predecessor != NULL);
predecessors_.Add(predecessor);
}
void AddSuccessor(Node* successor) {
ASSERT(successor_ == NULL && successor != NULL);
successor_ = successor;
}
void Traverse(bool mark,
ZoneList<Node*>* preorder,
ZoneList<Node*>* postorder);
#ifdef DEBUG
void PrintText();
#endif
private:
ZoneList<Node*> predecessors_;
Node* successor_;
DISALLOW_COPY_AND_ASSIGN(JoinNode);
};
// Construct a flow graph from a function literal. Build pre- and postorder
// traversal orders as a byproduct.
class FlowGraphBuilder: public AstVisitor {
public:
FlowGraphBuilder() : global_exit_(NULL), preorder_(4), postorder_(4) {}
void Build(FunctionLiteral* lit);
FlowGraph* graph() { return &graph_; }
ZoneList<Node*>* postorder() { return &postorder_; }
private:
ExitNode* global_exit() { return global_exit_; }
// AST node visit functions.
#define DECLARE_VISIT(type) virtual void Visit##type(type* node);
AST_NODE_LIST(DECLARE_VISIT)
#undef DECLARE_VISIT
FlowGraph graph_;
ExitNode* global_exit_;
ZoneList<Node*> preorder_;
ZoneList<Node*> postorder_;
DISALLOW_COPY_AND_ASSIGN(FlowGraphBuilder);
};
// This class is used to number all expressions in the AST according to
// their evaluation order (post-order left-to-right traversal).
class AstLabeler: public AstVisitor {
......
......@@ -153,6 +153,7 @@ DEFINE_bool(always_fast_compiler, false,
"try to use the speculative optimizing backend for all code")
DEFINE_bool(trace_bailout, false,
"print reasons for falling back to using the classic V8 backend")
DEFINE_bool(use_flow_graph, false, "perform flow-graph based optimizations")
// compilation-cache.cc
DEFINE_bool(compilation_cache, true, "enable compilation cache")
......@@ -305,6 +306,8 @@ DEFINE_string(stop_at, "", "function name where to insert a breakpoint")
DEFINE_bool(print_builtin_scopes, false, "print scopes for builtins")
DEFINE_bool(print_scopes, false, "print scopes")
DEFINE_bool(print_ir, false, "print the AST as seen by the backend")
DEFINE_bool(print_graph_text, false,
"print a text representation of the flow graph")
// contexts.cc
DEFINE_bool(trace_contexts, false, "trace contexts operations")
......
......@@ -604,7 +604,7 @@ class IndentedScope BASE_EMBEDDED {
ast_printer_->Print(StaticType::Type2String(expr->type()));
printed_first = true;
}
if (expr->num() != Expression::kNoLabel) {
if (expr->num() != AstNode::kNoNumber) {
ast_printer_->Print(printed_first ? ", num = " : " (num = ");
ast_printer_->Print("%d", expr->num());
printed_first = true;
......@@ -679,7 +679,7 @@ void AstPrinter::PrintLiteralWithModeIndented(const char* info,
pos += OS::SNPrintF(buf + pos, ", type = %s",
StaticType::Type2String(type));
}
if (num != Expression::kNoLabel) {
if (num != AstNode::kNoNumber) {
pos += OS::SNPrintF(buf + pos, ", num = %d", num);
}
OS::SNPrintF(buf + pos, ")");
......@@ -740,7 +740,7 @@ void AstPrinter::PrintParameters(Scope* scope) {
PrintLiteralWithModeIndented("VAR", scope->parameter(i),
scope->parameter(i)->name(),
scope->parameter(i)->type(),
Expression::kNoLabel);
AstNode::kNoNumber);
}
}
}
......@@ -786,7 +786,7 @@ void AstPrinter::VisitDeclaration(Declaration* node) {
node->proxy()->AsVariable(),
node->proxy()->name(),
node->proxy()->AsVariable()->type(),
Expression::kNoLabel);
AstNode::kNoNumber);
} else {
// function declarations
PrintIndented("FUNCTION ");
......
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