From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 13198 invoked by alias); 10 Oct 2014 20:43:39 -0000 Mailing-List: contact libffi-discuss-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: libffi-discuss-owner@sourceware.org Received: (qmail 13015 invoked by uid 89); 10 Oct 2014 20:43:38 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-2.2 required=5.0 tests=AWL,BAYES_00,FREEMAIL_ENVFROM_END_DIGIT,FREEMAIL_FROM,RCVD_IN_DNSWL_LOW,SPF_PASS autolearn=unavailable version=3.3.2 X-HELO: mail-qc0-f182.google.com Received: from mail-qc0-f182.google.com (HELO mail-qc0-f182.google.com) (209.85.216.182) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with (AES128-SHA encrypted) ESMTPS; Fri, 10 Oct 2014 20:43:35 +0000 Received: by mail-qc0-f182.google.com with SMTP id i17so2601088qcy.13 for ; Fri, 10 Oct 2014 13:43:32 -0700 (PDT) X-Received: by 10.140.17.77 with SMTP id 71mr5423172qgc.65.1412973812370; Fri, 10 Oct 2014 13:43:32 -0700 (PDT) Received: from anchor.com (50-194-63-110-static.hfc.comcastbusiness.net. [50.194.63.110]) by mx.google.com with ESMTPSA id s49sm5909008qge.15.2014.10.10.13.43.30 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Fri, 10 Oct 2014 13:43:31 -0700 (PDT) From: Richard Henderson To: gcc-patches@gcc.gnu.org Cc: libffi-discuss@sourceware.org, gofrontend-dev@googlegroups.com Subject: [PATCH 04/13] Use the static chain as the closure parameter from Go Date: Fri, 10 Oct 2014 20:43:00 -0000 Message-Id: <1412973773-3942-5-git-send-email-rth@redhat.com> In-Reply-To: <1412973773-3942-1-git-send-email-rth@redhat.com> References: <1412973773-3942-1-git-send-email-rth@redhat.com> X-IsSubscribed: yes X-SW-Source: 2014/txt/msg00102.txt.bz2 This is not a standalone patch; it only touches the Go front end. Further changes are required for the Go runtime. --- gcc/go/go-gcc.cc | 44 ++++++++++++++++++++++++++++++++++++++-- gcc/go/gofrontend/backend.h | 7 ++++++- gcc/go/gofrontend/expressions.cc | 21 ++++++++----------- gcc/go/gofrontend/gogo.cc | 29 +++++++++++++------------- gcc/go/gofrontend/gogo.h | 14 +++++++++++++ gcc/go/gofrontend/runtime.def | 6 ------ 6 files changed, 85 insertions(+), 36 deletions(-) diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 6bac84f..01cd473 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -304,7 +304,7 @@ class Gcc_backend : public Backend Bexpression* call_expression(Bexpression* fn, const std::vector& args, - Location); + Bexpression* static_chain, Location); // Statements. @@ -385,6 +385,9 @@ class Gcc_backend : public Backend Location); Bvariable* + static_chain_variable(Bfunction*, const std::string&, Btype*, Location); + + Bvariable* temporary_variable(Bfunction*, Bblock*, Btype*, Bexpression*, bool, Location, Bstatement**); @@ -1759,7 +1762,7 @@ Gcc_backend::array_index_expression(Bexpression* array, Bexpression* index, Bexpression* Gcc_backend::call_expression(Bexpression* fn_expr, const std::vector& fn_args, - Location location) + Bexpression* chain_expr, Location location) { tree fn = fn_expr->get_tree(); if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node) @@ -1819,6 +1822,9 @@ Gcc_backend::call_expression(Bexpression* fn_expr, excess_type != NULL_TREE ? excess_type : rettype, fn, nargs, args); + if (chain_expr) + CALL_EXPR_STATIC_CHAIN (ret) = chain_expr->get_tree(); + if (excess_type != NULL_TREE) { // Calling convert here can undo our excess precision change. @@ -2440,6 +2446,40 @@ Gcc_backend::parameter_variable(Bfunction* function, const std::string& name, return new Bvariable(decl); } +// Make a static chain variable. + +Bvariable* +Gcc_backend::static_chain_variable(Bfunction* function, const std::string& name, + Btype* btype, Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_variable(); + tree decl = build_decl(location.gcc_location(), PARM_DECL, + get_identifier_from_string(name), type_tree); + tree fndecl = function->get_tree(); + DECL_CONTEXT(decl) = fndecl; + DECL_ARG_TYPE(decl) = type_tree; + TREE_USED(decl) = 1; + DECL_ARTIFICIAL(decl) = 1; + DECL_IGNORED_P(decl) = 1; + TREE_READONLY(decl) = 1; + + struct function *f = DECL_STRUCT_FUNCTION(fndecl); + if (f == NULL) + { + push_struct_function(fndecl); + pop_cfun(); + f = DECL_STRUCT_FUNCTION(fndecl); + } + gcc_assert(f->static_chain_decl == NULL); + f->static_chain_decl = decl; + DECL_STATIC_CHAIN(fndecl) = 1; + + go_preserve_from_gc(decl); + return new Bvariable(decl); +} + // Make a temporary variable. Bvariable* diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index 98c36c1..d0a7995 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -374,7 +374,7 @@ class Backend // Create an expression for a call to FN with ARGS. virtual Bexpression* call_expression(Bexpression* fn, const std::vector& args, - Location) = 0; + Bexpression* static_chain, Location) = 0; // Statements. @@ -528,6 +528,11 @@ class Backend Btype* type, bool is_address_taken, Location location) = 0; + // Create a static chain parameter. This is the closure parameter. + virtual Bvariable* + static_chain_variable(Bfunction* function, const std::string& name, + Btype* type, Location location) = 0; + // Create a temporary variable. A temporary variable has no name, // just a type. We pass in FUNCTION and BLOCK in case they are // needed. If INIT is not NULL, the variable should be initialized diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index df1650a..37650eb 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -6621,6 +6621,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, Variable* cvar = new Variable(closure_type, NULL, false, false, false, loc); cvar->set_is_used(); + cvar->set_is_closure(); Named_object* cp = Named_object::make_variable("$closure", NULL, cvar); new_no->func_value()->set_closure_var(cp); @@ -9571,19 +9572,11 @@ Call_expression::do_get_backend(Translate_context* context) fn_args[0] = first_arg->get_backend(context); } - if (!has_closure_arg) - go_assert(closure == NULL); + Bexpression* bclosure = NULL; + if (has_closure_arg) + bclosure = closure->get_backend(context); else - { - // Pass the closure argument by calling the function function - // __go_set_closure. In the order_evaluations pass we have - // ensured that if any parameters contain call expressions, they - // will have been moved out to temporary variables. - go_assert(closure != NULL); - Expression* set_closure = - Runtime::make_call(Runtime::SET_CLOSURE, location, 1, closure); - fn = Expression::make_compound(set_closure, fn, location); - } + go_assert(closure == NULL); Bexpression* bfn = fn->get_backend(context); @@ -9599,7 +9592,8 @@ Call_expression::do_get_backend(Translate_context* context) bfn = gogo->backend()->convert_expression(bft, bfn, location); } - Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, location); + Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, + bclosure, location); if (this->results_ != NULL) { @@ -11373,6 +11367,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo, Variable* cvar = new Variable(closure_type, NULL, false, false, false, loc); cvar->set_is_used(); + cvar->set_is_closure(); Named_object* cp = Named_object::make_variable("$closure", NULL, cvar); new_no->func_value()->set_closure_var(cp); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 81a555f..3a7e686 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -702,7 +702,8 @@ Gogo::init_imports(std::vector& init_stmts) Bexpression* pfunc_code = this->backend()->function_code_expression(pfunc, unknown_loc); Bexpression* pfunc_call = - this->backend()->call_expression(pfunc_code, empty_args, unknown_loc); + this->backend()->call_expression(pfunc_code, empty_args, + NULL, unknown_loc); init_stmts.push_back(this->backend()->expression_statement(pfunc_call)); } } @@ -1354,7 +1355,7 @@ Gogo::write_globals() this->backend()->function_code_expression(initfn, func_loc); Bexpression* call = this->backend()->call_expression(func_code, empty_args, - func_loc); + NULL, func_loc); init_stmts.push_back(this->backend()->expression_statement(call)); } @@ -3856,6 +3857,7 @@ Build_recover_thunks::function(Named_object* orig_no) Variable* orig_closure_var = orig_closure_no->var_value(); Variable* new_var = new Variable(orig_closure_var->type(), NULL, false, false, false, location); + new_var->set_is_closure(); snprintf(buf, sizeof buf, "closure.%u", count); ++count; Named_object* new_closure_no = Named_object::make_variable(buf, NULL, @@ -4466,6 +4468,7 @@ Function::closure_var() Variable* var = new Variable(Type::make_pointer_type(struct_type), NULL, false, false, false, loc); var->set_is_used(); + var->set_is_closure(); this->closure_var_ = Named_object::make_variable("$closure", NULL, var); // Note that the new variable is not in any binding contour. } @@ -5128,18 +5131,12 @@ Function::build(Gogo* gogo, Named_object* named_function) return; } - // If we need a closure variable, fetch it by calling a runtime - // function. The caller will have called __go_set_closure before - // the function call. + // If we need a closure variable, make sure to create it. + // It gets installed in the function as a side effect of creation. if (this->closure_var_ != NULL) { - Bvariable* closure_bvar = - this->closure_var_->get_backend_variable(gogo, named_function); - vars.push_back(closure_bvar); - - Expression* closure = - Runtime::make_call(Runtime::GET_CLOSURE, this->location_, 0); - var_inits.push_back(closure->get_backend(&context)); + go_assert(this->closure_var_->var_value()->is_closure()); + this->closure_var_->get_backend_variable(gogo, named_function); } if (this->block_ != NULL) @@ -5673,7 +5670,8 @@ Variable::Variable(Type* type, Expression* init, bool is_global, Location location) : type_(type), init_(init), preinit_(NULL), location_(location), backend_(NULL), is_global_(is_global), is_parameter_(is_parameter), - is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false), + is_closure_(false), is_receiver_(is_receiver), + is_varargs_parameter_(false), is_used_(false), is_address_taken_(false), is_non_escaping_address_taken_(false), seen_(false), init_is_lowered_(false), init_is_flattened_(false), type_from_init_tuple_(false), type_from_range_index_(false), @@ -6212,7 +6210,10 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, Bfunction* bfunction = function->func_value()->get_decl(); bool is_address_taken = (this->is_non_escaping_address_taken_ && !this->is_in_heap()); - if (is_parameter) + if (this->is_closure()) + bvar = backend->static_chain_variable(bfunction, n, btype, + this->location_); + else if (is_parameter) bvar = backend->parameter_variable(bfunction, n, btype, is_address_taken, this->location_); diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 01390ac..6cc72e2 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -1340,6 +1340,18 @@ class Variable is_parameter() const { return this->is_parameter_; } + // Return whether this is a closure (static chain) parameter. + bool + is_closure() const + { return this->is_closure_; } + + // Change this parameter to be a closure. + void + set_is_closure() + { + this->is_closure_ = true; + } + // Return whether this is the receiver parameter of a method. bool is_receiver() const @@ -1561,6 +1573,8 @@ class Variable bool is_global_ : 1; // Whether this is a function parameter. bool is_parameter_ : 1; + // Whether this is a closure parameter. + bool is_closure_ : 1; // Whether this is the receiver parameter of a method. bool is_receiver_ : 1; // Whether this is the varargs parameter of a function. diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 8c6e82b..d7d4edb 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -230,12 +230,6 @@ DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER)) // Start a new goroutine. DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0()) -// Get the function closure. -DEF_GO_RUNTIME(GET_CLOSURE, "__go_get_closure", P0(), R1(POINTER)) - -// Set the function closure. -DEF_GO_RUNTIME(SET_CLOSURE, "__go_set_closure", P1(POINTER), R0()) - // Defer a function. DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0()) -- 1.9.3