escape: Implement tag phase.
authorIan Lance Taylor <ian@gcc.gnu.org>
Wed, 6 Jul 2016 17:34:03 +0000 (17:34 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Wed, 6 Jul 2016 17:34:03 +0000 (17:34 +0000)
    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

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/escape.cc

index e2a7a8d36eebd8276c9781f3f400807a06394f98..49976238de94e109f208ef9af4a982f2fcb565fb 100644 (file)
@@ -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.
index 7a558183f379df6eed47ac7dfe6fd9e5a6216212..af8f1e2f9936e22e84e303282978bcb6ad9a63e6 100644 (file)
@@ -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);
 }