From 7e84be5540080a194796f9c7411f20f7e52ff97a Mon Sep 17 00:00:00 2001 From: ian Date: Tue, 19 Apr 2011 18:20:05 +0000 Subject: [PATCH] Use backend interface for blocks. * go-gcc.cc (class Bblock): Define. (Gcc_backend::if_statement): Change then_block and else_block to Bblock*. (Gcc_backend::block): New function. (Gcc_backend::block_add_statements): New function. (Gcc_backend::block_statement): New function. (tree_to_block, block_to_tree): New functions. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@172731 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/go/ChangeLog | 10 +++ gcc/go/go-gcc.cc | 149 ++++++++++++++++++++++++++++++++++++++-- gcc/go/gofrontend/backend.h | 38 +++++++++- gcc/go/gofrontend/gogo-tree.cc | 113 ++++-------------------------- gcc/go/gofrontend/gogo.cc | 42 +++++++++++ gcc/go/gofrontend/gogo.h | 28 ++++---- gcc/go/gofrontend/statements.cc | 48 ++++++++----- gcc/go/gofrontend/types.cc | 2 +- 8 files changed, 292 insertions(+), 138 deletions(-) diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 141728ba7dc..4fe9b4618cf 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,13 @@ +2011-04-19 Ian Lance Taylor + + * go-gcc.cc (class Bblock): Define. + (Gcc_backend::if_statement): Change then_block and else_block to + Bblock*. + (Gcc_backend::block): New function. + (Gcc_backend::block_add_statements): New function. + (Gcc_backend::block_statement): New function. + (tree_to_block, block_to_tree): New functions. + 2011-04-18 Ian Lance Taylor * go-gcc.cc: Include "go-c.h". diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index e4f4cfcd951..46c149cd3cb 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -92,6 +92,14 @@ class Bfunction : public Gcc_tree { } }; +class Bblock : public Gcc_tree +{ + public: + Bblock(tree t) + : Gcc_tree(t) + { } +}; + class Bvariable : public Gcc_tree { public: @@ -194,8 +202,8 @@ class Gcc_backend : public Backend source_location); Bstatement* - if_statement(Bexpression* condition, Bstatement* then_block, - Bstatement* else_block, source_location); + if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block, + source_location); Bstatement* switch_statement(Bexpression* value, @@ -209,6 +217,18 @@ class Gcc_backend : public Backend Bstatement* statement_list(const std::vector&); + // Blocks. + + Bblock* + block(Bfunction*, Bblock*, const std::vector&, + source_location, source_location); + + void + block_add_statements(Bblock*, const std::vector&); + + Bstatement* + block_statement(Bblock*); + // Variables. Bvariable* @@ -370,8 +390,8 @@ Gcc_backend::return_statement(Bfunction* bfunction, // If. Bstatement* -Gcc_backend::if_statement(Bexpression* condition, Bstatement* then_block, - Bstatement* else_block, source_location location) +Gcc_backend::if_statement(Bexpression* condition, Bblock* then_block, + Bblock* else_block, source_location location) { tree cond_tree = condition->get_tree(); tree then_tree = then_block->get_tree(); @@ -481,6 +501,114 @@ Gcc_backend::statement_list(const std::vector& statements) return this->make_statement(stmt_list); } +// Make a block. For some reason gcc uses a dual structure for +// blocks: BLOCK tree nodes and BIND_EXPR tree nodes. Since the +// BIND_EXPR node points to the BLOCK node, we store the BIND_EXPR in +// the Bblock. + +Bblock* +Gcc_backend::block(Bfunction* function, Bblock* enclosing, + const std::vector& vars, + source_location start_location, + source_location) +{ + tree block_tree = make_node(BLOCK); + if (enclosing == NULL) + { + // FIXME: Permitting FUNCTION to be NULL is a temporary measure + // until we have a proper representation of the init function. + tree fndecl; + if (function == NULL) + fndecl = current_function_decl; + else + fndecl = function->get_tree(); + gcc_assert(fndecl != NULL_TREE); + + // We may have already created a block for local variables when + // we take the address of a parameter. + if (DECL_INITIAL(fndecl) == NULL_TREE) + { + BLOCK_SUPERCONTEXT(block_tree) = fndecl; + DECL_INITIAL(fndecl) = block_tree; + } + else + { + tree superblock_tree = DECL_INITIAL(fndecl); + BLOCK_SUPERCONTEXT(block_tree) = superblock_tree; + tree* pp; + for (pp = &BLOCK_SUBBLOCKS(superblock_tree); + *pp != NULL_TREE; + pp = &BLOCK_CHAIN(*pp)) + ; + *pp = block_tree; + } + } + else + { + tree superbind_tree = enclosing->get_tree(); + tree superblock_tree = BIND_EXPR_BLOCK(superbind_tree); + gcc_assert(TREE_CODE(superblock_tree) == BLOCK); + + BLOCK_SUPERCONTEXT(block_tree) = superblock_tree; + tree* pp; + for (pp = &BLOCK_SUBBLOCKS(superblock_tree); + *pp != NULL_TREE; + pp = &BLOCK_CHAIN(*pp)) + ; + *pp = block_tree; + } + + tree* pp = &BLOCK_VARS(block_tree); + for (std::vector::const_iterator pv = vars.begin(); + pv != vars.end(); + ++pv) + { + *pp = (*pv)->get_tree(); + if (*pp != error_mark_node) + pp = &DECL_CHAIN(*pp); + } + *pp = NULL_TREE; + + TREE_USED(block_tree) = 1; + + tree bind_tree = build3_loc(start_location, BIND_EXPR, void_type_node, + BLOCK_VARS(block_tree), NULL_TREE, block_tree); + TREE_SIDE_EFFECTS(bind_tree) = 1; + + return new Bblock(bind_tree); +} + +// Add statements to a block. + +void +Gcc_backend::block_add_statements(Bblock* bblock, + const std::vector& statements) +{ + tree stmt_list = NULL_TREE; + for (std::vector::const_iterator p = statements.begin(); + p != statements.end(); + ++p) + { + tree s = (*p)->get_tree(); + if (s != error_mark_node) + append_to_statement_list(s, &stmt_list); + } + + tree bind_tree = bblock->get_tree(); + gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); + BIND_EXPR_BODY(bind_tree) = stmt_list; +} + +// Return a block as a statement. + +Bstatement* +Gcc_backend::block_statement(Bblock* bblock) +{ + tree bind_tree = bblock->get_tree(); + gcc_assert(TREE_CODE(bind_tree) == BIND_EXPR); + return this->make_statement(bind_tree); +} + // Make a global variable. Bvariable* @@ -665,6 +793,13 @@ tree_to_function(tree t) return new Bfunction(t); } +Bblock* +tree_to_block(tree t) +{ + gcc_assert(TREE_CODE(t) == BIND_EXPR); + return new Bblock(t); +} + tree expr_to_tree(Bexpression* be) { @@ -678,6 +813,12 @@ stat_to_tree(Bstatement* bs) } tree +block_to_tree(Bblock* bb) +{ + return bb->get_tree(); +} + +tree var_to_tree(Bvariable* bv) { return bv->get_tree(); diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 3e4c6291fd6..6690a5238dc 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -27,6 +27,9 @@ class Bstatement; // The backend representation of a function definition. class Bfunction; +// The backend representation of a block. +class Bblock; + // The backend representation of a variable. class Bvariable; @@ -139,8 +142,8 @@ class Backend // Create an if statement. ELSE_BLOCK may be NULL. virtual Bstatement* - if_statement(Bexpression* condition, Bstatement* then_block, - Bstatement* else_block, source_location) = 0; + if_statement(Bexpression* condition, Bblock* then_block, Bblock* else_block, + source_location) = 0; // Create a switch statement where the case values are constants. // CASES and STATEMENTS must have the same number of entries. If @@ -163,6 +166,35 @@ class Backend virtual Bstatement* statement_list(const std::vector&) = 0; + // Blocks. + + // Create a block. The frontend will call this function when it + // starts converting a block within a function. FUNCTION is the + // current function. ENCLOSING is the enclosing block; it will be + // NULL for the top-level block in a function. VARS is the list of + // local variables defined within this block; each entry will be + // created by the local_variable function. START_LOCATION is the + // location of the start of the block, more or less the location of + // the initial curly brace. END_LOCATION is the location of the end + // of the block, more or less the location of the final curly brace. + // The statements will be added after the block is created. + virtual Bblock* + block(Bfunction* function, Bblock* enclosing, + const std::vector& vars, + source_location start_location, source_location end_location) = 0; + + // Add the statements to a block. The block is created first. Then + // the statements are created. Then the statements are added to the + // block. This will called exactly once per block. The vector may + // be empty if there are no statements. + virtual void + block_add_statements(Bblock*, const std::vector&) = 0; + + // Return the block as a statement. This is used to include a block + // in a list of statements. + virtual Bstatement* + block_statement(Bblock*) = 0; + // Variables. // Create an error variable. This is used for cases which should @@ -250,8 +282,10 @@ 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 Bblock* tree_to_block(tree); extern tree expr_to_tree(Bexpression*); extern tree stat_to_tree(Bstatement*); +extern tree block_to_tree(Bblock*); extern tree var_to_tree(Bvariable*); #endif // !defined(GO_BACKEND_H) diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index a59076e8257..ec06c65a13e 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -900,7 +900,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function) case NAMED_OBJECT_CONST: { Named_constant* named_constant = this->u_.const_value; - Translate_context subcontext(gogo, function, NULL, NULL_TREE); + Translate_context subcontext(gogo, function, NULL, NULL); tree expr_tree = named_constant->expr()->get_tree(&subcontext); if (expr_tree == error_mark_node) decl = error_mark_node; @@ -1038,7 +1038,7 @@ Variable::get_init_tree(Gogo* gogo, Named_object* function) } else { - Translate_context context(gogo, function, NULL, NULL_TREE); + Translate_context context(gogo, function, NULL, NULL); tree rhs_tree = this->init_->get_tree(&context); return Expression::convert_for_assignment(&context, this->type(), this->init_->type(), @@ -1059,8 +1059,9 @@ Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl) // TRY_CATCH_EXPR; if it does, we want to add to the end of the // regular statements. - Translate_context context(gogo, function, NULL, NULL_TREE); - tree block_tree = this->preinit_->get_tree(&context); + Translate_context context(gogo, function, NULL, NULL); + Bblock* bblock = this->preinit_->get_backend(&context); + tree block_tree = block_to_tree(bblock); if (block_tree == error_mark_node) return error_mark_node; gcc_assert(TREE_CODE(block_tree) == BIND_EXPR); @@ -1472,21 +1473,22 @@ Function::build_tree(Gogo* gogo, Named_object* named_function) BLOCK_VARS(block) = declare_vars; TREE_USED(block) = 1; + bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), + NULL_TREE, block); + TREE_SIDE_EFFECTS(bind) = 1; + if (this->defer_stack_ != NULL) { Translate_context dcontext(gogo, named_function, this->block_, - block); + tree_to_block(bind)); defer_init = this->defer_stack_->get_tree(&dcontext); } - - bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), - NULL_TREE, block); - TREE_SIDE_EFFECTS(bind) = 1; } // Build the trees for all the statements in the function. - Translate_context context(gogo, named_function, NULL, NULL_TREE); - tree code = this->block_->get_tree(&context); + Translate_context context(gogo, named_function, NULL, NULL); + Bblock* bblock = this->block_->get_backend(&context); + tree code = block_to_tree(bblock); tree init = NULL_TREE; tree except = NULL_TREE; @@ -1681,95 +1683,6 @@ Function::return_value(Gogo* gogo, Named_object* named_function, } } -// Get a tree for the statements in a block. - -tree -Block::get_tree(Translate_context* context) -{ - Gogo* gogo = context->gogo(); - - tree block = make_node(BLOCK); - - // Put the new block into the block tree. - - if (context->block() == NULL) - { - tree fndecl; - if (context->function() != NULL) - fndecl = context->function()->func_value()->get_decl(); - else - fndecl = current_function_decl; - gcc_assert(fndecl != NULL_TREE); - - // We may have already created a block for the receiver. - if (DECL_INITIAL(fndecl) == NULL_TREE) - { - BLOCK_SUPERCONTEXT(block) = fndecl; - DECL_INITIAL(fndecl) = block; - } - else - { - tree superblock_tree = DECL_INITIAL(fndecl); - BLOCK_SUPERCONTEXT(block) = superblock_tree; - gcc_assert(BLOCK_CHAIN(block) == NULL_TREE); - BLOCK_CHAIN(block) = block; - } - } - else - { - tree superblock_tree = context->block_tree(); - BLOCK_SUPERCONTEXT(block) = superblock_tree; - tree* pp; - for (pp = &BLOCK_SUBBLOCKS(superblock_tree); - *pp != NULL_TREE; - pp = &BLOCK_CHAIN(*pp)) - ; - *pp = block; - } - - // Expand local variables in the block. - - tree* pp = &BLOCK_VARS(block); - for (Bindings::const_definitions_iterator pv = - this->bindings_->begin_definitions(); - pv != this->bindings_->end_definitions(); - ++pv) - { - if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter()) - { - Bvariable* var = (*pv)->get_backend_variable(gogo, - context->function()); - *pp = var_to_tree(var); - if (*pp != error_mark_node) - pp = &DECL_CHAIN(*pp); - } - } - *pp = NULL_TREE; - - Translate_context subcontext(gogo, context->function(), this, block); - - tree statements = NULL_TREE; - - // Expand the statements. - - for (std::vector::const_iterator p = this->statements_.begin(); - p != this->statements_.end(); - ++p) - { - tree statement = (*p)->get_tree(&subcontext); - if (statement != error_mark_node) - append_to_statement_list(statement, &statements); - } - - TREE_USED(block) = 1; - - tree bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), statements, - block); - TREE_SIDE_EFFECTS(bind) = 1; - - return bind; -} - // Return the integer type to use for a size. GO_EXTERN_C diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 8f0d3288694..be945c5ced9 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -3285,6 +3285,48 @@ Block::may_fall_through() const return this->statements_.back()->may_fall_through(); } +// Convert a block to the backend representation. + +Bblock* +Block::get_backend(Translate_context* context) +{ + Gogo* gogo = context->gogo(); + Named_object* function = context->function(); + std::vector vars; + vars.reserve(this->bindings_->size_definitions()); + for (Bindings::const_definitions_iterator pv = + this->bindings_->begin_definitions(); + pv != this->bindings_->end_definitions(); + ++pv) + { + if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter()) + vars.push_back((*pv)->get_backend_variable(gogo, function)); + } + + // FIXME: Permitting FUNCTION to be NULL here is a temporary measure + // until we have a proper representation of the init function. + Bfunction* bfunction; + if (function == NULL) + bfunction = NULL; + else + bfunction = tree_to_function(function->func_value()->get_decl()); + Bblock* ret = context->backend()->block(bfunction, context->bblock(), + vars, this->start_location_, + this->end_location_); + + Translate_context subcontext(gogo, function, this, ret); + std::vector bstatements; + bstatements.reserve(this->statements_.size()); + for (std::vector::const_iterator p = this->statements_.begin(); + p != this->statements_.end(); + ++p) + bstatements.push_back(tree_to_stat((*p)->get_tree(&subcontext))); + + context->backend()->block_add_statements(ret, bstatements); + + return ret; +} + // Class Variable. Variable::Variable(Type* type, Expression* init, bool is_global, diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index cb6501e38ce..f9eba50ec2e 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -43,6 +43,7 @@ class Export; class Import; class Bexpression; class Bstatement; +class Bblock; class Bvariable; class Blabel; @@ -767,9 +768,9 @@ class Block bool may_fall_through() const; - // Return a tree of the code in this block. - tree - get_tree(Translate_context*); + // Convert the block to the backend representation. + Bblock* + get_backend(Translate_context*); // Iterate over statements. @@ -2507,9 +2508,9 @@ class Translate_context { public: Translate_context(Gogo* gogo, Named_object* function, Block* block, - tree block_tree) + Bblock* bblock) : gogo_(gogo), backend_(gogo->backend()), function_(function), - block_(block), block_tree_(block_tree), is_const_(false) + block_(block), bblock_(bblock), is_const_(false) { } // Accessors. @@ -2530,9 +2531,9 @@ class Translate_context block() { return this->block_; } - tree - block_tree() - { return this->block_tree_; } + Bblock* + bblock() + { return this->bblock_; } bool is_const() @@ -2548,12 +2549,15 @@ class Translate_context Gogo* gogo_; // The generator for the backend data structures. Backend* backend_; - // The function we are currently translating. + // The function we are currently translating. NULL if not in a + // function, e.g., the initializer of a global variable. Named_object* function_; - // The block we are currently translating. + // The block we are currently translating. NULL if not in a + // function. Block *block_; - // The BLOCK node for the current block. - tree block_tree_; + // The backend representation of the current block. NULL if block_ + // is NULL. + Bblock* bblock_; // Whether this is being evaluated in a constant context. This is // used for type descriptor initializers. bool is_const_; diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index fde3f62e3fc..7c6ccb989f5 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -428,12 +428,14 @@ Temporary_statement::do_get_tree(Translate_context* context) gcc_assert(current_function_decl != NULL_TREE); DECL_CONTEXT(decl) = current_function_decl; - // We have to add this variable to the block so that it winds up - // in a BIND_EXPR. - tree block_tree = context->block_tree(); - gcc_assert(block_tree != NULL_TREE); + // 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; } @@ -1518,13 +1520,22 @@ class Block_statement : public Statement { return this->block_->may_fall_through(); } tree - do_get_tree(Translate_context* context) - { return this->block_->get_tree(context); } + do_get_tree(Translate_context* context); private: Block* block_; }; +// Convert a block to the backend representation of a statement. + +tree +Block_statement::do_get_tree(Translate_context* context) +{ + Bblock* bblock = this->block_->get_backend(context); + Bstatement* ret = context->backend()->block_statement(bblock); + return stat_to_tree(ret); +} + // Make a block statement. Statement* @@ -2767,19 +2778,14 @@ If_statement::do_get_tree(Translate_context* context) gcc_assert(this->cond_->type()->is_boolean_type() || this->cond_->type()->is_error()); tree cond_tree = this->cond_->get_tree(context); - tree then_tree = this->then_block_->get_tree(context); - tree else_tree = (this->else_block_ == NULL - ? NULL_TREE - : this->else_block_->get_tree(context)); - + Bblock* then_block = this->then_block_->get_backend(context); + Bblock* else_block = (this->else_block_ == NULL + ? NULL + : this->else_block_->get_backend(context)); Bexpression* cond_expr = tree_to_expr(cond_tree); - Bstatement* then_stat = tree_to_stat(then_tree); - Bstatement* else_stat = (else_tree == NULL_TREE - ? NULL - : tree_to_stat(else_tree)); - Bstatement* ret = context->backend()->if_statement(cond_expr, then_stat, - else_stat, + Bstatement* ret = context->backend()->if_statement(cond_expr, then_block, + else_block, this->location()); return stat_to_tree(ret); } @@ -3056,7 +3062,10 @@ Case_clauses::Case_clause::get_backend(Translate_context* context, if (this->statements_ == NULL) statements = NULL; else - statements = tree_to_stat(this->statements_->get_tree(context)); + { + Bblock* bblock = this->statements_->get_backend(context); + statements = context->backend()->block_statement(bblock); + } Bstatement* break_stat; if (this->is_fallthrough_) @@ -4070,7 +4079,8 @@ Select_clauses::Select_clause::get_statements_backend( { if (this->statements_ == NULL) return NULL; - return tree_to_stat(this->statements_->get_tree(context)); + Bblock* bblock = this->statements_->get_backend(context); + return context->backend()->block_statement(bblock); } // Class Select_clauses. diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 1143376e4b3..da22947cb21 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -4470,7 +4470,7 @@ Array_type::get_length_tree(Gogo* gogo) // Make up a translation context for the array length // expression. FIXME: This won't work in general. - Translate_context context(gogo, NULL, NULL, NULL_TREE); + Translate_context context(gogo, NULL, NULL, NULL); tree len = this->length_->get_tree(&context); if (len != error_mark_node) { -- 2.11.0