* go-gcc.cc (Gcc_backend::temporary_variable): New function.
From-SVN: r172737
+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.
parameter_variable(Bfunction*, const std::string& name, Btype* type,
source_location);
+ Bvariable*
+ temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool,
+ source_location, Bstatement**);
+
// Labels.
Blabel*
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.
Blabel*
parameter_variable(Bfunction* function, const std::string& name,
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.
// Create a new label. NAME will be empty if this is a label
// Get a tree referring to the variable.
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.
// This is to support builtin math functions when using 80387 math.
tree excess_type = NULL_TREE;
- if (DECL_P(fndecl)
+ if (TREE_CODE(fndecl) == FUNCTION_DECL
&& DECL_IS_BUILTIN(fndecl)
&& DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL
&& nargs > 0
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.
int
tree
Temporary_statement::do_get_tree(Translate_context* context)
{
- gcc_assert(this->decl_ == NULL_TREE);
- tree type_tree = this->type()->get_tree(context->gogo());
- tree init_tree = (this->init_ == NULL
- ? NULL_TREE
- : this->init_->get_tree(context));
- if (type_tree == error_mark_node || init_tree == error_mark_node)
- {
- this->decl_ = error_mark_node;
- return error_mark_node;
- }
- // We can only use create_tmp_var if the type is not addressable.
- if (!TREE_ADDRESSABLE(type_tree))
+ gcc_assert(this->bvariable_ == NULL);
+
+ // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
+ // until we have a better representation of the init function.
+ Named_object* function = context->function();
+ Bfunction* bfunction;
+ if (function == NULL)
+ bfunction = NULL;
+ else
+ bfunction = tree_to_function(function->func_value()->get_decl());
+
+ 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");
- DECL_SOURCE_LOCATION(this->decl_) = this->location();
+ Expression* init = Expression::make_cast(this->type_, this->init_,
+ 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);
- tree decl = build_decl(this->location(), VAR_DECL,
- 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;
+ gcc_assert(saw_errors());
+ return context->backend()->error_variable();
}
- if (init_tree != NULL_TREE)
- 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_);
+ return this->bvariable_;
}
// Make and initialize a temporary variable in BLOCK.
class Typed_identifier_list;
class Bexpression;
class Bstatement;
+class Bvariable;
// This class is used to traverse assignments made by a statement
// which makes assignments.
public:
Temporary_statement(Type* type, Expression* init, source_location 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.
Type*
type() const;
- // Return the initialization expression.
- Expression*
- init() const
- { return this->init_; }
-
// Record that something takes the address of this temporary
// variable.
void
set_is_address_taken()
{ this->is_address_taken_ = true; }
- // Return the tree for the temporary variable itself. This should
- // not be called until after the statement itself has been expanded.
- tree
- get_decl() const;
+ // Return the temporary variable. This should not be called until
+ // after the statement itself has been converted.
+ Bvariable*
+ get_backend_variable(Translate_context*) const;
protected:
int
Type* type_;
// The initial value of the temporary variable. This may be NULL.
Expression* init_;
- // The DECL for the temporary variable.
- tree decl_;
+ // The backend representation of the temporary variable.
+ Bvariable* bvariable_;
// True if something takes the address of this temporary variable.
bool is_address_taken_;
};