Commit 2c418e1f by Ian Lance Taylor

escape: Add escape graph nodes.

    
    Introduces the nodes used to model connectivity in the escape graph
    and related state: a node's escape level and an encoding that will
    be added to import and export data.
    
    Reviewed-on: https://go-review.googlesource.com/18268

From-SVN: r235988
parent 5e5b938a
33f1d1d151721305ba37f3e23652d21310f868af 7f5a9fde801eb755a5252fd4ff588b0a47475bd3
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -4,9 +4,263 @@ ...@@ -4,9 +4,263 @@
// Use of this source code is governed by a BSD-style // Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file. // license that can be found in the LICENSE file.
#include <limits>
#include <stack>
#include "gogo.h" #include "gogo.h"
#include "types.h"
#include "expressions.h"
#include "statements.h"
#include "escape.h" #include "escape.h"
// class Node.
// Return the node's type, if it makes sense for it to have one.
Type*
Node::type() const
{
if (this->object() != NULL
&& this->object()->is_variable())
return this->object()->var_value()->type();
else if (this->object() != NULL
&& this->object()->is_function())
return this->object()->func_value()->type();
else if (this->expr() != NULL)
return this->expr()->type();
else
return NULL;
}
// A helper for reporting; return this node's location.
Location
Node::location() const
{
if (this->object() != NULL && !this->object()->is_sink())
return this->object()->location();
else if (this->expr() != NULL)
return this->expr()->location();
else if (this->statement() != NULL)
return this->statement()->location();
else
return Linemap::unknown_location();
}
// Return this node's state, creating it if has not been initialized.
Node::Escape_state*
Node::state(Escape_context* context, Named_object* fn)
{
if (this->state_ == NULL)
{
if (this->expr() != NULL && this->expr()->var_expression() != NULL)
{
// Tie state of variable references to underlying variables.
Named_object* var_no = this->expr()->var_expression()->named_object();
Node* var_node = Node::make_node(var_no);
this->state_ = var_node->state(context, fn);
}
else
{
this->state_ = new Node::Escape_state;
if (fn == NULL)
fn = context->current_function();
this->state_->fn = fn;
}
}
go_assert(this->state_ != NULL);
return this->state_;
}
void
Node::set_encoding(int enc)
{
this->encoding_ = enc;
if (this->expr() != NULL
&& this->expr()->var_expression() != NULL)
{
// Set underlying object as well.
Named_object* no = this->expr()->var_expression()->named_object();
Node::make_node(no)->set_encoding(enc);
}
}
bool
Node::is_sink() const
{
if (this->object() != NULL
&& this->object()->is_sink())
return true;
else if (this->expr() != NULL
&& this->expr()->is_sink_expression())
return true;
return false;
}
std::map<Named_object*, Node*> Node::objects;
std::map<Expression*, Node*> Node::expressions;
std::map<Statement*, Node*> Node::statements;
// Make a object node or return a cached node for this object.
Node*
Node::make_node(Named_object* no)
{
if (Node::objects.find(no) != Node::objects.end())
return Node::objects[no];
Node* n = new Node(no);
std::pair<Named_object*, Node*> val(no, n);
Node::objects.insert(val);
return n;
}
// Make an expression node or return a cached node for this expression.
Node*
Node::make_node(Expression* e)
{
if (Node::expressions.find(e) != Node::expressions.end())
return Node::expressions[e];
Node* n = new Node(e);
std::pair<Expression*, Node*> val(e, n);
Node::expressions.insert(val);
return n;
}
// Make a statement node or return a cached node for this statement.
Node*
Node::make_node(Statement* s)
{
if (Node::statements.find(s) != Node::statements.end())
return Node::statements[s];
Node* n = new Node(s);
std::pair<Statement*, Node*> val(s, n);
Node::statements.insert(val);
return n;
}
// Returns the maximum of an exisiting escape value
// (and its additional parameter flow flags) and a new escape type.
int
Node::max_encoding(int e, int etype)
{
if ((e & ESCAPE_MASK) >= etype)
return e;
if (etype == Node::ESCAPE_NONE || etype == Node::ESCAPE_RETURN)
return (e & ~ESCAPE_MASK) | etype;
return etype;
}
// Return a modified encoding for an input parameter that flows into an
// output parameter.
// Class Escape_context.
Escape_context::Escape_context(Gogo* gogo, bool recursive)
: gogo_(gogo), current_function_(NULL), recursive_(recursive),
sink_(Node::make_node(Named_object::make_sink())), loop_depth_(0)
{
// The sink always escapes to heap and strictly lives outside of the
// current function i.e. loop_depth == -1.
this->sink_->set_encoding(Node::ESCAPE_HEAP);
Node::Escape_state* state = this->sink_->state(this, NULL);
state->loop_depth = -1;
}
// Initialize the dummy return values for this Node N using the results
// in FNTYPE.
void
Escape_context::init_retvals(Node* n, Function_type* fntype)
{
if (fntype == NULL || fntype->results() == NULL)
return;
Node::Escape_state* state = n->state(this, NULL);
Location loc = n->location();
int i = 0;
char buf[50];
for (Typed_identifier_list::const_iterator p = fntype->results()->begin();
p != fntype->results()->end();
++p, ++i)
{
snprintf(buf, sizeof buf, ".out%d", i);
Variable* dummy_var = new Variable(p->type(), NULL, false, false,
false, loc);
dummy_var->set_is_used();
Named_object* dummy_no =
Named_object::make_variable(buf, NULL, dummy_var);
Node* dummy_node = Node::make_node(dummy_no);
// Initialize the state of the dummy output node.
dummy_node->state(this, NULL);
// Add dummy node to the retvals of n.
state->retvals.push_back(dummy_node);
}
}
// Apply an indirection to N and return the result.
// This really only works if N is an expression node; it essentially becomes
// Node::make_node(n->expr()->deref()). We need the escape context to set the
// correct loop depth, however.
Node*
Escape_context::add_dereference(Node* n)
{
// Just return the original node if we can't add an indirection.
if (n->object() != NULL || n->statement() != NULL)
return n;
Node* ind = Node::make_node(n->expr()->deref());
// Initialize the state if this node doesn't already exist.
ind->state(this, NULL);
return ind;
}
void
Escape_context::track(Node* n)
{
n->set_encoding(Node::ESCAPE_NONE);
// Initialize this node's state if it hasn't been encountered
// before.
Node::Escape_state* state = n->state(this, NULL);
state->loop_depth = this->loop_depth_;
this->noesc_.push_back(n);
}
// Return the string representation of an escapement encoding.
std::string
Escape_note::make_tag(int encoding)
{
char buf[50];
snprintf(buf, sizeof buf, "esc:0x%x", encoding);
return buf;
}
// Return the escapement encoding for a string tag.
int
Escape_note::parse_tag(std::string* tag)
{
if (tag == NULL || tag->substr(0, 4) != "esc:")
return Node::ESCAPE_UNKNOWN;
int encoding = (int)strtol(tag->substr(4).c_str(), NULL, 0);
if (encoding == 0)
return Node::ESCAPE_UNKNOWN;
return encoding;
}
// Analyze the program flow for escape information. // Analyze the program flow for escape information.
void void
...@@ -21,7 +275,7 @@ Gogo::analyze_escape() ...@@ -21,7 +275,7 @@ Gogo::analyze_escape()
++p) ++p)
{ {
std::vector<Named_object*> stack = p->first; std::vector<Named_object*> stack = p->first;
Escape_context* context = new Escape_context(p->second); Escape_context* context = new Escape_context(this, p->second);
// Analyze the flow of each function; build the connection graph. // Analyze the flow of each function; build the connection graph.
// This is the assign phase. // This is the assign phase.
...@@ -33,13 +287,12 @@ Gogo::analyze_escape() ...@@ -33,13 +287,12 @@ Gogo::analyze_escape()
this->assign_connectivity(context, *fn); this->assign_connectivity(context, *fn);
} }
// TODO(cmang): Introduce escape node.
// Propagate levels across each dst. This is the flood phase. // Propagate levels across each dst. This is the flood phase.
// std::vector<Node*> dsts = context->dsts(); std::set<Node*> dsts = context->dsts();
// for (std::vector<Node*>::iterator n = dsts.begin(); for (std::set<Node*>::iterator n = dsts.begin();
// n != dsts.end(); n != dsts.end();
// ++n) ++n)
// this->propagate_escape(context, *n); this->propagate_escape(context, *n);
// Tag each exported function's parameters with escape information. // Tag each exported function's parameters with escape information.
for (std::vector<Named_object*>::iterator fn = stack.begin(); for (std::vector<Named_object*>::iterator fn = stack.begin();
...@@ -71,11 +324,10 @@ Gogo::assign_connectivity(Escape_context*, Named_object*) ...@@ -71,11 +324,10 @@ Gogo::assign_connectivity(Escape_context*, Named_object*)
// TODO(cmang): Analyze the current function's body. // TODO(cmang): Analyze the current function's body.
} }
// Propagate escape information across the nodes modeled in this Analysis_set, // Propagate escape information across the nodes modeled in this Analysis_set.
// TODO(cmang): Introduce escape analysis node.
void void
Gogo::propagate_escape(Escape_context*) Gogo::propagate_escape(Escape_context*, Node*)
{ {
// TODO(cmang): Do a breadth-first traversal of a node's upstream, adjusting // TODO(cmang): Do a breadth-first traversal of a node's upstream, adjusting
// the Level appropriately. // the Level appropriately.
......
...@@ -51,6 +51,7 @@ class Bvariable; ...@@ -51,6 +51,7 @@ class Bvariable;
class Blabel; class Blabel;
class Bfunction; class Bfunction;
class Escape_context; class Escape_context;
class Node;
// This file declares the basic classes used to hold the internal // This file declares the basic classes used to hold the internal
// representation of Go which is built by the parser. // representation of Go which is built by the parser.
...@@ -570,7 +571,7 @@ class Gogo ...@@ -570,7 +571,7 @@ class Gogo
// Traverse the objects in the connecitivty graph from the sink, adjusting the // Traverse the objects in the connecitivty graph from the sink, adjusting the
// escape levels of each object. // escape levels of each object.
void void
propagate_escape(Escape_context*); propagate_escape(Escape_context*, Node*);
// Add notes about the escape level of a function's input and output // Add notes about the escape level of a function's input and output
// parameters for exporting and importing top level functions. // parameters for exporting and importing top level functions.
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define GO_TYPES_H #define GO_TYPES_H
#include "go-linemap.h" #include "go-linemap.h"
#include "escape.h"
class Gogo; class Gogo;
class Package; class Package;
...@@ -1324,7 +1325,7 @@ class Typed_identifier ...@@ -1324,7 +1325,7 @@ class Typed_identifier
public: public:
Typed_identifier(const std::string& name, Type* type, Typed_identifier(const std::string& name, Type* type,
Location location) Location location)
: name_(name), type_(type), location_(location) : name_(name), type_(type), location_(location), note_(NULL)
{ } { }
// Get the name. // Get the name.
...@@ -1351,6 +1352,16 @@ class Typed_identifier ...@@ -1351,6 +1352,16 @@ class Typed_identifier
this->type_ = type; this->type_ = type;
} }
// Get the escape note.
std::string*
note() const
{ return this->note_; }
// Set the escape note.
void
set_note(const std::string& note)
{ this->note_ = new std::string(note); }
private: private:
// Identifier name. // Identifier name.
std::string name_; std::string name_;
...@@ -1358,6 +1369,9 @@ class Typed_identifier ...@@ -1358,6 +1369,9 @@ class Typed_identifier
Type* type_; Type* type_;
// The location where the name was seen. // The location where the name was seen.
Location location_; Location location_;
// Escape note for this typed identifier. Used when importing and exporting
// functions.
std::string* note_;
}; };
// A list of Typed_identifiers. // A list of Typed_identifiers.
...@@ -1422,6 +1436,10 @@ class Typed_identifier_list ...@@ -1422,6 +1436,10 @@ class Typed_identifier_list
back() const back() const
{ return this->entries_.back(); } { return this->entries_.back(); }
Typed_identifier&
at(size_t i)
{ return this->entries_.at(i); }
const Typed_identifier& const Typed_identifier&
at(size_t i) const at(size_t i) const
{ return this->entries_.at(i); } { return this->entries_.at(i); }
...@@ -1778,7 +1796,7 @@ class Function_type : public Type ...@@ -1778,7 +1796,7 @@ class Function_type : public Type
: Type(TYPE_FUNCTION), : Type(TYPE_FUNCTION),
receiver_(receiver), parameters_(parameters), results_(results), receiver_(receiver), parameters_(parameters), results_(results),
location_(location), is_varargs_(false), is_builtin_(false), location_(location), is_varargs_(false), is_builtin_(false),
fnbtype_(NULL) fnbtype_(NULL), is_tagged_(false)
{ } { }
// Get the receiver. // Get the receiver.
...@@ -1786,6 +1804,11 @@ class Function_type : public Type ...@@ -1786,6 +1804,11 @@ class Function_type : public Type
receiver() const receiver() const
{ return this->receiver_; } { return this->receiver_; }
// Add an escape note for the receiver.
void
add_receiver_note(int encoding)
{ this->receiver_->set_note(Escape_note::make_tag(encoding)); }
// Get the return names and types. // Get the return names and types.
const Typed_identifier_list* const Typed_identifier_list*
results() const results() const
...@@ -1796,6 +1819,21 @@ class Function_type : public Type ...@@ -1796,6 +1819,21 @@ class Function_type : public Type
parameters() const parameters() const
{ return this->parameters_; } { return this->parameters_; }
// Add an escape note for the ith parameter.
void
add_parameter_note(int index, int encoding)
{ this->parameters_->at(index).set_note(Escape_note::make_tag(encoding)); }
// Whether this function has been tagged during escape analysis.
bool
is_tagged() const
{ return this->is_tagged_; }
// Mark this function as tagged after analyzing its escape.
void
set_is_tagged()
{ this->is_tagged_ = true; }
// Whether this is a varargs function. // Whether this is a varargs function.
bool bool
is_varargs() const is_varargs() const
...@@ -1950,6 +1988,9 @@ class Function_type : public Type ...@@ -1950,6 +1988,9 @@ class Function_type : public Type
// The backend representation of this type for backend function // The backend representation of this type for backend function
// declarations and definitions. // declarations and definitions.
Btype* fnbtype_; Btype* fnbtype_;
// Whether this function has been analyzed by escape analysis. If this is
// TRUE, this function type's parameters contain a summary of the analysis.
bool is_tagged_;
}; };
// The type of a function's backend representation. // The type of a function's backend representation.
......
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