Commit e09ce6c5 by Ian Lance Taylor Committed by Ian Lance Taylor

Use backend interface for variables.

	* go-gcc.cc: Include "go-c.h".
	(class Bvariable): Define.
	(Gcc_backend::init_statement): New function.
	(Gcc_backend::global_variable): New function.
	(Gcc_backend::global_variable_set_init): New function.
	(Gcc_backend::local_variable): New function.
	(Gcc_backend::parameter_variable): New function.
	(tree_to_type, var_to_tree): New functions.
	* Make-lang.in (go/go-gcc.o): Depend on $(GO_C_H).
	* (go/gogo-tree.o): Depend on go/gofrontend/backend.h.

From-SVN: r172693
parent 61bd5ad8
2011-04-18 Ian Lance Taylor <iant@google.com>
* go-gcc.cc: Include "go-c.h".
(class Bvariable): Define.
(Gcc_backend::init_statement): New function.
(Gcc_backend::global_variable): New function.
(Gcc_backend::global_variable_set_init): New function.
(Gcc_backend::local_variable): New function.
(Gcc_backend::parameter_variable): New function.
(tree_to_type, var_to_tree): New functions.
* Make-lang.in (go/go-gcc.o): Depend on $(GO_C_H).
* (go/gogo-tree.o): Depend on go/gofrontend/backend.h.
2011-04-15 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Gcc_backend::compound_statement): New function.
......
......@@ -239,7 +239,7 @@ go/go-lang.o: go/go-lang.c $(CONFIG_H) $(SYSTEM_H) coretypes.h $(OPTS_H) \
GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \
$(GIMPLE_H) $(GO_GOGO_H) go/gofrontend/backend.h
$(GIMPLE_H) $(GO_C_H) $(GO_GOGO_H) go/gofrontend/backend.h
$(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
go/%.o: go/gofrontend/%.cc
......@@ -262,7 +262,8 @@ go/go-dump.o: go/gofrontend/go-dump.cc $(GO_SYSTEM_H) $(GO_C_H) \
go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TOPLEV_H) \
$(TREE_H) $(GIMPLE_H) tree-iterator.h $(CGRAPH_H) langhooks.h \
convert.h output.h $(DIAGNOSTIC_H) $(GO_TYPES_H) \
$(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_RUNTIME_H) $(GO_GOGO_H)
$(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_RUNTIME_H) \
go/gofrontend/backend.h $(GO_GOGO_H)
go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) $(GO_C_H) \
go/gofrontend/go-dump.h $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) \
$(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_RUNTIME_H) \
......
......@@ -37,6 +37,8 @@ extern "C"
}
#endif
#include "go-c.h"
#include "gogo.h"
#include "backend.h"
......@@ -90,6 +92,14 @@ class Bfunction : public Gcc_tree
{ }
};
class Bvariable : public Gcc_tree
{
public:
Bvariable(tree t)
: Gcc_tree(t)
{ }
};
class Blabel : public Gcc_tree
{
public:
......@@ -174,6 +184,9 @@ class Gcc_backend : public Backend
expression_statement(Bexpression*);
Bstatement*
init_statement(Bvariable* var, Bexpression* init);
Bstatement*
assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location);
Bstatement*
......@@ -196,6 +209,32 @@ class Gcc_backend : public Backend
Bstatement*
statement_list(const std::vector<Bstatement*>&);
// Variables.
Bvariable*
error_variable()
{ return new Bvariable(error_mark_node); }
Bvariable*
global_variable(const std::string& package_name,
const std::string& unique_prefix,
const std::string& name,
Btype* btype,
bool is_external,
bool is_hidden,
source_location location);
void
global_variable_set_init(Bvariable*, Bexpression*);
Bvariable*
local_variable(Bfunction*, const std::string& name, Btype* type,
source_location);
Bvariable*
parameter_variable(Bfunction*, const std::string& name, Btype* type,
source_location);
// Labels.
Blabel*
......@@ -238,6 +277,21 @@ Gcc_backend::expression_statement(Bexpression* expr)
return this->make_statement(expr->get_tree());
}
// Variable initialization.
Bstatement*
Gcc_backend::init_statement(Bvariable* var, Bexpression* init)
{
tree var_tree = var->get_tree();
tree init_tree = init->get_tree();
if (var_tree == error_mark_node || init_tree == error_mark_node)
return this->error_statement();
gcc_assert(TREE_CODE(var_tree) == VAR_DECL);
DECL_INITIAL(var_tree) = init_tree;
return this->make_statement(build1_loc(DECL_SOURCE_LOCATION(var_tree),
DECL_EXPR, void_type_node, var_tree));
}
// Assignment.
Bstatement*
......@@ -427,6 +481,99 @@ Gcc_backend::statement_list(const std::vector<Bstatement*>& statements)
return this->make_statement(stmt_list);
}
// Make a global variable.
Bvariable*
Gcc_backend::global_variable(const std::string& package_name,
const std::string& unique_prefix,
const std::string& name,
Btype* btype,
bool is_external,
bool is_hidden,
source_location location)
{
tree type_tree = btype->get_tree();
if (type_tree == error_mark_node)
return this->error_variable();
std::string var_name(package_name);
var_name.push_back('.');
var_name.append(name);
tree decl = build_decl(location, VAR_DECL,
get_identifier_from_string(var_name),
type_tree);
if (is_external)
DECL_EXTERNAL(decl) = 1;
else
TREE_STATIC(decl) = 1;
if (!is_hidden)
{
TREE_PUBLIC(decl) = 1;
std::string asm_name(unique_prefix);
asm_name.push_back('.');
asm_name.append(var_name);
SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
}
TREE_USED(decl) = 1;
go_preserve_from_gc(decl);
return new Bvariable(decl);
}
// Set the initial value of a global variable.
void
Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr)
{
tree expr_tree = expr->get_tree();
if (expr_tree == error_mark_node)
return;
gcc_assert(TREE_CONSTANT(expr_tree));
tree var_decl = var->get_tree();
if (var_decl == error_mark_node)
return;
DECL_INITIAL(var_decl) = expr_tree;
}
// Make a local variable.
Bvariable*
Gcc_backend::local_variable(Bfunction* function, const std::string& name,
Btype* btype, source_location location)
{
tree type_tree = btype->get_tree();
if (type_tree == error_mark_node)
return this->error_variable();
tree decl = build_decl(location, VAR_DECL,
get_identifier_from_string(name),
type_tree);
DECL_CONTEXT(decl) = function->get_tree();
TREE_USED(decl) = 1;
go_preserve_from_gc(decl);
return new Bvariable(decl);
}
// Make a function parameter variable.
Bvariable*
Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
Btype* btype, source_location location)
{
tree type_tree = btype->get_tree();
if (type_tree == error_mark_node)
return this->error_variable();
tree decl = build_decl(location, PARM_DECL,
get_identifier_from_string(name),
type_tree);
DECL_CONTEXT(decl) = function->get_tree();
DECL_ARG_TYPE(decl) = type_tree;
TREE_USED(decl) = 1;
go_preserve_from_gc(decl);
return new Bvariable(decl);
}
// Make a label.
Blabel*
......@@ -494,6 +641,12 @@ go_get_backend()
// FIXME: Temporary functions while converting to the new backend
// interface.
Btype*
tree_to_type(tree t)
{
return new Btype(t);
}
Bexpression*
tree_to_expr(tree t)
{
......@@ -523,3 +676,9 @@ stat_to_tree(Bstatement* bs)
{
return bs->get_tree();
}
tree
var_to_tree(Bvariable* bv)
{
return bv->get_tree();
}
......@@ -27,6 +27,9 @@ class Bstatement;
// The backend representation of a function definition.
class Bfunction;
// The backend representation of a variable.
class Bvariable;
// The backend representation of a label.
class Blabel;
......@@ -117,6 +120,12 @@ class Backend
virtual Bstatement*
expression_statement(Bexpression*) = 0;
// Create a variable initialization statement. This initializes a
// local variable at the point in the program flow where it is
// declared.
virtual Bstatement*
init_statement(Bvariable* var, Bexpression* init) = 0;
// Create an assignment statement.
virtual Bstatement*
assignment_statement(Bexpression* lhs, Bexpression* rhs,
......@@ -154,6 +163,57 @@ class Backend
virtual Bstatement*
statement_list(const std::vector<Bstatement*>&) = 0;
// Variables.
// Create an error variable. This is used for cases which should
// not occur in a correct program, in order to keep the compilation
// going without crashing.
virtual Bvariable*
error_variable() = 0;
// Create a global variable. PACKAGE_NAME is the name of the
// package where the variable is defined. UNIQUE_PREFIX is the
// prefix for that package, from the -fgo-prefix option. NAME is
// the name of the variable. BTYPE is the type of the variable.
// IS_EXTERNAL is true if the variable is defined in some other
// package. IS_HIDDEN is true if the variable is not exported (name
// begins with a lower case letter). LOCATION is where the variable
// was defined.
virtual Bvariable*
global_variable(const std::string& package_name,
const std::string& unique_prefix,
const std::string& name,
Btype* btype,
bool is_external,
bool is_hidden,
source_location location) = 0;
// A global variable will 1) be initialized to zero, or 2) be
// initialized to a constant value, or 3) be initialized in the init
// function. In case 2, the frontend will call
// global_variable_set_init to set the initial value. If this is
// not called, the backend should initialize a global variable to 0.
// The init function may then assign a value to it.
virtual void
global_variable_set_init(Bvariable*, Bexpression*) = 0;
// Create a local variable. The frontend will create the local
// variables first, and then create the block which contains them.
// FUNCTION is the function in which the variable is defined. NAME
// is the name of the variable. TYPE is the type. LOCATION is
// where the variable is defined. For each local variable the
// frontend will call init_statement to set the initial value.
virtual Bvariable*
local_variable(Bfunction* function, const std::string& name, Btype* type,
source_location location) = 0;
// Create a function parameter. This is an incoming parameter, not
// a result parameter (result parameters are treated as local
// variables). The arguments are as for local_variable.
virtual Bvariable*
parameter_variable(Bfunction* function, const std::string& name,
Btype* type, source_location location) = 0;
// Labels.
// Create a new label. NAME will be empty if this is a label
......@@ -186,10 +246,12 @@ extern Backend* go_get_backend();
// FIXME: Temporary helper functions while converting to new backend
// interface.
extern Btype* tree_to_type(tree);
extern Bexpression* tree_to_expr(tree);
extern Bstatement* tree_to_stat(tree);
extern Bfunction* tree_to_function(tree);
extern tree expr_to_tree(Bexpression*);
extern tree stat_to_tree(Bstatement*);
extern tree var_to_tree(Bvariable*);
#endif // !defined(GO_BACKEND_H)
......@@ -972,7 +972,24 @@ Var_expression::do_address_taken(bool escapes)
tree
Var_expression::do_get_tree(Translate_context* context)
{
return this->variable_->get_tree(context->gogo(), context->function());
Bvariable* bvar = this->variable_->get_backend_variable(context->gogo(),
context->function());
tree ret = var_to_tree(bvar);
if (ret == error_mark_node)
return error_mark_node;
bool is_in_heap;
if (this->variable_->is_variable())
is_in_heap = this->variable_->var_value()->is_in_heap();
else if (this->variable_->is_result_variable())
is_in_heap = this->variable_->result_var_value()->is_in_heap();
else
gcc_unreachable();
if (is_in_heap)
{
ret = build_fold_indirect_ref_loc(this->location(), ret);
TREE_THIS_NOTRAP(ret) = 1;
}
return ret;
}
// Make a reference to a variable in an expression.
......
......@@ -2659,7 +2659,8 @@ Function::create_result_variables(Gogo* gogo)
++result_counter;
name = gogo->pack_hidden_name(buf, false);
}
Result_variable* result = new Result_variable(p->type(), this, index);
Result_variable* result = new Result_variable(p->type(), this, index,
p->location());
Named_object* no = block->bindings()->add_result_variable(name, result);
if (no->is_result_variable())
this->results_->push_back(no);
......@@ -3290,7 +3291,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
bool is_parameter, bool is_receiver,
source_location location)
: type_(type), init_(init), preinit_(NULL), location_(location),
is_global_(is_global), is_parameter_(is_parameter),
backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
is_receiver_(is_receiver), is_varargs_parameter_(false),
is_address_taken_(false), seen_(false), init_is_lowered_(false),
type_from_init_tuple_(false), type_from_range_index_(false),
......@@ -3636,6 +3637,93 @@ Variable::import_var(Import* imp, std::string* pname, Type** ptype)
imp->require_c_string(";\n");
}
// Convert a variable to the backend representation.
Bvariable*
Variable::get_backend_variable(Gogo* gogo, Named_object* function,
const Package* package, const std::string& name)
{
if (this->backend_ == NULL)
{
Backend* backend = gogo->backend();
Type* type = this->type_;
if (type->is_error_type()
|| (type->is_undefined()
&& (!this->is_global_ || package == NULL)))
this->backend_ = backend->error_variable();
else
{
bool is_parameter = this->is_parameter_;
if (this->is_receiver_ && type->points_to() == NULL)
is_parameter = false;
if (this->is_in_heap())
{
is_parameter = false;
type = Type::make_pointer_type(type);
}
std::string n = Gogo::unpack_hidden_name(name);
Btype* btype = tree_to_type(type->get_tree(gogo));
Bvariable* bvar;
if (this->is_global_)
bvar = backend->global_variable((package == NULL
? gogo->package_name()
: package->name()),
(package == NULL
? gogo->unique_prefix()
: package->unique_prefix()),
n,
btype,
package != NULL,
Gogo::is_hidden_name(name),
this->location_);
else
{
tree fndecl = function->func_value()->get_decl();
Bfunction* bfunction = tree_to_function(fndecl);
if (is_parameter)
bvar = backend->parameter_variable(bfunction, n, btype,
this->location_);
else
bvar = backend->local_variable(bfunction, n, btype,
this->location_);
}
this->backend_ = bvar;
}
}
return this->backend_;
}
// Class Result_variable.
// Convert a result variable to the backend representation.
Bvariable*
Result_variable::get_backend_variable(Gogo* gogo, Named_object* function,
const std::string& name)
{
if (this->backend_ == NULL)
{
Backend* backend = gogo->backend();
Type* type = this->type_;
if (type->is_error())
this->backend_ = backend->error_variable();
else
{
if (this->is_in_heap())
type = Type::make_pointer_type(type);
Btype* btype = tree_to_type(type->get_tree(gogo));
tree fndecl = function->func_value()->get_decl();
Bfunction* bfunction = tree_to_function(fndecl);
std::string n = Gogo::unpack_hidden_name(name);
this->backend_ = backend->local_variable(bfunction, n, btype,
this->location_);
}
}
return this->backend_;
}
// Class Named_constant.
// Traverse the initializer expression.
......@@ -3997,7 +4085,7 @@ Named_object::location() const
return this->var_value()->location();
case NAMED_OBJECT_RESULT_VAR:
return this->result_var_value()->function()->location();
return this->result_var_value()->location();
case NAMED_OBJECT_SINK:
gcc_unreachable();
......@@ -4057,6 +4145,21 @@ Named_object::export_named_object(Export* exp) const
}
}
// Convert a variable to the backend representation.
Bvariable*
Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
{
if (this->classification_ == NAMED_OBJECT_VAR)
return this->var_value()->get_backend_variable(gogo, function,
this->package_, this->name_);
else if (this->classification_ == NAMED_OBJECT_RESULT_VAR)
return this->result_var_value()->get_backend_variable(gogo, function,
this->name_);
else
gcc_unreachable();
}
// Class Bindings.
Bindings::Bindings(Bindings* enclosing)
......
......@@ -43,6 +43,7 @@ class Export;
class Import;
class Bexpression;
class Bstatement;
class Bvariable;
class Blabel;
// This file declares the basic classes used to hold the internal
......@@ -1270,6 +1271,11 @@ class Variable
set_address_taken()
{ this->is_address_taken_ = true; }
// Get the backend representation of the variable.
Bvariable*
get_backend_variable(Gogo*, Named_object*, const Package*,
const std::string&);
// Get the initial value of the variable as a tree. This may only
// be called if has_pre_init() returns false.
tree
......@@ -1312,6 +1318,8 @@ class Variable
Block* preinit_;
// Location of variable definition.
source_location location_;
// Backend representation.
Bvariable* backend_;
// Whether this is a global variable.
bool is_global_ : 1;
// Whether this is a function parameter.
......@@ -1346,9 +1354,10 @@ class Variable
class Result_variable
{
public:
Result_variable(Type* type, Function* function, int index)
: type_(type), function_(function), index_(index),
is_address_taken_(false)
Result_variable(Type* type, Function* function, int index,
source_location location)
: type_(type), function_(function), index_(index), location_(location),
backend_(NULL), is_address_taken_(false)
{ }
// Get the type of the result variable.
......@@ -1366,6 +1375,11 @@ class Result_variable
index() const
{ return this->index_; }
// The location of the variable definition.
source_location
location() const
{ return this->location_; }
// Whether this variable's address is taken.
bool
is_address_taken() const
......@@ -1387,6 +1401,10 @@ class Result_variable
set_function(Function* function)
{ this->function_ = function; }
// Get the backend representation of the variable.
Bvariable*
get_backend_variable(Gogo*, Named_object*, const std::string&);
private:
// Type of result variable.
Type* type_;
......@@ -1394,6 +1412,10 @@ class Result_variable
Function* function_;
// Index in list of results.
int index_;
// Where the result variable is defined.
source_location location_;
// Backend representation.
Bvariable* backend_;
// Whether something takes the address of this variable.
bool is_address_taken_;
};
......@@ -1868,6 +1890,10 @@ class Named_object
source_location
location() const;
// Convert a variable to the backend representation.
Bvariable*
get_backend_variable(Gogo*, Named_object* function);
// Return a tree for the external identifier for this object.
tree
get_id(Gogo*);
......
......@@ -251,37 +251,46 @@ Variable_declaration_statement::do_traverse_assignments(
tree
Variable_declaration_statement::do_get_tree(Translate_context* context)
{
tree val = this->var_->get_tree(context->gogo(), context->function());
if (val == error_mark_node || TREE_TYPE(val) == error_mark_node)
return error_mark_node;
Variable* variable = this->var_->var_value();
tree init = variable->get_init_tree(context->gogo(), context->function());
if (init == error_mark_node)
return error_mark_node;
// If this variable lives on the heap, we need to allocate it now.
if (!variable->is_in_heap())
Variable* var = this->var_->var_value();
Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
context->function());
tree init = var->get_init_tree(context->gogo(), context->function());
Bexpression* binit = init == NULL_TREE ? NULL : tree_to_expr(init);
Bstatement* ret;
if (!var->is_in_heap())
{
DECL_INITIAL(val) = init;
return this->build_stmt_1(DECL_EXPR, val);
gcc_assert(binit != NULL);
ret = context->backend()->init_statement(bvar, binit);
}
else
{
gcc_assert(TREE_CODE(val) == INDIRECT_REF);
tree decl = TREE_OPERAND(val, 0);
gcc_assert(TREE_CODE(decl) == VAR_DECL);
tree type = TREE_TYPE(decl);
gcc_assert(POINTER_TYPE_P(type));
tree size = TYPE_SIZE_UNIT(TREE_TYPE(type));
tree space = context->gogo()->allocate_memory(variable->type(), size,
this->location());
space = fold_convert(TREE_TYPE(decl), space);
DECL_INITIAL(decl) = space;
return build2(COMPOUND_EXPR, void_type_node,
this->build_stmt_1(DECL_EXPR, decl),
build2(MODIFY_EXPR, void_type_node, val, init));
// Something takes the address of this variable, so the value is
// stored in the heap. Initialize it to newly allocated memory
// space, and assign the initial value to the new space.
source_location loc = this->location();
tree decl = var_to_tree(bvar);
tree decl_type = TREE_TYPE(decl);
gcc_assert(POINTER_TYPE_P(decl_type));
tree size = TYPE_SIZE_UNIT(TREE_TYPE(decl_type));
tree space = context->gogo()->allocate_memory(var->type(), size, loc);
if (binit != NULL)
space = save_expr(space);
space = fold_convert_loc(loc, decl_type, space);
Bstatement* s1 = context->backend()->init_statement(bvar,
tree_to_expr(space));
if (binit == NULL)
ret = s1;
else
{
tree indir = build_fold_indirect_ref_loc(loc, space);
Bexpression* bindir = tree_to_expr(indir);
Bstatement* s2 = context->backend()->assignment_statement(bindir,
binit,
loc);
ret = context->backend()->compound_statement(s1, s2);
}
}
return stat_to_tree(ret);
}
// Make a variable declaration.
......@@ -2421,6 +2430,8 @@ Return_statement::do_lower(Gogo*, Named_object* function, Block* enclosing)
tree
Return_statement::do_get_tree(Translate_context* context)
{
source_location loc = this->location();
Function* function = context->function()->func_value();
tree fndecl = function->get_decl();
......@@ -2433,14 +2444,14 @@ Return_statement::do_get_tree(Translate_context* context)
p != results->end();
p++)
{
tree rv = (*p)->get_tree(context->gogo(), context->function());
retvals.push_back(tree_to_expr(rv));
Expression* vr = Expression::make_var_reference(*p, loc);
retvals.push_back(tree_to_expr(vr->get_tree(context)));
}
}
Bstatement* ret;
ret = context->backend()->return_statement(tree_to_function(fndecl),
retvals, this->location());
retvals, loc);
return stat_to_tree(ret);
}
......
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