aboutsummaryrefslogtreecommitdiffstats
path: root/gcc-4.9/gcc/go/gofrontend/dataflow.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc-4.9/gcc/go/gofrontend/dataflow.cc')
-rw-r--r--gcc-4.9/gcc/go/gofrontend/dataflow.cc278
1 files changed, 278 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/go/gofrontend/dataflow.cc b/gcc-4.9/gcc/go/gofrontend/dataflow.cc
new file mode 100644
index 000000000..572ab3631
--- /dev/null
+++ b/gcc-4.9/gcc/go/gofrontend/dataflow.cc
@@ -0,0 +1,278 @@
+// dataflow.cc -- Go frontend dataflow.
+
+// Copyright 2009 The Go 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 "go-system.h"
+
+#include "gogo.h"
+#include "expressions.h"
+#include "statements.h"
+#include "dataflow.h"
+
+// This class is used to traverse the tree to look for uses of
+// variables.
+
+class Dataflow_traverse_expressions : public Traverse
+{
+ public:
+ Dataflow_traverse_expressions(Dataflow* dataflow, Statement* statement)
+ : Traverse(traverse_blocks | traverse_expressions),
+ dataflow_(dataflow), statement_(statement)
+ { }
+
+ protected:
+ // Only look at top-level expressions: do not descend into blocks.
+ // They will be examined via Dataflow_traverse_statements.
+ int
+ block(Block*)
+ { return TRAVERSE_SKIP_COMPONENTS; }
+
+ int
+ expression(Expression**);
+
+ private:
+ // The dataflow information.
+ Dataflow* dataflow_;
+ // The Statement in which we are looking.
+ Statement* statement_;
+};
+
+// Given an expression, return the Named_object that it refers to, if
+// it is a local variable.
+
+static Named_object*
+get_var(Expression* expr)
+{
+ Var_expression* ve = expr->var_expression();
+ if (ve == NULL)
+ return NULL;
+ Named_object* no = ve->named_object();
+ go_assert(no->is_variable() || no->is_result_variable());
+ if (no->is_variable() && no->var_value()->is_global())
+ return NULL;
+ return no;
+}
+
+// Look for a reference to a variable in an expression.
+
+int
+Dataflow_traverse_expressions::expression(Expression** expr)
+{
+ Named_object* no = get_var(*expr);
+ if (no != NULL)
+ this->dataflow_->add_ref(no, this->statement_);
+ return TRAVERSE_CONTINUE;
+}
+
+// This class is used to handle an assignment statement.
+
+class Dataflow_traverse_assignment : public Traverse_assignments
+{
+ public:
+ Dataflow_traverse_assignment(Dataflow* dataflow, Statement* statement)
+ : dataflow_(dataflow), statement_(statement)
+ { }
+
+ protected:
+ void
+ initialize_variable(Named_object*);
+
+ void
+ assignment(Expression** lhs, Expression** rhs);
+
+ void
+ value(Expression**, bool, bool);
+
+ private:
+ // The dataflow information.
+ Dataflow* dataflow_;
+ // The Statement in which we are looking.
+ Statement* statement_;
+};
+
+// Handle a variable initialization.
+
+void
+Dataflow_traverse_assignment::initialize_variable(Named_object* var)
+{
+ Expression* init = var->var_value()->init();
+ this->dataflow_->add_def(var, init, this->statement_, true);
+ if (init != NULL)
+ {
+ Expression* e = init;
+ this->value(&e, true, true);
+ go_assert(e == init);
+ }
+}
+
+// Handle an assignment in a statement.
+
+void
+Dataflow_traverse_assignment::assignment(Expression** plhs, Expression** prhs)
+{
+ Named_object* no = get_var(*plhs);
+ if (no != NULL)
+ {
+ Expression* rhs = prhs == NULL ? NULL : *prhs;
+ this->dataflow_->add_def(no, rhs, this->statement_, false);
+ }
+ else
+ {
+ // If this is not a variable it may be some computed lvalue, and
+ // we want to look for references to variables in that lvalue.
+ this->value(plhs, false, false);
+ }
+ if (prhs != NULL)
+ this->value(prhs, true, false);
+}
+
+// Handle a value in a statement.
+
+void
+Dataflow_traverse_assignment::value(Expression** pexpr, bool, bool)
+{
+ Named_object* no = get_var(*pexpr);
+ if (no != NULL)
+ this->dataflow_->add_ref(no, this->statement_);
+ else
+ {
+ Dataflow_traverse_expressions dte(this->dataflow_, this->statement_);
+ Expression::traverse(pexpr, &dte);
+ }
+}
+
+// This class is used to traverse the tree to look for statements.
+
+class Dataflow_traverse_statements : public Traverse
+{
+ public:
+ Dataflow_traverse_statements(Dataflow* dataflow)
+ : Traverse(traverse_statements),
+ dataflow_(dataflow)
+ { }
+
+ protected:
+ int
+ statement(Block*, size_t* pindex, Statement*);
+
+ private:
+ // The dataflow information.
+ Dataflow* dataflow_;
+};
+
+// For each Statement, we look for expressions.
+
+int
+Dataflow_traverse_statements::statement(Block* block, size_t* pindex,
+ Statement *statement)
+{
+ Dataflow_traverse_assignment dta(this->dataflow_, statement);
+ if (!statement->traverse_assignments(&dta))
+ {
+ Dataflow_traverse_expressions dte(this->dataflow_, statement);
+ statement->traverse(block, pindex, &dte);
+ }
+ return TRAVERSE_CONTINUE;
+}
+
+// Compare variables.
+
+bool
+Dataflow::Compare_vars::operator()(const Named_object* no1,
+ const Named_object* no2) const
+{
+ if (no1->name() < no2->name())
+ return true;
+ if (no1->name() > no2->name())
+ return false;
+
+ // We can have two different variables with the same name.
+ Location loc1 = no1->location();
+ Location loc2 = no2->location();
+ if (loc1 < loc2)
+ return false;
+ if (loc1 > loc2)
+ return true;
+
+ if (no1 == no2)
+ return false;
+
+ // We can't have two variables with the same name in the same
+ // location.
+ go_unreachable();
+}
+
+// Class Dataflow.
+
+Dataflow::Dataflow()
+ : defs_(), refs_()
+{
+}
+
+// Build the dataflow information.
+
+void
+Dataflow::initialize(Gogo* gogo)
+{
+ Dataflow_traverse_statements dts(this);
+ gogo->traverse(&dts);
+}
+
+// Add a definition of a variable.
+
+void
+Dataflow::add_def(Named_object* var, Expression* val, Statement* statement,
+ bool is_init)
+{
+ Defs* defnull = NULL;
+ std::pair<Defmap::iterator, bool> ins =
+ this->defs_.insert(std::make_pair(var, defnull));
+ if (ins.second)
+ ins.first->second = new Defs;
+ Def def;
+ def.statement = statement;
+ def.val = val;
+ def.is_init = is_init;
+ ins.first->second->push_back(def);
+}
+
+// Add a reference to a variable.
+
+void
+Dataflow::add_ref(Named_object* var, Statement* statement)
+{
+ Refs* refnull = NULL;
+ std::pair<Refmap::iterator, bool> ins =
+ this->refs_.insert(std::make_pair(var, refnull));
+ if (ins.second)
+ ins.first->second = new Refs;
+ Ref ref;
+ ref.statement = statement;
+ ins.first->second->push_back(ref);
+}
+
+// Return the definitions of a variable.
+
+const Dataflow::Defs*
+Dataflow::find_defs(Named_object* var) const
+{
+ Defmap::const_iterator p = this->defs_.find(var);
+ if (p == this->defs_.end())
+ return NULL;
+ else
+ return p->second;
+}
+
+// Return the references of a variable.
+
+const Dataflow::Refs*
+Dataflow::find_refs(Named_object* var) const
+{
+ Refmap::const_iterator p = this->refs_.find(var);
+ if (p == this->refs_.end())
+ return NULL;
+ else
+ return p->second;
+}