From: Ian Lance Taylor Date: Wed, 6 Jul 2016 17:34:03 +0000 (+0000) Subject: escape: Implement tag phase. X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=f91f0e21733dae6f8d1393d6c8029b8d9cf073fa;p=gcc.git escape: Implement tag phase. Adds notes to function parameters which summarize the escape of that parameter with respect to the function's scope. Reviewed-on: https://go-review.googlesource.com/18443 From-SVN: r238057 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e2a7a8d36ee..49976238de9 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -1f2f2c77c7ec92efa254e07162a8fc0d22a550e7 +c8fdad389ce6f439a02fb654d231053b47ff4e02 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc index 7a558183f37..af8f1e2f993 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -2194,15 +2194,103 @@ Gogo::propagate_escape(Escape_context* context, Node* dst) } } +class Escape_analysis_tag +{ + public: + Escape_analysis_tag(Escape_context* context) + : context_(context) + { } + + // Add notes to the function's type about the escape information of its + // input parameters. + void + tag(Named_object* fn); + + private: + Escape_context* context_; +}; + +void +Escape_analysis_tag::tag(Named_object* fn) +{ + // External functions are assumed unsafe + // unless //go:noescape is given before the declaration. + if (fn->package() != NULL || !fn->is_function()) + { + // TODO(cmang): Implement //go:noescape directive for external functions; + // mark input parameters as not escaping. + return; + } + + Function_type* fntype = fn->func_value()->type(); + Bindings* bindings = fn->func_value()->block()->bindings(); + + if (fntype->is_method() + && !fntype->receiver()->name().empty() + && !Gogo::is_sink_name(fntype->receiver()->name())) + { + Named_object* rcvr_no = bindings->lookup(fntype->receiver()->name()); + go_assert(rcvr_no != NULL); + Node* rcvr_node = Node::make_node(rcvr_no); + switch ((rcvr_node->encoding() & ESCAPE_MASK)) + { + case Node::ESCAPE_NONE: // not touched by flood + case Node::ESCAPE_RETURN: + if (fntype->receiver()->type()->has_pointer()) + // Don't bother tagging for scalars. + fntype->add_receiver_note(rcvr_node->encoding()); + break; + + case Node::ESCAPE_HEAP: // flooded, moved to heap. + case Node::ESCAPE_SCOPE: // flooded, value leaves scope. + break; + + default: + break; + } + } + + int i = 0; + if (fntype->parameters() != NULL) + { + const Typed_identifier_list* til = fntype->parameters(); + for (Typed_identifier_list::const_iterator p = til->begin(); + p != til->end(); + ++p, ++i) + { + if (p->name().empty() || Gogo::is_sink_name(p->name())) + continue; + + Named_object* param_no = bindings->lookup(p->name()); + go_assert(param_no != NULL); + Node* param_node = Node::make_node(param_no); + switch ((param_node->encoding() & ESCAPE_MASK)) + { + case Node::ESCAPE_NONE: // not touched by flood + case Node::ESCAPE_RETURN: + if (p->type()->has_pointer()) + // Don't bother tagging for scalars. + fntype->add_parameter_note(i, param_node->encoding()); + break; + + case Node::ESCAPE_HEAP: // flooded, moved to heap. + case Node::ESCAPE_SCOPE: // flooded, value leaves scope. + break; + + default: + break; + } + } + } + fntype->set_is_tagged(); +} // Tag each top-level function with escape information that will be used to // retain analysis results across imports. void -Gogo::tag_function(Escape_context*, Named_object*) +Gogo::tag_function(Escape_context* context, Named_object* fn) { - // TODO(cmang): Create escape information notes for each input and output - // parameter in a given function. - // Escape_analysis_tag eat(context, fn); - // this->traverse(&eat); + Escape_analysis_tag eat(context); + eat.tag(fn); }