Commit 9131ad67 by Ian Lance Taylor Committed by Ian Lance Taylor

Use backend interface for temporary variables.

	* go-gcc.cc (Gcc_backend::temporary_variable): New function.

From-SVN: r172737
parent f0679612
2011-04-19 Ian Lance Taylor <iant@google.com> 2011-04-19 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Gcc_backend::temporary_variable): New function.
2011-04-19 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (class Bblock): Define. * go-gcc.cc (class Bblock): Define.
(Gcc_backend::if_statement): Change then_block and else_block to (Gcc_backend::if_statement): Change then_block and else_block to
Bblock*. Bblock*.
......
...@@ -255,6 +255,10 @@ class Gcc_backend : public Backend ...@@ -255,6 +255,10 @@ class Gcc_backend : public Backend
parameter_variable(Bfunction*, const std::string& name, Btype* type, parameter_variable(Bfunction*, const std::string& name, Btype* type,
source_location); source_location);
Bvariable*
temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool,
source_location, Bstatement**);
// Labels. // Labels.
Blabel* Blabel*
...@@ -702,6 +706,68 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, ...@@ -702,6 +706,68 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
return new Bvariable(decl); return new Bvariable(decl);
} }
// Make a temporary variable.
Bvariable*
Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
Btype* btype, Bexpression* binit,
bool is_address_taken,
source_location location,
Bstatement** pstatement)
{
tree type_tree = btype->get_tree();
tree init_tree = binit == NULL ? NULL_TREE : binit->get_tree();
if (type_tree == error_mark_node || init_tree == error_mark_node)
{
*pstatement = this->error_statement();
return this->error_variable();
}
tree var;
// We can only use create_tmp_var if the type is not addressable.
if (!TREE_ADDRESSABLE(type_tree))
var = create_tmp_var(type_tree, "GOTMP");
else
{
gcc_assert(bblock != NULL);
var = build_decl(location, VAR_DECL,
create_tmp_var_name("GOTMP"),
type_tree);
DECL_ARTIFICIAL(var) = 1;
DECL_IGNORED_P(var) = 1;
TREE_USED(var) = 1;
// FIXME: Permitting function to be NULL here is a temporary
// measure until we have a proper representation of the init
// function.
if (function != NULL)
DECL_CONTEXT(var) = function->get_tree();
else
{
gcc_assert(current_function_decl != NULL_TREE);
DECL_CONTEXT(var) = current_function_decl;
}
// We have to add this variable to the BLOCK and the BIND_EXPR.
tree bind_tree = bblock->get_tree();
gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR);
tree block_tree = BIND_EXPR_BLOCK(bind_tree);
gcc_assert(TREE_CODE(block_tree) == BLOCK);
DECL_CHAIN(var) = BLOCK_VARS(block_tree);
BLOCK_VARS(block_tree) = var;
BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree);
}
if (init_tree != NULL_TREE)
DECL_INITIAL(var) = fold_convert_loc(location, type_tree, init_tree);
if (is_address_taken)
TREE_ADDRESSABLE(var) = 1;
*pstatement = this->make_statement(build1_loc(location, DECL_EXPR,
void_type_node, var));
return new Bvariable(var);
}
// Make a label. // Make a label.
Blabel* Blabel*
......
...@@ -246,6 +246,22 @@ class Backend ...@@ -246,6 +246,22 @@ class Backend
parameter_variable(Bfunction* function, const std::string& name, parameter_variable(Bfunction* function, const std::string& name,
Btype* type, source_location location) = 0; Btype* type, source_location location) = 0;
// Create a temporary variable. A temporary variable has no name,
// just a type. We pass in FUNCTION and BLOCK in case they are
// needed. If INIT is not NULL, the variable should be initialized
// to that value. Otherwise the initial value is irrelevant--the
// backend does not have to explicitly initialize it to zero.
// ADDRESS_IS_TAKEN is true if the programs needs to take the
// address of this temporary variable. LOCATION is the location of
// the statement or expression which requires creating the temporary
// variable, and may not be very useful. This function should
// return a variable which can be referenced later and should set
// *PSTATEMENT to a statement which initializes the variable.
virtual Bvariable*
temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression* init,
bool address_is_taken, source_location location,
Bstatement** pstatement) = 0;
// Labels. // Labels.
// Create a new label. NAME will be empty if this is a label // Create a new label. NAME will be empty if this is a label
......
...@@ -1029,9 +1029,22 @@ Temporary_reference_expression::do_address_taken(bool) ...@@ -1029,9 +1029,22 @@ Temporary_reference_expression::do_address_taken(bool)
// Get a tree referring to the variable. // Get a tree referring to the variable.
tree tree
Temporary_reference_expression::do_get_tree(Translate_context*) Temporary_reference_expression::do_get_tree(Translate_context* context)
{ {
return this->statement_->get_decl(); Bvariable* bvar = this->statement_->get_backend_variable(context);
// The gcc backend can't represent the same set of recursive types
// that the Go frontend can. In some cases this means that a
// temporary variable won't have the right backend type. Correct
// that here by adding a type cast. We need to use base() to push
// the circularity down one level.
tree ret = var_to_tree(bvar);
if (POINTER_TYPE_P(TREE_TYPE(ret)) && VOID_TYPE_P(TREE_TYPE(TREE_TYPE(ret))))
{
tree type_tree = this->type()->base()->get_tree(context->gogo());
ret = fold_convert_loc(this->location(), type_tree, ret);
}
return ret;
} }
// Make a reference to a temporary variable. // Make a reference to a temporary variable.
...@@ -8952,7 +8965,7 @@ Call_expression::do_get_tree(Translate_context* context) ...@@ -8952,7 +8965,7 @@ Call_expression::do_get_tree(Translate_context* context)
// This is to support builtin math functions when using 80387 math. // This is to support builtin math functions when using 80387 math.
tree excess_type = NULL_TREE; tree excess_type = NULL_TREE;
if (DECL_P(fndecl) if (TREE_CODE(fndecl) == FUNCTION_DECL
&& DECL_IS_BUILTIN(fndecl) && DECL_IS_BUILTIN(fndecl)
&& DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
&& nargs > 0 && nargs > 0
......
...@@ -311,19 +311,6 @@ Temporary_statement::type() const ...@@ -311,19 +311,6 @@ Temporary_statement::type() const
return this->type_ != NULL ? this->type_ : this->init_->type(); return this->type_ != NULL ? this->type_ : this->init_->type();
} }
// Return the tree for the temporary variable.
tree
Temporary_statement::get_decl() const
{
if (this->decl_ == NULL)
{
gcc_assert(saw_errors());
return error_mark_node;
}
return this->decl_;
}
// Traversal. // Traversal.
int int
...@@ -400,53 +387,52 @@ Temporary_statement::do_check_types(Gogo*) ...@@ -400,53 +387,52 @@ Temporary_statement::do_check_types(Gogo*)
tree tree
Temporary_statement::do_get_tree(Translate_context* context) Temporary_statement::do_get_tree(Translate_context* context)
{ {
gcc_assert(this->decl_ == NULL_TREE); gcc_assert(this->bvariable_ == NULL);
tree type_tree = this->type()->get_tree(context->gogo());
tree init_tree = (this->init_ == NULL // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
? NULL_TREE // until we have a better representation of the init function.
: this->init_->get_tree(context)); Named_object* function = context->function();
if (type_tree == error_mark_node || init_tree == error_mark_node) Bfunction* bfunction;
{ if (function == NULL)
this->decl_ = error_mark_node; bfunction = NULL;
return error_mark_node; else
} bfunction = tree_to_function(function->func_value()->get_decl());
// We can only use create_tmp_var if the type is not addressable.
if (!TREE_ADDRESSABLE(type_tree)) Btype* btype = tree_to_type(this->type()->get_tree(context->gogo()));
Bexpression* binit;
if (this->init_ == NULL)
binit = NULL;
else if (this->type_ == NULL)
binit = tree_to_expr(this->init_->get_tree(context));
else
{ {
this->decl_ = create_tmp_var(type_tree, "GOTMP"); Expression* init = Expression::make_cast(this->type_, this->init_,
DECL_SOURCE_LOCATION(this->decl_) = this->location(); this->location());
context->gogo()->lower_expression(context->function(), &init);
binit = tree_to_expr(init->get_tree(context));
} }
else
Bstatement* statement;
this->bvariable_ =
context->backend()->temporary_variable(bfunction, context->bblock(),
btype, binit,
this->is_address_taken_,
this->location(), &statement);
return stat_to_tree(statement);
}
// Return the backend variable.
Bvariable*
Temporary_statement::get_backend_variable(Translate_context* context) const
{
if (this->bvariable_ == NULL)
{ {
gcc_assert(context->function() != NULL && context->block() != NULL); gcc_assert(saw_errors());
tree decl = build_decl(this->location(), VAR_DECL, return context->backend()->error_variable();
create_tmp_var_name("GOTMP"),
type_tree);
DECL_ARTIFICIAL(decl) = 1;
DECL_IGNORED_P(decl) = 1;
TREE_USED(decl) = 1;
gcc_assert(current_function_decl != NULL_TREE);
DECL_CONTEXT(decl) = current_function_decl;
// We have to add this variable to the BLOCK and the BIND_EXPR.
tree bind_tree = block_to_tree(context->bblock());
gcc_assert(bind_tree != NULL_TREE && TREE_CODE(bind_tree) == BIND_EXPR);
tree block_tree = BIND_EXPR_BLOCK(bind_tree);
gcc_assert(TREE_CODE(block_tree) == BLOCK);
DECL_CHAIN(decl) = BLOCK_VARS(block_tree);
BLOCK_VARS(block_tree) = decl;
BIND_EXPR_VARS(bind_tree) = BLOCK_VARS(block_tree);
this->decl_ = decl;
} }
if (init_tree != NULL_TREE) return this->bvariable_;
DECL_INITIAL(this->decl_) =
Expression::convert_for_assignment(context, this->type(),
this->init_->type(), init_tree,
this->location());
if (this->is_address_taken_)
TREE_ADDRESSABLE(this->decl_) = 1;
return this->build_stmt_1(DECL_EXPR, this->decl_);
} }
// Make and initialize a temporary variable in BLOCK. // Make and initialize a temporary variable in BLOCK.
......
...@@ -41,6 +41,7 @@ class Select_clauses; ...@@ -41,6 +41,7 @@ class Select_clauses;
class Typed_identifier_list; class Typed_identifier_list;
class Bexpression; class Bexpression;
class Bstatement; class Bstatement;
class Bvariable;
// This class is used to traverse assignments made by a statement // This class is used to traverse assignments made by a statement
// which makes assignments. // which makes assignments.
...@@ -475,28 +476,23 @@ class Temporary_statement : public Statement ...@@ -475,28 +476,23 @@ class Temporary_statement : public Statement
public: public:
Temporary_statement(Type* type, Expression* init, source_location location) Temporary_statement(Type* type, Expression* init, source_location location)
: Statement(STATEMENT_TEMPORARY, location), : Statement(STATEMENT_TEMPORARY, location),
type_(type), init_(init), decl_(NULL), is_address_taken_(false) type_(type), init_(init), bvariable_(NULL), is_address_taken_(false)
{ } { }
// Return the type of the temporary variable. // Return the type of the temporary variable.
Type* Type*
type() const; type() const;
// Return the initialization expression.
Expression*
init() const
{ return this->init_; }
// Record that something takes the address of this temporary // Record that something takes the address of this temporary
// variable. // variable.
void void
set_is_address_taken() set_is_address_taken()
{ this->is_address_taken_ = true; } { this->is_address_taken_ = true; }
// Return the tree for the temporary variable itself. This should // Return the temporary variable. This should not be called until
// not be called until after the statement itself has been expanded. // after the statement itself has been converted.
tree Bvariable*
get_decl() const; get_backend_variable(Translate_context*) const;
protected: protected:
int int
...@@ -519,8 +515,8 @@ class Temporary_statement : public Statement ...@@ -519,8 +515,8 @@ class Temporary_statement : public Statement
Type* type_; Type* type_;
// The initial value of the temporary variable. This may be NULL. // The initial value of the temporary variable. This may be NULL.
Expression* init_; Expression* init_;
// The DECL for the temporary variable. // The backend representation of the temporary variable.
tree decl_; Bvariable* bvariable_;
// True if something takes the address of this temporary variable. // True if something takes the address of this temporary variable.
bool is_address_taken_; bool is_address_taken_;
}; };
......
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