From 9131ad67477de06fb420c24863b9c9abf2a16d80 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 19 Apr 2011 21:52:41 +0000 Subject: [PATCH] Use backend interface for temporary variables. * go-gcc.cc (Gcc_backend::temporary_variable): New function. From-SVN: r172737 --- gcc/go/ChangeLog | 4 ++ gcc/go/go-gcc.cc | 66 +++++++++++++++++++++++++++ gcc/go/gofrontend/backend.h | 16 +++++++ gcc/go/gofrontend/expressions.cc | 19 ++++++-- gcc/go/gofrontend/statements.cc | 98 +++++++++++++++++----------------------- gcc/go/gofrontend/statements.h | 20 ++++---- 6 files changed, 152 insertions(+), 71 deletions(-) diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 4fe9b46..37d6b6c 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,5 +1,9 @@ 2011-04-19 Ian Lance Taylor + * go-gcc.cc (Gcc_backend::temporary_variable): New function. + +2011-04-19 Ian Lance Taylor + * go-gcc.cc (class Bblock): Define. (Gcc_backend::if_statement): Change then_block and else_block to Bblock*. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 46c149c..7b7923d 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -255,6 +255,10 @@ class Gcc_backend : public Backend parameter_variable(Bfunction*, const std::string& name, Btype* type, source_location); + Bvariable* + temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool, + source_location, Bstatement**); + // Labels. Blabel* @@ -702,6 +706,68 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, 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* diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 6690a52..4377332 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -246,6 +246,22 @@ class Backend 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 diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 9adcbc3..5f885ab 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -1029,9 +1029,22 @@ Temporary_reference_expression::do_address_taken(bool) // 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. @@ -8952,7 +8965,7 @@ Call_expression::do_get_tree(Translate_context* context) // 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 diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 7c6ccb9..eef9398 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -311,19 +311,6 @@ Temporary_statement::type() const 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 @@ -400,53 +387,52 @@ Temporary_statement::do_check_types(Gogo*) 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. diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 1958bf9..2310ef1 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -41,6 +41,7 @@ class Select_clauses; class Typed_identifier_list; class Bexpression; class Bstatement; +class Bvariable; // This class is used to traverse assignments made by a statement // which makes assignments. @@ -475,28 +476,23 @@ class Temporary_statement : public Statement 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 @@ -519,8 +515,8 @@ class Temporary_statement : public Statement 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_; }; -- 2.7.4