From e09ce6c5bc057b933d34bd9e9674fd2b3b622190 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 19 Apr 2011 04:23:00 +0000 Subject: [PATCH] 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 --- gcc/go/ChangeLog | 13 ++ gcc/go/Make-lang.in | 5 +- gcc/go/go-gcc.cc | 159 +++++++++++++++ gcc/go/gofrontend/backend.h | 62 ++++++ gcc/go/gofrontend/expressions.cc | 19 +- gcc/go/gofrontend/gogo-tree.cc | 326 ++++++++++--------------------- gcc/go/gofrontend/gogo.cc | 109 ++++++++++- gcc/go/gofrontend/gogo.h | 32 ++- gcc/go/gofrontend/statements.cc | 69 ++++--- 9 files changed, 532 insertions(+), 262 deletions(-) diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index b6f91c45edc..141728ba7dc 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,16 @@ +2011-04-18 Ian Lance Taylor + + * 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 * go-gcc.cc (Gcc_backend::compound_statement): New function. diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index c20cebdec4e..c0b279d3513 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -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) \ diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 6cd402ec854..e4f4cfcd951 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -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: @@ -173,6 +183,9 @@ class Gcc_backend : public Backend Bstatement* expression_statement(Bexpression*); + Bstatement* + init_statement(Bvariable* var, Bexpression* init); + Bstatement* assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location); @@ -196,6 +209,32 @@ class Gcc_backend : public Backend Bstatement* statement_list(const std::vector&); + // 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& 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(); +} diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index bd761bda2be..3e4c6291fd6 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 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&) = 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) diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 5b72c6a0661..9adcbc33b65 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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. diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index ea4663953d8..a59076e8257 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -32,6 +32,7 @@ extern "C" #include "expressions.h" #include "statements.h" #include "runtime.h" +#include "backend.h" #include "gogo.h" // Whether we have seen any errors. @@ -277,7 +278,8 @@ Gogo::register_gc_vars(const std::vector& var_gc, constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL); tree field = TYPE_FIELDS(root_type); elt->index = field; - tree decl = (*p)->get_tree(this, NULL); + Bvariable* bvar = (*p)->get_backend_variable(this, NULL); + tree decl = var_to_tree(bvar); gcc_assert(TREE_CODE(decl) == VAR_DECL); elt->value = build_fold_addr_expr(decl); @@ -704,24 +706,31 @@ Gogo::write_globals() } } - vec[i] = no->get_tree(this, NULL); - - if (vec[i] == error_mark_node) + if (!no->is_variable()) { - gcc_assert(saw_errors()); - --i; - --count; - continue; + vec[i] = no->get_tree(this, NULL); + if (vec[i] == error_mark_node) + { + gcc_assert(saw_errors()); + --i; + --count; + continue; + } } - - // If a variable is initialized to a non-constant value, do the - // initialization in an initialization function. - if (TREE_CODE(vec[i]) == VAR_DECL) + else { - gcc_assert(no->is_variable()); + Bvariable* var = no->get_backend_variable(this, NULL); + vec[i] = var_to_tree(var); + if (vec[i] == error_mark_node) + { + gcc_assert(saw_errors()); + --i; + --count; + continue; + } - // Check for a sink variable, which may be used to run - // an initializer purely for its side effects. + // Check for a sink variable, which may be used to run an + // initializer purely for its side effects. bool is_sink = no->name()[0] == '_' && no->name()[1] == '.'; tree var_init_tree = NULL_TREE; @@ -733,7 +742,8 @@ Gogo::write_globals() else if (init == NULL_TREE) ; else if (TREE_CONSTANT(init)) - DECL_INITIAL(vec[i]) = init; + this->backend()->global_variable_set_init(var, + tree_to_expr(init)); else if (is_sink) var_init_tree = init; else @@ -828,16 +838,15 @@ Gogo::write_globals() tree Named_object::get_id(Gogo* gogo) { + gcc_assert(!this->is_variable() && !this->is_result_variable()); std::string decl_name; if (this->is_function_declaration() && !this->func_declaration_value()->asm_name().empty()) decl_name = this->func_declaration_value()->asm_name(); - else if ((this->is_variable() && !this->var_value()->is_global()) - || (this->is_type() - && this->type_value()->location() == BUILTINS_LOCATION)) + else if (this->is_type() + && this->type_value()->location() == BUILTINS_LOCATION) { - // We don't need the package name for local variables or builtin - // types. + // We don't need the package name for builtin types. decl_name = Gogo::unpack_hidden_name(this->name_); } else @@ -878,22 +887,7 @@ tree Named_object::get_tree(Gogo* gogo, Named_object* function) { if (this->tree_ != NULL_TREE) - { - // If this is a variable whose address is taken, we must rebuild - // the INDIRECT_REF each time to avoid invalid sharing. - tree ret = this->tree_; - if (((this->classification_ == NAMED_OBJECT_VAR - && this->var_value()->is_in_heap()) - || (this->classification_ == NAMED_OBJECT_RESULT_VAR - && this->result_var_value()->is_in_heap())) - && ret != error_mark_node) - { - gcc_assert(TREE_CODE(ret) == INDIRECT_REF); - ret = build_fold_indirect_ref(TREE_OPERAND(ret, 0)); - TREE_THIS_NOTRAP(ret) = 1; - } - return ret; - } + return this->tree_; tree name; if (this->classification_ == NAMED_OBJECT_TYPE) @@ -976,117 +970,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function) return error_mark_node; case NAMED_OBJECT_VAR: - { - Variable* var = this->u_.var_value; - Type* type = var->type(); - if (type->is_error_type() - || (type->is_undefined() - && (!var->is_global() || this->package() == NULL))) - { - // Force the error for an undefined type, just in case. - type->base(); - decl = error_mark_node; - } - else - { - tree var_type = type->get_tree(gogo); - bool is_parameter = var->is_parameter(); - if (var->is_receiver() && type->points_to() == NULL) - is_parameter = false; - if (var->is_in_heap()) - { - is_parameter = false; - var_type = build_pointer_type(var_type); - } - decl = build_decl(var->location(), - is_parameter ? PARM_DECL : VAR_DECL, - name, var_type); - if (!var->is_global()) - { - tree fnid = function->get_id(gogo); - tree fndecl = function->func_value()->get_or_make_decl(gogo, - function, - fnid); - DECL_CONTEXT(decl) = fndecl; - } - if (is_parameter) - DECL_ARG_TYPE(decl) = TREE_TYPE(decl); - - if (var->is_global()) - { - const Package* package = this->package(); - if (package == NULL) - TREE_STATIC(decl) = 1; - else - DECL_EXTERNAL(decl) = 1; - if (!Gogo::is_hidden_name(this->name_)) - { - TREE_PUBLIC(decl) = 1; - std::string asm_name = (package == NULL - ? gogo->unique_prefix() - : package->unique_prefix()); - asm_name.append(1, '.'); - asm_name.append(IDENTIFIER_POINTER(name), - IDENTIFIER_LENGTH(name)); - tree asm_id = get_identifier_from_string(asm_name); - SET_DECL_ASSEMBLER_NAME(decl, asm_id); - } - } - - // FIXME: We should only set this for variables which are - // actually used somewhere. - TREE_USED(decl) = 1; - } - } - break; - case NAMED_OBJECT_RESULT_VAR: - { - Result_variable* result = this->u_.result_var_value; - Type* type = result->type(); - if (type->is_error()) - decl = error_mark_node; - else - { - gcc_assert(result->function() == function->func_value()); - source_location loc = function->location(); - tree result_type = type->get_tree(gogo); - tree init; - if (!result->is_in_heap()) - init = type->get_init_tree(gogo, false); - else - { - tree space = gogo->allocate_memory(type, - TYPE_SIZE_UNIT(result_type), - loc); - result_type = build_pointer_type(result_type); - tree subinit = type->get_init_tree(gogo, true); - if (subinit == NULL_TREE) - init = fold_convert_loc(loc, result_type, space); - else - { - space = save_expr(space); - space = fold_convert_loc(loc, result_type, space); - tree spaceref = build_fold_indirect_ref_loc(loc, space); - TREE_THIS_NOTRAP(spaceref) = 1; - tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node, - spaceref, subinit); - init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space), - set, space); - } - } - decl = build_decl(loc, VAR_DECL, name, result_type); - tree fnid = function->get_id(gogo); - tree fndecl = function->func_value()->get_or_make_decl(gogo, - function, - fnid); - DECL_CONTEXT(decl) = fndecl; - DECL_INITIAL(decl) = init; - TREE_USED(decl) = 1; - } - } - break; - case NAMED_OBJECT_SINK: gcc_unreachable(); @@ -1129,20 +1013,6 @@ Named_object::get_tree(Gogo* gogo, Named_object* function) tree ret = decl; - // If this is a local variable whose address is taken, then we - // actually store it in the heap. For uses of the variable we need - // to return a reference to that heap location. - if (((this->classification_ == NAMED_OBJECT_VAR - && this->var_value()->is_in_heap()) - || (this->classification_ == NAMED_OBJECT_RESULT_VAR - && this->result_var_value()->is_in_heap())) - && ret != error_mark_node) - { - gcc_assert(POINTER_TYPE_P(TREE_TYPE(ret))); - ret = build_fold_indirect_ref(ret); - TREE_THIS_NOTRAP(ret) = 1; - } - this->tree_ = ret; if (ret != error_mark_node) @@ -1162,7 +1032,9 @@ Variable::get_init_tree(Gogo* gogo, Named_object* function) if (this->init_ == NULL) { gcc_assert(!this->is_parameter_); - return this->type_->get_init_tree(gogo, this->is_global_); + return this->type_->get_init_tree(gogo, + (this->is_global_ + || this->is_in_heap())); } else { @@ -1301,7 +1173,9 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) { push_struct_function(decl); - tree closure_decl = this->closure_var_->get_tree(gogo, no); + Bvariable* bvar = this->closure_var_->get_backend_variable(gogo, + no); + tree closure_decl = var_to_tree(bvar); if (closure_decl == error_mark_node) this->fndecl_ = error_mark_node; else @@ -1384,26 +1258,15 @@ Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl) { if (var_decl == error_mark_node) return error_mark_node; - // If the function takes the address of a receiver which is passed - // by value, then we will have an INDIRECT_REF here. We need to get - // the real variable. + gcc_assert(TREE_CODE(var_decl) == VAR_DECL); + tree val_type = TREE_TYPE(var_decl); bool is_in_heap = no->var_value()->is_in_heap(); - tree val_type; - if (TREE_CODE(var_decl) != INDIRECT_REF) - { - gcc_assert(!is_in_heap); - val_type = TREE_TYPE(var_decl); - } - else + if (is_in_heap) { - gcc_assert(is_in_heap); - var_decl = TREE_OPERAND(var_decl, 0); - if (var_decl == error_mark_node) - return error_mark_node; - gcc_assert(POINTER_TYPE_P(TREE_TYPE(var_decl))); - val_type = TREE_TYPE(TREE_TYPE(var_decl)); + gcc_assert(POINTER_TYPE_P(val_type)); + val_type = TREE_TYPE(val_type); } - gcc_assert(TREE_CODE(var_decl) == VAR_DECL); + source_location loc = DECL_SOURCE_LOCATION(var_decl); std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl)); name += ".pointer"; @@ -1456,14 +1319,8 @@ Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl) // indirection. tree -Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree ref) +Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl) { - if (ref == error_mark_node) - return error_mark_node; - - gcc_assert(TREE_CODE(ref) == INDIRECT_REF); - - tree var_decl = TREE_OPERAND(ref, 0); if (var_decl == error_mark_node) return error_mark_node; gcc_assert(TREE_CODE(var_decl) == VAR_DECL); @@ -1514,7 +1371,8 @@ Function::build_tree(Gogo* gogo, Named_object* named_function) { if ((*p)->is_variable() && (*p)->var_value()->is_parameter()) { - *pp = (*p)->get_tree(gogo, named_function); + Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); + *pp = var_to_tree(bvar); // We always pass the receiver to a method as a pointer. If // the receiver is declared as a non-pointer type, then we @@ -1524,8 +1382,6 @@ Function::build_tree(Gogo* gogo, Named_object* named_function) { tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp); tree var = *pp; - if (TREE_CODE(var) == INDIRECT_REF) - var = TREE_OPERAND(var, 0); if (var != error_mark_node) { gcc_assert(TREE_CODE(var) == VAR_DECL); @@ -1539,16 +1395,12 @@ Function::build_tree(Gogo* gogo, Named_object* named_function) // If we take the address of a parameter, then we need // to copy it into the heap. tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp); - if (*pp != error_mark_node) + tree var = *pp; + if (var != error_mark_node) { - gcc_assert(TREE_CODE(*pp) == INDIRECT_REF); - tree var_decl = TREE_OPERAND(*pp, 0); - if (var_decl != error_mark_node) - { - gcc_assert(TREE_CODE(var_decl) == VAR_DECL); - DECL_CHAIN(var_decl) = declare_vars; - declare_vars = var_decl; - } + gcc_assert(TREE_CODE(var) == VAR_DECL); + DECL_CHAIN(var) = declare_vars; + declare_vars = var; } *pp = parm_decl; } @@ -1561,16 +1413,41 @@ Function::build_tree(Gogo* gogo, Named_object* named_function) } else if ((*p)->is_result_variable()) { - tree var_decl = (*p)->get_tree(gogo, named_function); - if (var_decl != error_mark_node - && (*p)->result_var_value()->is_in_heap()) + Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); + tree var_decl = var_to_tree(bvar); + + Type* type = (*p)->result_var_value()->type(); + tree init; + if (!(*p)->result_var_value()->is_in_heap()) + init = type->get_init_tree(gogo, false); + else { - gcc_assert(TREE_CODE(var_decl) == INDIRECT_REF); - var_decl = TREE_OPERAND(var_decl, 0); + source_location loc = (*p)->location(); + tree type_tree = type->get_tree(gogo); + tree space = gogo->allocate_memory(type, + TYPE_SIZE_UNIT(type_tree), + loc); + tree ptr_type_tree = build_pointer_type(type_tree); + tree subinit = type->get_init_tree(gogo, true); + if (subinit == NULL_TREE) + init = fold_convert_loc(loc, ptr_type_tree, space); + else + { + space = save_expr(space); + space = fold_convert_loc(loc, ptr_type_tree, space); + tree spaceref = build_fold_indirect_ref_loc(loc, space); + TREE_THIS_NOTRAP(spaceref) = 1; + tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node, + spaceref, subinit); + init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space), + set, space); + } } + if (var_decl != error_mark_node) { gcc_assert(TREE_CODE(var_decl) == VAR_DECL); + DECL_INITIAL(var_decl) = init; DECL_CHAIN(var_decl) = declare_vars; declare_vars = var_decl; } @@ -1769,7 +1646,15 @@ Function::return_value(Gogo* gogo, Named_object* named_function, tree retval; if (results->size() == 1) - return this->results_->front()->get_tree(gogo, named_function); + { + Bvariable* bvar = + this->results_->front()->get_backend_variable(gogo, + named_function); + tree ret = var_to_tree(bvar); + if (this->results_->front()->result_var_value()->is_in_heap()) + ret = build_fold_indirect_ref_loc(location, ret); + return ret; + } else { tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_)); @@ -1781,8 +1666,11 @@ Function::return_value(Gogo* gogo, Named_object* named_function, ++pr, ++index, field = DECL_CHAIN(field)) { gcc_assert(field != NULL); - tree val; - val = (*this->results_)[index]->get_tree(gogo, named_function); + Named_object* no = (*this->results_)[index]; + Bvariable* bvar = no->get_backend_variable(gogo, named_function); + tree val = var_to_tree(bvar); + if (no->result_var_value()->is_in_heap()) + val = build_fold_indirect_ref_loc(location, val); tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node, build3(COMPONENT_REF, TREE_TYPE(field), retval, field, NULL_TREE), @@ -1847,28 +1735,18 @@ Block::get_tree(Translate_context* context) pv != this->bindings_->end_definitions(); ++pv) { - if ((!(*pv)->is_variable() || !(*pv)->var_value()->is_parameter()) - && !(*pv)->is_result_variable() - && !(*pv)->is_const()) + if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter()) { - tree var = (*pv)->get_tree(gogo, context->function()); - if (var != error_mark_node && TREE_TYPE(var) != error_mark_node) - { - if ((*pv)->is_variable() && (*pv)->var_value()->is_in_heap()) - { - gcc_assert(TREE_CODE(var) == INDIRECT_REF); - var = TREE_OPERAND(var, 0); - gcc_assert(TREE_CODE(var) == VAR_DECL); - } - *pp = var; - pp = &DECL_CHAIN(*pp); - } + 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(context->gogo(), context->function(), - this, block); + Translate_context subcontext(gogo, context->function(), this, block); tree statements = NULL_TREE; diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 91a7526aece..8f0d3288694 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -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) diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index b622d049e05..cb6501e38ce 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 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*); diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 8e00d37b291..fde3f62e3fc 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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); } -- 2.30.2