From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22883 invoked by alias); 26 Apr 2014 03:38:48 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Received: (qmail 22872 invoked by uid 89); 26 Apr 2014 03:38:48 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-3.0 required=5.0 tests=AWL,BAYES_00,KAM_ADVERT2,RCVD_IN_DNSWL_LOW,RP_MATCHES_RCVD,SPF_PASS,T_TVD_MIME_NO_HEADERS autolearn=ham version=3.3.2 X-HELO: mail-ie0-f172.google.com Received: from mail-ie0-f172.google.com (HELO mail-ie0-f172.google.com) (209.85.223.172) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Sat, 26 Apr 2014 03:38:41 +0000 Received: by mail-ie0-f172.google.com with SMTP id at1so1222918iec.3 for ; Fri, 25 Apr 2014 20:38:39 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:from:to:subject:date:message-id:user-agent :mime-version:content-type; bh=qDEfsLeIqd+FmJtJFKXYfXdjiTwFJGjFpJ5tvTXWw/o=; b=NlxS/6a5S777OSjWC8DKr0EmKP8+aOZG2CDb51Y3xPxhthMcvvFvT05nVESjWNdNGT +2UzyQ609YwTt1BABbsoGuV7on4GaXzxwroJXg2pLzBGGGqPVVb6SMxKrFRPn46c79IJ nvOXWVDa6QCj+IHfQix02Uw6wETyVtVNzofsT2nEMCJNg51DtlD1Qa2ZrRlvEp3jjGTV DPvwf7wLsnTir3iCK5kllB8xx4unL6Nj5heXjiHWMTYoLeiD9nL0rI/XLtRTi1ub/Gf+ w15H19dANE5KVU3NaJn/xdQcNaCXb6+Rk6JosKl4b1LtXD/C4Puzc4mNdDH12Fm37Q+5 RHpQ== X-Gm-Message-State: ALoCoQkL0wUc7Gp/IyJPNLxK3o0kx83K8g7wvTQPw76p9JEKeu0GvRSnB3nS+wUN04mobLnuTB5k/SiBhSat0nluyZ2esBbYfPdF7ZxIG2G72mCXkTiCLbqUypdhhHnu8x31IDHVQKRsAdPIDGH48AlNh7qPtOG5si+h74U+fnqUs/nqvGXGsYObQAu+pEQKgez1oXaFzemqyvtwnOuOy1GsCmhA0QhmEg== X-Received: by 10.50.47.12 with SMTP id z12mr9180917igm.37.1398483519596; Fri, 25 Apr 2014 20:38:39 -0700 (PDT) Received: from iant-glaptop.roam.corp.google.com.google.com ([12.69.21.253]) by mx.google.com with ESMTPSA id ie20sm2279994igb.10.2014.04.25.20.38.38 for (version=TLSv1.2 cipher=RC4-SHA bits=128/128); Fri, 25 Apr 2014 20:38:38 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: Go patch committed: Use backend interface for global decls Date: Sat, 26 Apr 2014 06:22:00 -0000 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.3 (gnu/linux) MIME-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" X-IsSubscribed: yes X-SW-Source: 2014-04/txt/msg01735.txt.bz2 --=-=-= Content-length: 735 This patch from Chris Manghane changes the Go frontend to use the backend interface for global declarations. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu. Committed to mainline. Ian 2014-04-25 Chris Manghane * go-gcc.cc: Include "cgraph.h" and "gimplify.h". (Gcc_backend::return_statement): Push and pop function. (Gcc_backend::label): Likewise. (Gcc_backend::function_defer_statement): Likewise. (Gcc_backend::switch_statement): Add function parameter. (Gcc_backend::block): Don't permit function to be NULL. (Gcc_backend::temporary_variable): Change go_assert to gcc_assert. (Gcc_backend::gc_root_variable): New function. (Gcc_backend::write_global_definitions): New function. --=-=-= Content-Type: text/x-diff Content-Disposition: inline; filename=foo.patch Content-Description: patch Content-length: 82475 Index: gcc/go/gofrontend/gogo.h =================================================================== --- gcc/go/gofrontend/gogo.h (revision 209665) +++ gcc/go/gofrontend/gogo.h (working copy) @@ -44,6 +44,7 @@ class Backend; class Export; class Import; class Bexpression; +class Btype; class Bstatement; class Bblock; class Bvariable; @@ -591,11 +592,6 @@ class Gogo Expression* runtime_error(int code, Location); - // Build a builtin struct with a list of fields. - static tree - builtin_struct(tree* ptype, const char* struct_name, tree struct_type, - int nfields, ...); - // Mark a function declaration as a builtin library function. static void mark_fndecl_as_builtin_library(tree fndecl); @@ -650,17 +646,18 @@ class Gogo Named_object* initialization_function_decl(); - // Write the magic initialization function. - void - write_initialization_function(Named_object* fndecl, tree init_stmt_list); + // Create the magic initialization function. + Named_object* + create_initialization_function(Named_object* fndecl, Bstatement* code_stmt); // Initialize imported packages. void - init_imports(tree*); + init_imports(std::vector&); // Register variables with the garbage collector. void - register_gc_vars(const std::vector&, tree*); + register_gc_vars(const std::vector&, + std::vector&); // Type used to map import names to packages. typedef std::map Imports; @@ -1086,7 +1083,7 @@ class Function get_or_make_decl(Gogo*, Named_object*); // Return the function's decl after it has been built. - tree + Bfunction* get_decl() const; // Set the function decl to hold a backend representation of the function @@ -1675,7 +1672,7 @@ class Named_constant Named_constant(Type* type, Expression* expr, int iota_value, Location location) : type_(type), expr_(expr), iota_value_(iota_value), location_(location), - lowering_(false), is_sink_(false) + lowering_(false), is_sink_(false), bconst_(NULL) { } Type* @@ -1737,6 +1734,10 @@ class Named_constant static void import_const(Import*, std::string*, Type**, Expression**); + // Get the backend representation of the constant value. + Bexpression* + get_backend(Gogo*, Named_object*); + private: // The type of the constant. Type* type_; @@ -1754,6 +1755,8 @@ class Named_constant bool lowering_; // Whether this constant is blank named and needs only type checking. bool is_sink_; + // The backend representation of the constant value. + Bexpression* bconst_; }; // A type declaration. @@ -2176,9 +2179,10 @@ class Named_object std::string get_id(Gogo*); - // Return a tree representing this object. - tree - get_tree(Gogo*, Named_object* function); + // Get the backend representation of this object. + void + get_backend(Gogo*, std::vector&, std::vector&, + std::vector&); // Define a type declaration. void @@ -2219,8 +2223,6 @@ class Named_object Function_declaration* func_declaration_value; Package* package_value; } u_; - // The DECL tree for this object if we have already converted it. - tree tree_; }; // A binding contour. This binds names to objects. Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 209393) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -30,6 +30,7 @@ class Var_expression; class Temporary_reference_expression; class Set_and_use_temporary_expression; class String_expression; +class Unary_expression; class Binary_expression; class Call_expression; class Func_expression; @@ -327,6 +328,10 @@ class Expression static Expression* make_struct_composite_literal(Type*, Expression_list*, Location); + // Make an array composite literal. + static Expression* + make_array_composite_literal(Type*, Expression_list*, Location); + // Make a slice composite literal. static Expression* make_slice_composite_literal(Type*, Expression_list*, Location); @@ -533,6 +538,12 @@ class Expression Expression* deref(); + // If this is a unary expression, return the Unary_expression + // structure. Otherwise return NULL. + Unary_expression* + unary_expression() + { return this->convert(); } + // If this is a binary expression, return the Binary_expression // structure. Otherwise return NULL. Binary_expression* @@ -1286,6 +1297,143 @@ class String_expression : public Express Type* type_; }; +// A Unary expression. + +class Unary_expression : public Expression +{ + public: + Unary_expression(Operator op, Expression* expr, Location location) + : Expression(EXPRESSION_UNARY, location), + op_(op), escapes_(true), create_temp_(false), is_gc_root_(false), + expr_(expr), issue_nil_check_(false) + { } + + // Return the operator. + Operator + op() const + { return this->op_; } + + // Return the operand. + Expression* + operand() const + { return this->expr_; } + + // Record that an address expression does not escape. + void + set_does_not_escape() + { + go_assert(this->op_ == OPERATOR_AND); + this->escapes_ = false; + } + + // Record that this is an address expression which should create a + // temporary variable if necessary. This is used for method calls. + void + set_create_temp() + { + go_assert(this->op_ == OPERATOR_AND); + this->create_temp_ = true; + } + + // Record that this is an address expression of a GC root, which is a + // mutable composite literal. This used for registering GC variables. + void + set_is_gc_root() + { + go_assert(this->op_ == OPERATOR_AND); + this->is_gc_root_ = true; + } + + // Apply unary opcode OP to UNC, setting NC. Return true if this + // could be done, false if not. Issue errors for overflow. + static bool + eval_constant(Operator op, const Numeric_constant* unc, + Location, Numeric_constant* nc); + + static Expression* + do_import(Import*); + + protected: + int + do_traverse(Traverse* traverse) + { return Expression::traverse(&this->expr_, traverse); } + + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int); + + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + + bool + do_is_constant() const; + + bool + do_is_immutable() const + { + return (this->expr_->is_immutable() + || (this->op_ == OPERATOR_AND && this->expr_->is_variable())); + } + + bool + do_numeric_constant_value(Numeric_constant*) const; + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return Expression::make_unary(this->op_, this->expr_->copy(), + this->location()); + } + + bool + do_must_eval_subexpressions_in_order(int*) const + { return this->op_ == OPERATOR_MULT; } + + bool + do_is_addressable() const + { return this->op_ == OPERATOR_MULT; } + + tree + do_get_tree(Translate_context*); + + void + do_export(Export*) const; + + void + do_dump_expression(Ast_dump_context*) const; + + void + do_issue_nil_check() + { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); } + + private: + // The unary operator to apply. + Operator op_; + // Normally true. False if this is an address expression which does + // not escape the current function. + bool escapes_; + // True if this is an address expression which should create a + // temporary variable if necessary. + bool create_temp_; + // True if this is an address expression for a GC root. A GC root is a + // special struct composite literal that is mutable when addressed, meaning + // it cannot be represented as an immutable_struct in the backend. + bool is_gc_root_; + // The operand. + Expression* expr_; + // Whether or not to issue a nil check for this expression if its address + // is being taken. + bool issue_nil_check_; +}; + // A binary expression. class Binary_expression : public Expression Index: gcc/go/gofrontend/statements.cc =================================================================== --- gcc/go/gofrontend/statements.cc (revision 209393) +++ gcc/go/gofrontend/statements.cc (working copy) @@ -434,15 +434,9 @@ Temporary_statement::do_get_backend(Tran { go_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()); - + go_assert(function != NULL); + Bfunction* bfunction = function->func_value()->get_decl(); Btype* btype = this->type()->get_backend(context->gogo()); Bexpression* binit; @@ -2781,8 +2775,6 @@ Return_statement::do_get_backend(Transla Location loc = this->location(); Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - Function::Results* results = function->result_variables(); std::vector retvals; if (results != NULL && !results->empty()) @@ -2797,7 +2789,7 @@ Return_statement::do_get_backend(Transla } } - return context->backend()->return_statement(tree_to_function(fndecl), + return context->backend()->return_statement(function->get_decl(), retvals, loc); } @@ -3803,8 +3795,10 @@ Constant_switch_statement::do_get_backen this->clauses_->get_backend(context, break_label, &all_cases, &all_statements); + Bfunction* bfunction = context->function()->func_value()->get_decl(); Bstatement* switch_statement; - switch_statement = context->backend()->switch_statement(switch_val_expr, + switch_statement = context->backend()->switch_statement(bfunction, + switch_val_expr, all_cases, all_statements, this->location()); @@ -4980,7 +4974,9 @@ Select_clauses::get_backend(Translate_co std::vector statements; statements.reserve(2); - Bstatement* switch_stmt = context->backend()->switch_statement(bcall, + Bfunction* bfunction = context->function()->func_value()->get_decl(); + Bstatement* switch_stmt = context->backend()->switch_statement(bfunction, + bcall, cases, clauses, location); Index: gcc/go/gofrontend/gogo-tree.cc =================================================================== --- gcc/go/gofrontend/gogo-tree.cc (revision 209665) +++ gcc/go/gofrontend/gogo-tree.cc (working copy) @@ -236,830 +236,6 @@ Gogo::define_builtin_function_trees() false); } -// Add statements to INIT_STMT_LIST which run the initialization -// functions for imported packages. This is only used for the "main" -// package. - -void -Gogo::init_imports(tree* init_stmt_list) -{ - go_assert(this->is_main_package()); - - if (this->imported_init_fns_.empty()) - return; - - tree fntype = build_function_type(void_type_node, void_list_node); - - // We must call them in increasing priority order. - std::vector v; - for (std::set::const_iterator p = - this->imported_init_fns_.begin(); - p != this->imported_init_fns_.end(); - ++p) - v.push_back(*p); - std::sort(v.begin(), v.end()); - - for (std::vector::const_iterator p = v.begin(); - p != v.end(); - ++p) - { - std::string user_name = p->package_name() + ".init"; - tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL, - get_identifier_from_string(user_name), - fntype); - const std::string& init_name(p->init_name()); - SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name)); - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - append_to_statement_list(build_call_expr(decl, 0), init_stmt_list); - } -} - -// Register global variables with the garbage collector. We need to -// register all variables which can hold a pointer value. They become -// roots during the mark phase. We build a struct that is easy to -// hook into a list of roots. - -// struct __go_gc_root_list -// { -// struct __go_gc_root_list* __next; -// struct __go_gc_root -// { -// void* __decl; -// size_t __size; -// } __roots[]; -// }; - -// The last entry in the roots array has a NULL decl field. - -void -Gogo::register_gc_vars(const std::vector& var_gc, - tree* init_stmt_list) -{ - if (var_gc.empty()) - return; - - size_t count = var_gc.size(); - - tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2, - "__next", - ptr_type_node, - "__size", - sizetype); - - tree index_type = build_index_type(size_int(count)); - tree array_type = build_array_type(root_type, index_type); - - tree root_list_type = make_node(RECORD_TYPE); - root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list", - root_list_type, 2, - "__next", - build_pointer_type(root_list_type), - "__roots", - array_type); - - // Build an initialier for the __roots array. - - vec *roots_init; - vec_alloc(roots_init, count + 1); - - size_t i = 0; - for (std::vector::const_iterator p = var_gc.begin(); - p != var_gc.end(); - ++p, ++i) - { - vec *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(root_type); - elt->index = field; - Bvariable* bvar = (*p)->get_backend_variable(this, NULL); - tree decl = var_to_tree(bvar); - go_assert(TREE_CODE(decl) == VAR_DECL); - elt->value = build_fold_addr_expr(decl); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = DECL_SIZE_UNIT(decl); - - elt = roots_init->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(root_type, init); - } - - // The list ends with a NULL entry. - - vec *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(root_type); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = size_zero_node; - - elt = roots_init->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(root_type, init); - - // Build a constructor for the struct. - - vec *root_list_init; - vec_alloc(root_list_init, 2); - - elt = root_list_init->quick_push(empty); - field = TYPE_FIELDS(root_list_type); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = root_list_init->quick_push(empty); - field = DECL_CHAIN(field); - elt->index = field; - elt->value = build_constructor(array_type, roots_init); - - // Build a decl to register. - - tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, - create_tmp_var_name("gc"), root_list_type); - DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = 0; - TREE_STATIC(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init); - rest_of_decl_compilation(decl, 1, 0); - - static tree register_gc_fndecl; - tree call = Gogo::call_builtin(®ister_gc_fndecl, - Linemap::predeclared_location(), - "__go_register_gc_roots", - 1, - void_type_node, - build_pointer_type(root_list_type), - build_fold_addr_expr(decl)); - if (call != error_mark_node) - append_to_statement_list(call, init_stmt_list); -} - -// Create the magic initialization function. INIT_STMT_LIST is the -// code that it needs to run. - -void -Gogo::write_initialization_function(Named_object* initfn, tree init_stmt_list) -{ - // Make sure that we thought we needed an initialization function, - // as otherwise we will not have reported it in the export data. - go_assert(this->is_main_package() || this->need_init_fn_); - - if (initfn == NULL) - initfn = this->initialization_function_decl(); - - Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn); - Location loc = this->package_->location(); - std::vector vars; - this->backend()->block(fndecl, NULL, vars, loc, loc); - - if (!this->backend()->function_set_body(fndecl, tree_to_stat(init_stmt_list))) - { - go_assert(saw_errors()); - return; - } - gimplify_function_tree(function_to_tree(fndecl)); - cgraph_add_new_function(function_to_tree(fndecl), false); -} - -// Search for references to VAR in any statements or called functions. - -class Find_var : public Traverse -{ - public: - // A hash table we use to avoid looping. The index is the name of a - // named object. We only look through objects defined in this - // package. - typedef Unordered_set(const void*) Seen_objects; - - Find_var(Named_object* var, Seen_objects* seen_objects) - : Traverse(traverse_expressions), - var_(var), seen_objects_(seen_objects), found_(false) - { } - - // Whether the variable was found. - bool - found() const - { return this->found_; } - - int - expression(Expression**); - - private: - // The variable we are looking for. - Named_object* var_; - // Names of objects we have already seen. - Seen_objects* seen_objects_; - // True if the variable was found. - bool found_; -}; - -// See if EXPR refers to VAR, looking through function calls and -// variable initializations. - -int -Find_var::expression(Expression** pexpr) -{ - Expression* e = *pexpr; - - Var_expression* ve = e->var_expression(); - if (ve != NULL) - { - Named_object* v = ve->named_object(); - if (v == this->var_) - { - this->found_ = true; - return TRAVERSE_EXIT; - } - - if (v->is_variable() && v->package() == NULL) - { - Expression* init = v->var_value()->init(); - if (init != NULL) - { - std::pair ins = - this->seen_objects_->insert(v); - if (ins.second) - { - // This is the first time we have seen this name. - if (Expression::traverse(&init, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - } - - // We traverse the code of any function we see. Note that this - // means that we will traverse the code of a function whose address - // is taken even if it is not called. - Func_expression* fe = e->func_expression(); - if (fe != NULL) - { - const Named_object* f = fe->named_object(); - if (f->is_function() && f->package() == NULL) - { - std::pair ins = - this->seen_objects_->insert(f); - if (ins.second) - { - // This is the first time we have seen this name. - if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - Temporary_reference_expression* tre = e->temporary_reference_expression(); - if (tre != NULL) - { - Temporary_statement* ts = tre->statement(); - Expression* init = ts->init(); - if (init != NULL) - { - std::pair ins = - this->seen_objects_->insert(ts); - if (ins.second) - { - // This is the first time we have seen this temporary - // statement. - if (Expression::traverse(&init, this) == TRAVERSE_EXIT) - return TRAVERSE_EXIT; - } - } - } - - return TRAVERSE_CONTINUE; -} - -// Return true if EXPR, PREINIT, or DEP refers to VAR. - -static bool -expression_requires(Expression* expr, Block* preinit, Named_object* dep, - Named_object* var) -{ - Find_var::Seen_objects seen_objects; - Find_var find_var(var, &seen_objects); - if (expr != NULL) - Expression::traverse(&expr, &find_var); - if (preinit != NULL) - preinit->traverse(&find_var); - if (dep != NULL) - { - Expression* init = dep->var_value()->init(); - if (init != NULL) - Expression::traverse(&init, &find_var); - if (dep->var_value()->has_pre_init()) - dep->var_value()->preinit()->traverse(&find_var); - } - - return find_var.found(); -} - -// Sort variable initializations. If the initialization expression -// for variable A refers directly or indirectly to the initialization -// expression for variable B, then we must initialize B before A. - -class Var_init -{ - public: - Var_init() - : var_(NULL), init_(NULL) - { } - - Var_init(Named_object* var, Bstatement* init) - : var_(var), init_(init) - { } - - // Return the variable. - Named_object* - var() const - { return this->var_; } - - // Return the initialization expression. - Bstatement* - init() const - { return this->init_; } - - private: - // The variable being initialized. - Named_object* var_; - // The initialization statement. - Bstatement* init_; -}; - -typedef std::list Var_inits; - -// Sort the variable initializations. The rule we follow is that we -// emit them in the order they appear in the array, except that if the -// initialization expression for a variable V1 depends upon another -// variable V2 then we initialize V1 after V2. - -static void -sort_var_inits(Gogo* gogo, Var_inits* var_inits) -{ - typedef std::pair No_no; - typedef std::map Cache; - Cache cache; - - Var_inits ready; - while (!var_inits->empty()) - { - Var_inits::iterator p1 = var_inits->begin(); - Named_object* var = p1->var(); - Expression* init = var->var_value()->init(); - Block* preinit = var->var_value()->preinit(); - Named_object* dep = gogo->var_depends_on(var->var_value()); - - // Start walking through the list to see which variables VAR - // needs to wait for. - Var_inits::iterator p2 = p1; - ++p2; - - for (; p2 != var_inits->end(); ++p2) - { - Named_object* p2var = p2->var(); - No_no key(var, p2var); - std::pair ins = - cache.insert(std::make_pair(key, false)); - if (ins.second) - ins.first->second = expression_requires(init, preinit, dep, p2var); - if (ins.first->second) - { - // Check for cycles. - key = std::make_pair(p2var, var); - ins = cache.insert(std::make_pair(key, false)); - if (ins.second) - ins.first->second = - expression_requires(p2var->var_value()->init(), - p2var->var_value()->preinit(), - gogo->var_depends_on(p2var->var_value()), - var); - if (ins.first->second) - { - error_at(var->location(), - ("initialization expressions for %qs and " - "%qs depend upon each other"), - var->message_name().c_str(), - p2var->message_name().c_str()); - inform(p2->var()->location(), "%qs defined here", - p2var->message_name().c_str()); - p2 = var_inits->end(); - } - else - { - // We can't emit P1 until P2 is emitted. Move P1. - Var_inits::iterator p3 = p2; - ++p3; - var_inits->splice(p3, *var_inits, p1); - } - break; - } - } - - if (p2 == var_inits->end()) - { - // VAR does not depends upon any other initialization expressions. - - // Check for a loop of VAR on itself. We only do this if - // INIT is not NULL and there is no dependency; when INIT is - // NULL, it means that PREINIT sets VAR, which we will - // interpret as a loop. - if (init != NULL && dep == NULL - && expression_requires(init, preinit, NULL, var)) - error_at(var->location(), - "initialization expression for %qs depends upon itself", - var->message_name().c_str()); - ready.splice(ready.end(), *var_inits, p1); - } - } - - // Now READY is the list in the desired initialization order. - var_inits->swap(ready); -} - -// Write out the global definitions. - -void -Gogo::write_globals() -{ - this->build_interface_method_tables(); - - Bindings* bindings = this->current_bindings(); - - for (Bindings::const_declarations_iterator p = bindings->begin_declarations(); - p != bindings->end_declarations(); - ++p) - { - // If any function declarations needed a descriptor, make sure - // we build it. - Named_object* no = p->second; - if (no->is_function_declaration()) - no->func_declaration_value()->build_backend_descriptor(this); - } - - size_t count_definitions = bindings->size_definitions(); - size_t count = count_definitions; - - tree* vec = new tree[count]; - - Named_object* init_fndecl = NULL; - tree init_stmt_list = NULL_TREE; - - if (this->is_main_package()) - this->init_imports(&init_stmt_list); - - // A list of variable initializations. - Var_inits var_inits; - - // A list of variables which need to be registered with the garbage - // collector. - std::vector var_gc; - var_gc.reserve(count); - - tree var_init_stmt_list = NULL_TREE; - size_t i = 0; - for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); - p != bindings->end_definitions(); - ++p, ++i) - { - Named_object* no = *p; - - go_assert(i < count); - - go_assert(!no->is_type_declaration() && !no->is_function_declaration()); - // There is nothing to do for a package. - if (no->is_package()) - { - --i; - --count; - continue; - } - - // There is nothing to do for an object which was imported from - // a different package into the global scope. - if (no->package() != NULL) - { - --i; - --count; - continue; - } - - // Skip blank named functions and constants. - if ((no->is_function() && no->func_value()->is_sink()) - || (no->is_const() && no->const_value()->is_sink())) - { - --i; - --count; - continue; - } - - // There is nothing useful we can output for constants which - // have ideal or non-integral type. - if (no->is_const()) - { - Type* type = no->const_value()->type(); - if (type == NULL) - type = no->const_value()->expr()->type(); - if (type->is_abstract() || type->integer_type() == NULL) - { - --i; - --count; - continue; - } - } - - if (!no->is_variable()) - { - vec[i] = no->get_tree(this, NULL); - if (vec[i] == error_mark_node) - { - go_assert(saw_errors()); - --i; - --count; - continue; - } - } - else - { - Bvariable* var = no->get_backend_variable(this, NULL); - vec[i] = var_to_tree(var); - if (vec[i] == error_mark_node) - { - go_assert(saw_errors()); - --i; - --count; - continue; - } - - // 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] == '.'; - - Bstatement* var_init_stmt = NULL; - if (!no->var_value()->has_pre_init()) - { - Bexpression* var_binit = no->var_value()->get_init(this, NULL); - if (var_binit == NULL) - ; - else if (TREE_CONSTANT(expr_to_tree(var_binit))) - { - if (expression_requires(no->var_value()->init(), NULL, - this->var_depends_on(no->var_value()), - no)) - error_at(no->location(), - "initialization expression for %qs depends " - "upon itself", - no->message_name().c_str()); - this->backend()->global_variable_set_init(var, var_binit); - } - else if (is_sink) - var_init_stmt = - this->backend()->expression_statement(var_binit); - else - { - Location loc = no->var_value()->location(); - Bexpression* var_expr = - this->backend()->var_expression(var, loc); - var_init_stmt = - this->backend()->assignment_statement(var_expr, var_binit, - loc); - } - } - else - { - // We are going to create temporary variables which - // means that we need an fndecl. - if (init_fndecl == NULL) - init_fndecl = this->initialization_function_decl(); - - Bvariable* var_decl = is_sink ? NULL : var; - var_init_stmt = - no->var_value()->get_init_block(this, init_fndecl, var_decl); - } - - if (var_init_stmt != NULL) - { - if (no->var_value()->init() == NULL - && !no->var_value()->has_pre_init()) - append_to_statement_list(stat_to_tree(var_init_stmt), - &var_init_stmt_list); - else - var_inits.push_back(Var_init(no, var_init_stmt)); - } - else if (this->var_depends_on(no->var_value()) != NULL) - { - // This variable is initialized from something that is - // not in its init or preinit. This variable needs to - // participate in dependency analysis sorting, in case - // some other variable depends on this one. - Btype* int_btype = - Type::lookup_integer_type("int")->get_backend(this); - Bexpression* zero = this->backend()->zero_expression(int_btype); - Bstatement* zero_stmt = - this->backend()->expression_statement(zero); - var_inits.push_back(Var_init(no, zero_stmt)); - } - - if (!is_sink && no->var_value()->type()->has_pointer()) - var_gc.push_back(no); - } - } - - // Register global variables with the garbage collector. - this->register_gc_vars(var_gc, &init_stmt_list); - - // Simple variable initializations, after all variables are - // registered. - append_to_statement_list(var_init_stmt_list, &init_stmt_list); - - // Complex variable initializations, first sorting them into a - // workable order. - if (!var_inits.empty()) - { - sort_var_inits(this, &var_inits); - for (Var_inits::const_iterator p = var_inits.begin(); - p != var_inits.end(); - ++p) - append_to_statement_list(stat_to_tree(p->init()), &init_stmt_list); - } - - // After all the variables are initialized, call the "init" - // functions if there are any. - for (std::vector::const_iterator p = - this->init_functions_.begin(); - p != this->init_functions_.end(); - ++p) - { - tree decl = (*p)->get_tree(this, NULL); - tree call = build_call_expr(decl, 0); - append_to_statement_list(call, &init_stmt_list); - } - - // Set up a magic function to do all the initialization actions. - // This will be called if this package is imported. - if (init_stmt_list != NULL - || this->need_init_fn_ - || this->is_main_package()) - this->write_initialization_function(init_fndecl, init_stmt_list); - - // We should not have seen any new bindings created during the - // conversion. - go_assert(count_definitions == this->current_bindings()->size_definitions()); - - // Pass everything back to the middle-end. - - wrapup_global_declarations(vec, count); - - finalize_compilation_unit(); - - check_global_declarations(vec, count); - emit_debug_global_declarations(vec, count); - - delete[] vec; -} - -// Get a tree for a named object. - -tree -Named_object::get_tree(Gogo* gogo, Named_object* function) -{ - if (this->tree_ != NULL_TREE) - return this->tree_; - - if (Gogo::is_erroneous_name(this->name_)) - { - this->tree_ = error_mark_node; - return error_mark_node; - } - - tree decl; - switch (this->classification_) - { - case NAMED_OBJECT_CONST: - { - Translate_context subcontext(gogo, function, NULL, NULL); - Type* type = this->u_.const_value->type(); - Location loc = this->location(); - - Expression* const_ref = Expression::make_const_reference(this, loc); - Bexpression* const_decl = - tree_to_expr(const_ref->get_tree(&subcontext)); - if (type != NULL && type->is_numeric_type()) - { - Btype* btype = type->get_backend(gogo); - std::string name = this->get_id(gogo); - const_decl = - gogo->backend()->named_constant_expression(btype, name, - const_decl, loc); - } - decl = expr_to_tree(const_decl); - } - break; - - case NAMED_OBJECT_TYPE: - { - Named_type* named_type = this->u_.type_value; - tree type_tree = type_to_tree(named_type->get_backend(gogo)); - if (type_tree == error_mark_node) - decl = error_mark_node; - else - { - decl = TYPE_NAME(type_tree); - go_assert(decl != NULL_TREE); - - // We need to produce a type descriptor for every named - // type, and for a pointer to every named type, since - // other files or packages might refer to them. We need - // to do this even for hidden types, because they might - // still be returned by some function. Simply calling the - // type_descriptor method is enough to create the type - // descriptor, even though we don't do anything with it. - if (this->package_ == NULL) - { - named_type-> - type_descriptor_pointer(gogo, - Linemap::predeclared_location()); - Type* pn = Type::make_pointer_type(named_type); - pn->type_descriptor_pointer(gogo, - Linemap::predeclared_location()); - } - } - } - break; - - case NAMED_OBJECT_TYPE_DECLARATION: - error("reference to undefined type %qs", - this->message_name().c_str()); - return error_mark_node; - - case NAMED_OBJECT_VAR: - case NAMED_OBJECT_RESULT_VAR: - case NAMED_OBJECT_SINK: - go_unreachable(); - - case NAMED_OBJECT_FUNC: - { - Function* func = this->u_.func_value; - decl = function_to_tree(func->get_or_make_decl(gogo, this)); - if (decl != error_mark_node) - { - if (func->block() != NULL) - { - if (DECL_STRUCT_FUNCTION(decl) == NULL) - push_struct_function(decl); - else - push_cfun(DECL_STRUCT_FUNCTION(decl)); - - cfun->function_start_locus = func->location().gcc_location(); - cfun->function_end_locus = - func->block()->end_location().gcc_location(); - - func->build(gogo, this); - - gimplify_function_tree(decl); - - cgraph_finalize_function(decl, true); - - pop_cfun(); - } - } - } - break; - - case NAMED_OBJECT_ERRONEOUS: - decl = error_mark_node; - break; - - default: - go_unreachable(); - } - - if (TREE_TYPE(decl) == error_mark_node) - decl = error_mark_node; - - tree ret = decl; - - this->tree_ = ret; - - if (ret != error_mark_node) - go_preserve_from_gc(ret); - - return ret; -} - // Get the backend representation. Bfunction* @@ -1106,15 +282,6 @@ Function_declaration::get_or_make_decl(G return this->fndecl_; } -// Return the function's decl after it has been built. - -tree -Function::get_decl() const -{ - go_assert(this->fndecl_ != NULL); - return function_to_tree(this->fndecl_); -} - // Build the descriptor for a function declaration. This won't // necessarily happen if the package has just a declaration for the // function and no other reference to it, but we may still need the @@ -1214,55 +381,6 @@ go_type_for_mode(enum machine_mode mode, return NULL_TREE; } -// Build a builtin struct with a list of fields. The name is -// STRUCT_NAME. STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE -// node; this exists so that the struct can have fields which point to -// itself. If PTYPE is not NULL, store the result in *PTYPE. There -// are NFIELDS fields. Each field is a name (a const char*) followed -// by a type (a tree). - -tree -Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type, - int nfields, ...) -{ - if (ptype != NULL && *ptype != NULL_TREE) - return *ptype; - - va_list ap; - va_start(ap, nfields); - - tree fields = NULL_TREE; - for (int i = 0; i < nfields; ++i) - { - const char* field_name = va_arg(ap, const char*); - tree type = va_arg(ap, tree); - if (type == error_mark_node) - { - if (ptype != NULL) - *ptype = error_mark_node; - return error_mark_node; - } - tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL, - get_identifier(field_name), type); - DECL_CHAIN(field) = fields; - fields = field; - } - - va_end(ap); - - if (struct_type == NULL_TREE) - struct_type = make_node(RECORD_TYPE); - finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE); - - if (ptype != NULL) - { - go_preserve_from_gc(struct_type); - *ptype = struct_type; - } - - return struct_type; -} - // Build a constructor for a slice. SLICE_TYPE_TREE is the type of // the slice. VALUES is the value pointer and COUNT is the number of // entries. If CAPACITY is not NULL, it is the capacity; otherwise Index: gcc/go/gofrontend/backend.h =================================================================== --- gcc/go/gofrontend/backend.h (revision 209495) +++ gcc/go/gofrontend/backend.h (working copy) @@ -406,9 +406,9 @@ class Backend // integers, then STATEMENTS[i] is executed. STATEMENTS[i] will // either end with a goto statement or will fall through into // STATEMENTS[i + 1]. CASES[i] is empty for the default clause, - // which need not be last. + // which need not be last. FUNCTION is the current function. virtual Bstatement* - switch_statement(Bexpression* value, + switch_statement(Bfunction* function, Bexpression* value, const std::vector >& cases, const std::vector& statements, Location) = 0; @@ -534,6 +534,12 @@ class Backend bool address_is_taken, Location location, Bstatement** pstatement) = 0; + // Create a GC root variable. TYPE is the __go_gc_root_list struct described + // in Gogo::register_gc_vars. INIT is the composite literal consisting of a + // pointer to the next GC root and the global variables registered. + virtual Bvariable* + gc_root_variable(Btype* type, Bexpression* init) = 0; + // Create a named immutable initialized data structure. This is // used for type descriptors, map descriptors, and function // descriptors. This returns a Bvariable because it corresponds to @@ -653,6 +659,16 @@ class Backend // true on success, false on failure. virtual bool function_set_body(Bfunction* function, Bstatement* code_stmt) = 0; + + // Utility. + + // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, + // FUNCTION_DECLS, and VARIABLE_DECLS declared globally. + virtual void + write_global_definitions(const std::vector& type_decls, + const std::vector& constant_decls, + const std::vector& function_decls, + const std::vector& variable_decls) = 0; }; // The backend interface has to define this function. Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 209495) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -3578,127 +3578,7 @@ Expression::make_unsafe_cast(Type* type, return new Unsafe_type_conversion_expression(type, expr, location); } -// Unary expressions. - -class Unary_expression : public Expression -{ - public: - Unary_expression(Operator op, Expression* expr, Location location) - : Expression(EXPRESSION_UNARY, location), - op_(op), escapes_(true), create_temp_(false), expr_(expr), - issue_nil_check_(false) - { } - - // Return the operator. - Operator - op() const - { return this->op_; } - - // Return the operand. - Expression* - operand() const - { return this->expr_; } - - // Record that an address expression does not escape. - void - set_does_not_escape() - { - go_assert(this->op_ == OPERATOR_AND); - this->escapes_ = false; - } - - // Record that this is an address expression which should create a - // temporary variable if necessary. This is used for method calls. - void - set_create_temp() - { - go_assert(this->op_ == OPERATOR_AND); - this->create_temp_ = true; - } - - // Apply unary opcode OP to UNC, setting NC. Return true if this - // could be done, false if not. Issue errors for overflow. - static bool - eval_constant(Operator op, const Numeric_constant* unc, - Location, Numeric_constant* nc); - - static Expression* - do_import(Import*); - - protected: - int - do_traverse(Traverse* traverse) - { return Expression::traverse(&this->expr_, traverse); } - - Expression* - do_lower(Gogo*, Named_object*, Statement_inserter*, int); - - Expression* - do_flatten(Gogo*, Named_object*, Statement_inserter*); - - bool - do_is_constant() const; - - bool - do_is_immutable() const - { return this->expr_->is_immutable() - || (this->op_ == OPERATOR_AND && this->expr_->is_variable()); } - - bool - do_numeric_constant_value(Numeric_constant*) const; - - Type* - do_type(); - - void - do_determine_type(const Type_context*); - - void - do_check_types(Gogo*); - - Expression* - do_copy() - { - return Expression::make_unary(this->op_, this->expr_->copy(), - this->location()); - } - - bool - do_must_eval_subexpressions_in_order(int*) const - { return this->op_ == OPERATOR_MULT; } - - bool - do_is_addressable() const - { return this->op_ == OPERATOR_MULT; } - - tree - do_get_tree(Translate_context*); - - void - do_export(Export*) const; - - void - do_dump_expression(Ast_dump_context*) const; - - void - do_issue_nil_check() - { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); } - - private: - // The unary operator to apply. - Operator op_; - // Normally true. False if this is an address expression which does - // not escape the current function. - bool escapes_; - // True if this is an address expression which should create a - // temporary variable if necessary. - bool create_temp_; - // The operand. - Expression* expr_; - // Whether or not to issue a nil check for this expression if its address - // is being taken. - bool issue_nil_check_; -}; +// Class Unary_expression. // If we are taking the address of a composite literal, and the // contents are not constant, then we want to make a heap expression @@ -4214,11 +4094,18 @@ Unary_expression::do_get_tree(Translate_ } } - // Build a decl for a constant constructor. - if ((this->expr_->is_composite_literal() + if (this->is_gc_root_) + { + // Build a decl for a GC root variable. GC roots are mutable, so they + // cannot be represented as an immutable_struct in the backend. + Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr); + bexpr = gogo->backend()->var_expression(gc_root, loc); + } + else if ((this->expr_->is_composite_literal() || this->expr_->string_expression() != NULL) && this->expr_->is_immutable()) { + // Build a decl for a constant constructor. static unsigned int counter; char buf[100]; snprintf(buf, sizeof buf, "C%u", counter); @@ -12508,6 +12395,14 @@ Fixed_array_construction_expression::do_ return expr_to_tree(this->get_constructor(context, btype)); } +Expression* +Expression::make_array_composite_literal(Type* type, Expression_list* vals, + Location location) +{ + go_assert(type->array_type() != NULL && !type->is_slice_type()); + return new Fixed_array_construction_expression(type, NULL, vals, location); +} + // Construct a slice. class Slice_construction_expression : public Array_construction_expression Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 209665) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -575,6 +575,164 @@ Gogo::current_bindings() const return this->globals_; } +// Add statements to INIT_STMTS which run the initialization +// functions for imported packages. This is only used for the "main" +// package. + +void +Gogo::init_imports(std::vector& init_stmts) +{ + go_assert(this->is_main_package()); + + if (this->imported_init_fns_.empty()) + return; + + Location unknown_loc = Linemap::unknown_location(); + Function_type* func_type = + Type::make_function_type(NULL, NULL, NULL, unknown_loc); + Btype* fntype = func_type->get_backend_fntype(this); + + // We must call them in increasing priority order. + std::vector v; + for (std::set::const_iterator p = + this->imported_init_fns_.begin(); + p != this->imported_init_fns_.end(); + ++p) + v.push_back(*p); + std::sort(v.begin(), v.end()); + + // We build calls to the init functions, which take no arguments. + std::vector empty_args; + for (std::vector::const_iterator p = v.begin(); + p != v.end(); + ++p) + { + std::string user_name = p->package_name() + ".init"; + const std::string& init_name(p->init_name()); + + Bfunction* pfunc = this->backend()->function(fntype, user_name, init_name, + true, true, true, false, + false, unknown_loc); + Bexpression* pfunc_code = + this->backend()->function_code_expression(pfunc, unknown_loc); + Bexpression* pfunc_call = + this->backend()->call_expression(pfunc_code, empty_args, unknown_loc); + init_stmts.push_back(this->backend()->expression_statement(pfunc_call)); + } +} + +// Register global variables with the garbage collector. We need to +// register all variables which can hold a pointer value. They become +// roots during the mark phase. We build a struct that is easy to +// hook into a list of roots. + +// struct __go_gc_root_list +// { +// struct __go_gc_root_list* __next; +// struct __go_gc_root +// { +// void* __decl; +// size_t __size; +// } __roots[]; +// }; + +// The last entry in the roots array has a NULL decl field. + +void +Gogo::register_gc_vars(const std::vector& var_gc, + std::vector& init_stmts) +{ + if (var_gc.empty()) + return; + + Type* pvt = Type::make_pointer_type(Type::make_void_type()); + Type* uint_type = Type::lookup_integer_type("uint"); + Struct_type* root_type = Type::make_builtin_struct_type(2, + "__decl", pvt, + "__size", uint_type); + + Location builtin_loc = Linemap::predeclared_location(); + size_t count = var_gc.size(); + mpz_t lenval; + mpz_init_set_ui(lenval, count); + Expression* length = Expression::make_integer(&lenval, NULL, builtin_loc); + mpz_clear(lenval); + + Array_type* root_array_type = Type::make_array_type(root_type, length); + Type* ptdt = Type::make_type_descriptor_ptr_type(); + Struct_type* root_list_type = + Type::make_builtin_struct_type(2, + "__next", ptdt, + "__roots", root_array_type); + + // Build an initializer for the __roots array. + + Expression_list* roots_init = new Expression_list(); + + size_t i = 0; + for (std::vector::const_iterator p = var_gc.begin(); + p != var_gc.end(); + ++p, ++i) + { + Expression_list* init = new Expression_list(); + + Location no_loc = (*p)->location(); + Expression* decl = Expression::make_var_reference(*p, no_loc); + Expression* decl_addr = + Expression::make_unary(OPERATOR_AND, decl, no_loc); + init->push_back(decl_addr); + + Expression* decl_size = + Expression::make_type_info(decl->type(), Expression::TYPE_INFO_SIZE); + init->push_back(decl_size); + + Expression* root_ctor = + Expression::make_struct_composite_literal(root_type, init, no_loc); + roots_init->push_back(root_ctor); + } + + // The list ends with a NULL entry. + + Expression_list* null_init = new Expression_list(); + Expression* nil = Expression::make_nil(builtin_loc); + null_init->push_back(nil); + + mpz_t zval; + mpz_init_set_ui(zval, 0UL); + Expression* zero = Expression::make_integer(&zval, NULL, builtin_loc); + mpz_clear(zval); + null_init->push_back(zero); + + Expression* null_root_ctor = + Expression::make_struct_composite_literal(root_type, null_init, + builtin_loc); + roots_init->push_back(null_root_ctor); + + // Build a constructor for the struct. + + Expression_list* root_list_init = new Expression_list(); + root_list_init->push_back(nil); + + Expression* roots_ctor = + Expression::make_array_composite_literal(root_array_type, roots_init, + builtin_loc); + root_list_init->push_back(roots_ctor); + + Expression* root_list_ctor = + Expression::make_struct_composite_literal(root_list_type, root_list_init, + builtin_loc); + + Expression* root_addr = Expression::make_unary(OPERATOR_AND, root_list_ctor, + builtin_loc); + root_addr->unary_expression()->set_is_gc_root(); + Expression* register_roots = Runtime::make_call(Runtime::REGISTER_GC_ROOTS, + builtin_loc, 1, root_addr); + + Translate_context context(this, NULL, NULL, NULL); + Bexpression* bcall = tree_to_expr(register_roots->get_tree(&context)); + init_stmts.push_back(this->backend()->expression_statement(bcall)); +} + // Get the name to use for the import control function. If there is a // global function or variable, then we know that that name must be // unique in the link, and we use it as the basis for our name. @@ -614,6 +772,521 @@ Gogo::initialization_function_decl() return Named_object::make_function(name, NULL, initfn); } +// Create the magic initialization function. CODE_STMT is the +// code that it needs to run. + +Named_object* +Gogo::create_initialization_function(Named_object* initfn, + Bstatement* code_stmt) +{ + // Make sure that we thought we needed an initialization function, + // as otherwise we will not have reported it in the export data. + go_assert(this->is_main_package() || this->need_init_fn_); + + if (initfn == NULL) + initfn = this->initialization_function_decl(); + + // Bind the initialization function code to a block. + Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn); + Location pkg_loc = this->package_->location(); + std::vector vars; + this->backend()->block(fndecl, NULL, vars, pkg_loc, pkg_loc); + + if (!this->backend()->function_set_body(fndecl, code_stmt)) + { + go_assert(saw_errors()); + return NULL; + } + return initfn; +} + +// Search for references to VAR in any statements or called functions. + +class Find_var : public Traverse +{ + public: + // A hash table we use to avoid looping. The index is the name of a + // named object. We only look through objects defined in this + // package. + typedef Unordered_set(const void*) Seen_objects; + + Find_var(Named_object* var, Seen_objects* seen_objects) + : Traverse(traverse_expressions), + var_(var), seen_objects_(seen_objects), found_(false) + { } + + // Whether the variable was found. + bool + found() const + { return this->found_; } + + int + expression(Expression**); + + private: + // The variable we are looking for. + Named_object* var_; + // Names of objects we have already seen. + Seen_objects* seen_objects_; + // True if the variable was found. + bool found_; +}; + +// See if EXPR refers to VAR, looking through function calls and +// variable initializations. + +int +Find_var::expression(Expression** pexpr) +{ + Expression* e = *pexpr; + + Var_expression* ve = e->var_expression(); + if (ve != NULL) + { + Named_object* v = ve->named_object(); + if (v == this->var_) + { + this->found_ = true; + return TRAVERSE_EXIT; + } + + if (v->is_variable() && v->package() == NULL) + { + Expression* init = v->var_value()->init(); + if (init != NULL) + { + std::pair ins = + this->seen_objects_->insert(v); + if (ins.second) + { + // This is the first time we have seen this name. + if (Expression::traverse(&init, this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + } + } + } + + // We traverse the code of any function we see. Note that this + // means that we will traverse the code of a function whose address + // is taken even if it is not called. + Func_expression* fe = e->func_expression(); + if (fe != NULL) + { + const Named_object* f = fe->named_object(); + if (f->is_function() && f->package() == NULL) + { + std::pair ins = + this->seen_objects_->insert(f); + if (ins.second) + { + // This is the first time we have seen this name. + if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + } + } + + Temporary_reference_expression* tre = e->temporary_reference_expression(); + if (tre != NULL) + { + Temporary_statement* ts = tre->statement(); + Expression* init = ts->init(); + if (init != NULL) + { + std::pair ins = + this->seen_objects_->insert(ts); + if (ins.second) + { + // This is the first time we have seen this temporary + // statement. + if (Expression::traverse(&init, this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + } + } + } + + return TRAVERSE_CONTINUE; +} + +// Return true if EXPR, PREINIT, or DEP refers to VAR. + +static bool +expression_requires(Expression* expr, Block* preinit, Named_object* dep, + Named_object* var) +{ + Find_var::Seen_objects seen_objects; + Find_var find_var(var, &seen_objects); + if (expr != NULL) + Expression::traverse(&expr, &find_var); + if (preinit != NULL) + preinit->traverse(&find_var); + if (dep != NULL) + { + Expression* init = dep->var_value()->init(); + if (init != NULL) + Expression::traverse(&init, &find_var); + if (dep->var_value()->has_pre_init()) + dep->var_value()->preinit()->traverse(&find_var); + } + + return find_var.found(); +} + +// Sort variable initializations. If the initialization expression +// for variable A refers directly or indirectly to the initialization +// expression for variable B, then we must initialize B before A. + +class Var_init +{ + public: + Var_init() + : var_(NULL), init_(NULL) + { } + + Var_init(Named_object* var, Bstatement* init) + : var_(var), init_(init) + { } + + // Return the variable. + Named_object* + var() const + { return this->var_; } + + // Return the initialization expression. + Bstatement* + init() const + { return this->init_; } + + private: + // The variable being initialized. + Named_object* var_; + // The initialization statement. + Bstatement* init_; +}; + +typedef std::list Var_inits; + +// Sort the variable initializations. The rule we follow is that we +// emit them in the order they appear in the array, except that if the +// initialization expression for a variable V1 depends upon another +// variable V2 then we initialize V1 after V2. + +static void +sort_var_inits(Gogo* gogo, Var_inits* var_inits) +{ + typedef std::pair No_no; + typedef std::map Cache; + Cache cache; + + Var_inits ready; + while (!var_inits->empty()) + { + Var_inits::iterator p1 = var_inits->begin(); + Named_object* var = p1->var(); + Expression* init = var->var_value()->init(); + Block* preinit = var->var_value()->preinit(); + Named_object* dep = gogo->var_depends_on(var->var_value()); + + // Start walking through the list to see which variables VAR + // needs to wait for. + Var_inits::iterator p2 = p1; + ++p2; + + for (; p2 != var_inits->end(); ++p2) + { + Named_object* p2var = p2->var(); + No_no key(var, p2var); + std::pair ins = + cache.insert(std::make_pair(key, false)); + if (ins.second) + ins.first->second = expression_requires(init, preinit, dep, p2var); + if (ins.first->second) + { + // Check for cycles. + key = std::make_pair(p2var, var); + ins = cache.insert(std::make_pair(key, false)); + if (ins.second) + ins.first->second = + expression_requires(p2var->var_value()->init(), + p2var->var_value()->preinit(), + gogo->var_depends_on(p2var->var_value()), + var); + if (ins.first->second) + { + error_at(var->location(), + ("initialization expressions for %qs and " + "%qs depend upon each other"), + var->message_name().c_str(), + p2var->message_name().c_str()); + inform(p2->var()->location(), "%qs defined here", + p2var->message_name().c_str()); + p2 = var_inits->end(); + } + else + { + // We can't emit P1 until P2 is emitted. Move P1. + Var_inits::iterator p3 = p2; + ++p3; + var_inits->splice(p3, *var_inits, p1); + } + break; + } + } + + if (p2 == var_inits->end()) + { + // VAR does not depends upon any other initialization expressions. + + // Check for a loop of VAR on itself. We only do this if + // INIT is not NULL and there is no dependency; when INIT is + // NULL, it means that PREINIT sets VAR, which we will + // interpret as a loop. + if (init != NULL && dep == NULL + && expression_requires(init, preinit, NULL, var)) + error_at(var->location(), + "initialization expression for %qs depends upon itself", + var->message_name().c_str()); + ready.splice(ready.end(), *var_inits, p1); + } + } + + // Now READY is the list in the desired initialization order. + var_inits->swap(ready); +} + +// Write out the global definitions. + +void +Gogo::write_globals() +{ + this->build_interface_method_tables(); + + Bindings* bindings = this->current_bindings(); + + for (Bindings::const_declarations_iterator p = bindings->begin_declarations(); + p != bindings->end_declarations(); + ++p) + { + // If any function declarations needed a descriptor, make sure + // we build it. + Named_object* no = p->second; + if (no->is_function_declaration()) + no->func_declaration_value()->build_backend_descriptor(this); + } + + // Lists of globally declared types, variables, constants, and functions + // that must be defined. + std::vector type_decls; + std::vector var_decls; + std::vector const_decls; + std::vector func_decls; + + // The init function declaration, if necessary. + Named_object* init_fndecl = NULL; + + std::vector init_stmts; + std::vector var_init_stmts; + + if (this->is_main_package()) + this->init_imports(init_stmts); + + // A list of variable initializations. + Var_inits var_inits; + + // A list of variables which need to be registered with the garbage + // collector. + size_t count_definitions = bindings->size_definitions(); + std::vector var_gc; + var_gc.reserve(count_definitions); + + for (Bindings::const_definitions_iterator p = bindings->begin_definitions(); + p != bindings->end_definitions(); + ++p) + { + Named_object* no = *p; + go_assert(!no->is_type_declaration() && !no->is_function_declaration()); + + // There is nothing to do for a package. + if (no->is_package()) + continue; + + // There is nothing to do for an object which was imported from + // a different package into the global scope. + if (no->package() != NULL) + continue; + + // Skip blank named functions and constants. + if ((no->is_function() && no->func_value()->is_sink()) + || (no->is_const() && no->const_value()->is_sink())) + continue; + + // There is nothing useful we can output for constants which + // have ideal or non-integral type. + if (no->is_const()) + { + Type* type = no->const_value()->type(); + if (type == NULL) + type = no->const_value()->expr()->type(); + if (type->is_abstract() || !type->is_numeric_type()) + continue; + } + + if (!no->is_variable()) + no->get_backend(this, const_decls, type_decls, func_decls); + else + { + Variable* var = no->var_value(); + Bvariable* bvar = no->get_backend_variable(this, NULL); + var_decls.push_back(bvar); + + // 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] == '.'; + + Bstatement* var_init_stmt = NULL; + if (!var->has_pre_init()) + { + Bexpression* var_binit = var->get_init(this, NULL); + + // If the backend representation of the variable initializer is + // constant, we can just set the initial value using + // global_var_set_init instead of during the init() function. + // The initializer is constant if it is the zero-value of the + // variable's type or if the initial value is an immutable value + // that is not copied to the heap. + bool is_constant_initializer = false; + if (var->init() == NULL) + is_constant_initializer = true; + else + { + Type* var_type = var->type(); + Expression* init = var->init(); + Expression* init_cast = + Expression::make_cast(var_type, init, var->location()); + is_constant_initializer = + init_cast->is_immutable() && !var_type->has_pointer(); + } + + if (var_binit == NULL) + ; + else if (is_constant_initializer) + { + if (expression_requires(var->init(), NULL, + this->var_depends_on(var), no)) + error_at(no->location(), + "initialization expression for %qs depends " + "upon itself", + no->message_name().c_str()); + this->backend()->global_variable_set_init(bvar, var_binit); + } + else if (is_sink) + var_init_stmt = + this->backend()->expression_statement(var_binit); + else + { + Location loc = var->location(); + Bexpression* var_expr = + this->backend()->var_expression(bvar, loc); + var_init_stmt = + this->backend()->assignment_statement(var_expr, var_binit, + loc); + } + } + else + { + // We are going to create temporary variables which + // means that we need an fndecl. + if (init_fndecl == NULL) + init_fndecl = this->initialization_function_decl(); + + Bvariable* var_decl = is_sink ? NULL : bvar; + var_init_stmt = var->get_init_block(this, init_fndecl, var_decl); + } + + if (var_init_stmt != NULL) + { + if (var->init() == NULL && !var->has_pre_init()) + var_init_stmts.push_back(var_init_stmt); + else + var_inits.push_back(Var_init(no, var_init_stmt)); + } + else if (this->var_depends_on(var) != NULL) + { + // This variable is initialized from something that is + // not in its init or preinit. This variable needs to + // participate in dependency analysis sorting, in case + // some other variable depends on this one. + Btype* btype = no->var_value()->type()->get_backend(this); + Bexpression* zero = this->backend()->zero_expression(btype); + Bstatement* zero_stmt = + this->backend()->expression_statement(zero); + var_inits.push_back(Var_init(no, zero_stmt)); + } + + if (!is_sink && var->type()->has_pointer()) + var_gc.push_back(no); + } + } + + // Register global variables with the garbage collector. + this->register_gc_vars(var_gc, init_stmts); + + // Simple variable initializations, after all variables are + // registered. + init_stmts.push_back(this->backend()->statement_list(var_init_stmts)); + + // Complete variable initializations, first sorting them into a + // workable order. + if (!var_inits.empty()) + { + sort_var_inits(this, &var_inits); + for (Var_inits::const_iterator p = var_inits.begin(); + p != var_inits.end(); + ++p) + init_stmts.push_back(p->init()); + } + + // After all the variables are initialized, call the init + // functions if there are any. Init functions take no arguments, so + // we pass in EMPTY_ARGS to call them. + std::vector empty_args; + for (std::vector::const_iterator p = + this->init_functions_.begin(); + p != this->init_functions_.end(); + ++p) + { + Location func_loc = (*p)->location(); + Function* func = (*p)->func_value(); + Bfunction* initfn = func->get_or_make_decl(this, *p); + Bexpression* func_code = + this->backend()->function_code_expression(initfn, func_loc); + Bexpression* call = this->backend()->call_expression(func_code, + empty_args, + func_loc); + init_stmts.push_back(this->backend()->expression_statement(call)); + } + + // Set up a magic function to do all the initialization actions. + // This will be called if this package is imported. + Bstatement* init_fncode = this->backend()->statement_list(init_stmts); + if (this->need_init_fn_ || this->is_main_package()) + { + init_fndecl = + this->create_initialization_function(init_fndecl, init_fncode); + if (init_fndecl != NULL) + func_decls.push_back(init_fndecl->func_value()->get_decl()); + } + + // We should not have seen any new bindings created during the conversion. + go_assert(count_definitions == this->current_bindings()->size_definitions()); + + // Define all globally declared values. + if (!saw_errors()) + this->backend()->write_global_definitions(type_decls, const_decls, + func_decls, var_decls); +} + // Return the current block. Block* @@ -4182,6 +4855,15 @@ Function::get_or_make_decl(Gogo* gogo, N return this->fndecl_; } +// Return the function's decl after it has been built. + +Bfunction* +Function::get_decl() const +{ + go_assert(this->fndecl_ != NULL); + return this->fndecl_; +} + // Build the backend representation for the function code. void @@ -5266,8 +5948,7 @@ Variable::get_init_block(Gogo* gogo, Nam { Location loc = this->location(); Expression* val_expr = - Expression::convert_for_assignment(gogo, this->type(), - this->init_, this->location()); + Expression::make_cast(this->type(), this->init_, loc); Bexpression* val = tree_to_expr(val_expr->get_tree(&context)); Bexpression* var_ref = gogo->backend()->var_expression(var_decl, loc); decl_init = gogo->backend()->assignment_statement(var_ref, val, loc); @@ -5353,8 +6034,7 @@ Variable::get_backend_variable(Gogo* gog } else { - tree fndecl = function->func_value()->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); + Bfunction* bfunction = function->func_value()->get_decl(); bool is_address_taken = (this->is_non_escaping_address_taken_ && !this->is_in_heap()); if (is_parameter) @@ -5391,8 +6071,7 @@ Result_variable::get_backend_variable(Go if (this->is_in_heap()) type = Type::make_pointer_type(type); Btype* btype = type->get_backend(gogo); - tree fndecl = function->func_value()->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); + Bfunction* bfunction = function->func_value()->get_decl(); std::string n = Gogo::unpack_hidden_name(name); bool is_address_taken = (this->is_non_escaping_address_taken_ && !this->is_in_heap()); @@ -5482,6 +6161,33 @@ Named_constant::import_const(Import* imp imp->require_c_string(";\n"); } +// Get the backend representation. + +Bexpression* +Named_constant::get_backend(Gogo* gogo, Named_object* const_no) +{ + if (this->bconst_ == NULL) + { + Translate_context subcontext(gogo, NULL, NULL, NULL); + Type* type = this->type(); + Location loc = this->location(); + + Expression* const_ref = Expression::make_const_reference(const_no, loc); + Bexpression* const_decl = + tree_to_expr(const_ref->get_tree(&subcontext)); + if (type != NULL && type->is_numeric_type()) + { + Btype* btype = type->get_backend(gogo); + std::string name = const_no->get_id(gogo); + const_decl = + gogo->backend()->named_constant_expression(btype, name, + const_decl, loc); + } + this->bconst_ = const_decl; + } + return this->bconst_; +} + // Add a method. Named_object* @@ -5552,8 +6258,7 @@ Unknown_name::set_real_named_object(Name Named_object::Named_object(const std::string& name, const Package* package, Classification classification) - : name_(name), package_(package), classification_(classification), - tree_(NULL) + : name_(name), package_(package), classification_(classification) { if (Gogo::is_sink_name(name)) go_assert(classification == NAMED_OBJECT_SINK); @@ -5928,6 +6633,72 @@ Named_object::get_id(Gogo* gogo) return decl_name; } +// Get the backend representation for this named object. + +void +Named_object::get_backend(Gogo* gogo, std::vector& const_decls, + std::vector& type_decls, + std::vector& func_decls) +{ + switch (this->classification_) + { + case NAMED_OBJECT_CONST: + if (!Gogo::is_erroneous_name(this->name_)) + const_decls.push_back(this->u_.const_value->get_backend(gogo, this)); + break; + + case NAMED_OBJECT_TYPE: + { + Named_type* named_type = this->u_.type_value; + if (!Gogo::is_erroneous_name(this->name_)) + type_decls.push_back(named_type->get_backend(gogo)); + + // We need to produce a type descriptor for every named + // type, and for a pointer to every named type, since + // other files or packages might refer to them. We need + // to do this even for hidden types, because they might + // still be returned by some function. Simply calling the + // type_descriptor method is enough to create the type + // descriptor, even though we don't do anything with it. + if (this->package_ == NULL) + { + named_type-> + type_descriptor_pointer(gogo, Linemap::predeclared_location()); + Type* pn = Type::make_pointer_type(named_type); + pn->type_descriptor_pointer(gogo, Linemap::predeclared_location()); + } + } + break; + + case NAMED_OBJECT_TYPE_DECLARATION: + error("reference to undefined type %qs", + this->message_name().c_str()); + return; + + case NAMED_OBJECT_VAR: + case NAMED_OBJECT_RESULT_VAR: + case NAMED_OBJECT_SINK: + go_unreachable(); + + case NAMED_OBJECT_FUNC: + { + Function* func = this->u_.func_value; + if (!Gogo::is_erroneous_name(this->name_)) + func_decls.push_back(func->get_or_make_decl(gogo, this)); + + if (func->block() != NULL) + func->build(gogo, this); + } + break; + + case NAMED_OBJECT_ERRONEOUS: + break; + + default: + go_unreachable(); + } +} + // Class Bindings. Bindings::Bindings(Bindings* enclosing) @@ -6400,8 +7171,7 @@ Label::get_backend_label(Translate_conte if (this->blabel_ == NULL) { Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); + Bfunction* bfunction = function->get_decl(); this->blabel_ = context->backend()->label(bfunction, this->name_, this->location_); } @@ -6427,8 +7197,7 @@ Unnamed_label::get_blabel(Translate_cont if (this->blabel_ == NULL) { Function* function = context->function()->func_value(); - tree fndecl = function->get_decl(); - Bfunction* bfunction = tree_to_function(fndecl); + Bfunction* bfunction = function->get_decl(); this->blabel_ = context->backend()->label(bfunction, "", this->location_); } Index: gcc/go/go-gcc.cc =================================================================== --- gcc/go/go-gcc.cc (revision 209665) +++ gcc/go/go-gcc.cc (working copy) @@ -29,9 +29,11 @@ #include "stor-layout.h" #include "varasm.h" #include "tree-iterator.h" +#include "cgraph.h" #include "convert.h" #include "basic-block.h" #include "gimple-expr.h" +#include "gimplify.h" #include "toplev.h" #include "output.h" #include "real.h" @@ -317,7 +319,7 @@ class Gcc_backend : public Backend Location); Bstatement* - switch_statement(Bexpression* value, + switch_statement(Bfunction* function, Bexpression* value, const std::vector >& cases, const std::vector& statements, Location); @@ -376,6 +378,9 @@ class Gcc_backend : public Backend Location, Bstatement**); Bvariable* + gc_root_variable(Btype*, Bexpression*); + + Bvariable* immutable_struct(const std::string&, bool, bool, Btype*, Location); void @@ -420,6 +425,12 @@ class Gcc_backend : public Backend bool function_set_body(Bfunction* function, Bstatement* code_stmt); + void + write_global_definitions(const std::vector&, + const std::vector&, + const std::vector&, + const std::vector&); + private: // Make a Bexpression from a tree. Bexpression* @@ -1709,6 +1720,7 @@ Gcc_backend::return_statement(Bfunction* tree result = DECL_RESULT(fntree); if (result == error_mark_node) return this->error_statement(); + tree ret; if (vals.empty()) ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node, @@ -1732,7 +1744,14 @@ Gcc_backend::return_statement(Bfunction* // statement. tree stmt_list = NULL_TREE; tree rettype = TREE_TYPE(result); + + if (DECL_STRUCT_FUNCTION(fntree) == NULL) + push_struct_function(fntree); + else + push_cfun(DECL_STRUCT_FUNCTION(fntree)); tree rettmp = create_tmp_var(rettype, "RESULT"); + pop_cfun(); + tree field = TYPE_FIELDS(rettype); for (std::vector::const_iterator p = vals.begin(); p != vals.end(); @@ -1818,6 +1837,7 @@ Gcc_backend::if_statement(Bexpression* c Bstatement* Gcc_backend::switch_statement( + Bfunction* function, Bexpression* value, const std::vector >& cases, const std::vector& statements, @@ -1825,6 +1845,12 @@ Gcc_backend::switch_statement( { gcc_assert(cases.size() == statements.size()); + tree decl = function->get_tree(); + if (DECL_STRUCT_FUNCTION(decl) == NULL) + push_struct_function(decl); + else + push_cfun(DECL_STRUCT_FUNCTION(decl)); + tree stmt_list = NULL_TREE; std::vector >::const_iterator pc = cases.begin(); for (std::vector::const_iterator ps = statements.begin(); @@ -1864,6 +1890,7 @@ Gcc_backend::switch_statement( append_to_statement_list(t, &stmt_list); } } + pop_cfun(); tree tv = value->get_tree(); if (tv == error_mark_node) @@ -1922,13 +1949,7 @@ Gcc_backend::block(Bfunction* function, 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(); + tree fndecl = function->get_tree(); gcc_assert(fndecl != NULL_TREE); // We may have already created a block for local variables when @@ -1982,7 +2003,6 @@ Gcc_backend::block(Bfunction* function, void_type_node, BLOCK_VARS(block_tree), NULL_TREE, block_tree); TREE_SIDE_EFFECTS(bind_tree) = 1; - return new Bblock(bind_tree); } @@ -2214,7 +2234,7 @@ Gcc_backend::temporary_variable(Bfunctio return this->error_variable(); } - go_assert(function != NULL); + gcc_assert(function != NULL); tree decl = function->get_tree(); tree var; @@ -2263,6 +2283,28 @@ Gcc_backend::temporary_variable(Bfunctio return new Bvariable(var); } +// Make a GC root variable. + +Bvariable* +Gcc_backend::gc_root_variable(Btype* type, Bexpression* init) +{ + tree type_tree = type->get_tree(); + tree init_tree = init->get_tree(); + if (type_tree == error_mark_node || init_tree == error_mark_node) + return this->error_variable(); + + tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, + create_tmp_var_name("gc"), type_tree); + DECL_EXTERNAL(decl) = 0; + TREE_PUBLIC(decl) = 0; + TREE_STATIC(decl) = 1; + DECL_ARTIFICIAL(decl) = 1; + DECL_INITIAL(decl) = init_tree; + rest_of_decl_compilation(decl, 1, 0); + + return new Bvariable(decl); +} + // Create a named immutable initialized data structure. Bvariable* @@ -2277,9 +2319,9 @@ Gcc_backend::immutable_struct(const std: get_identifier_from_string(name), build_qualified_type(type_tree, TYPE_QUAL_CONST)); TREE_STATIC(decl) = 1; + TREE_USED(decl) = 1; TREE_READONLY(decl) = 1; TREE_CONSTANT(decl) = 1; - TREE_USED(decl) = 1; DECL_ARTIFICIAL(decl) = 1; if (!is_hidden) TREE_PUBLIC(decl) = 1; @@ -2369,7 +2411,17 @@ Gcc_backend::label(Bfunction* function, { tree decl; if (name.empty()) - decl = create_artificial_label(location.gcc_location()); + { + tree func_tree = function->get_tree(); + if (DECL_STRUCT_FUNCTION(func_tree) == NULL) + push_struct_function(func_tree); + else + push_cfun(DECL_STRUCT_FUNCTION(func_tree)); + + decl = create_artificial_label(location.gcc_location()); + + pop_cfun(); + } else { tree id = get_identifier_from_string(name); @@ -2477,11 +2529,18 @@ Gcc_backend::function_defer_statement(Bf { tree undefer_tree = undefer->get_tree(); tree defer_tree = defer->get_tree(); + tree fntree = function->get_tree(); if (undefer_tree == error_mark_node - || defer_tree == error_mark_node) + || defer_tree == error_mark_node + || fntree == error_mark_node) return this->error_statement(); + if (DECL_STRUCT_FUNCTION(fntree) == NULL) + push_struct_function(fntree); + else + push_cfun(DECL_STRUCT_FUNCTION(fntree)); + tree stmt_list = NULL; Blabel* blabel = this->label(function, "", location); Bstatement* label_def = this->label_definition_statement(blabel); @@ -2494,6 +2553,7 @@ Gcc_backend::function_defer_statement(Bf tree try_catch = build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body); append_to_statement_list(try_catch, &stmt_list); + pop_cfun(); return this->make_statement(stmt_list); } @@ -2538,6 +2598,88 @@ Gcc_backend::function_set_body(Bfunction return true; } +// Write the definitions for all TYPE_DECLS, CONSTANT_DECLS, +// FUNCTION_DECLS, and VARIABLE_DECLS declared globally. + +void +Gcc_backend::write_global_definitions( + const std::vector& type_decls, + const std::vector& constant_decls, + const std::vector& function_decls, + const std::vector& variable_decls) +{ + size_t count_definitions = type_decls.size() + constant_decls.size() + + function_decls.size() + variable_decls.size(); + + tree* defs = new tree[count_definitions]; + + // Convert all non-erroneous declarations into Gimple form. + size_t i = 0; + for (std::vector::const_iterator p = variable_decls.begin(); + p != variable_decls.end(); + ++p) + { + if ((*p)->get_tree() != error_mark_node) + { + defs[i] = (*p)->get_tree(); + go_preserve_from_gc(defs[i]); + ++i; + } + } + + for (std::vector::const_iterator p = type_decls.begin(); + p != type_decls.end(); + ++p) + { + tree type_tree = (*p)->get_tree(); + if (type_tree != error_mark_node + && IS_TYPE_OR_DECL_P(type_tree)) + { + defs[i] = TYPE_NAME(type_tree); + gcc_assert(defs[i] != NULL); + go_preserve_from_gc(defs[i]); + ++i; + } + } + for (std::vector::const_iterator p = constant_decls.begin(); + p != constant_decls.end(); + ++p) + { + if ((*p)->get_tree() != error_mark_node) + { + defs[i] = (*p)->get_tree(); + go_preserve_from_gc(defs[i]); + ++i; + } + } + for (std::vector::const_iterator p = function_decls.begin(); + p != function_decls.end(); + ++p) + { + tree decl = (*p)->get_tree(); + if (decl != error_mark_node) + { + go_preserve_from_gc(decl); + gimplify_function_tree(decl); + cgraph_finalize_function(decl, true); + + defs[i] = decl; + ++i; + } + } + + // Pass everything back to the middle-end. + + wrapup_global_declarations(defs, i); + + finalize_compilation_unit(); + + check_global_declarations(defs, i); + emit_debug_global_declarations(defs, i); + + delete[] defs; +} + // The single backend. static Gcc_backend gcc_backend; --=-=-=--