diff mbox

Go patch committed: Move encoding utilities from gcc/go to gofrontend proper

Message ID CAOyqgcWOQW75+FOXf4T6Loxbg5kJG-Q+vyr4v7P9bqa-q-QUMA@mail.gmail.com
State New
Headers show

Commit Message

Ian Lance Taylor Nov. 22, 2016, 10:28 p.m. UTC
This patch by Than McIntosh moves the name encoding utilities from
gcc/go/go-gcc.cc to the gofrontend proper, where they are available
for other backend implementations.  Bootstrapped and ran Go testsuite
on x86_64-pc-linux-gnu.  Committed to mainline.

Ian
diff mbox

Patch

Index: gcc/go/Make-lang.in
===================================================================
--- gcc/go/Make-lang.in	(revision 242724)
+++ gcc/go/Make-lang.in	(working copy)
@@ -55,6 +55,7 @@  GO_OBJS = \
 	go/expressions.o \
 	go/go-backend.o \
 	go/go-diagnostics.o \
+	go/go-encode-id.o \
 	go/go-dump.o \
 	go/go-gcc.o \
 	go/go-gcc-diagnostics.o \
@@ -230,6 +231,7 @@  CFLAGS-go/go-gcc.o += $(GOINCLUDES)
 CFLAGS-go/go-linemap.o += $(GOINCLUDES)
 CFLAGS-go/go-sha1.o += $(GOINCLUDES)
 CFLAGS-go/go-gcc-diagnostics.o += $(GOINCLUDES)
+CFLAGS-go/go-encode-id.o += $(GOINCLUDES)
 
 go/%.o: go/gofrontend/%.cc
 	$(COMPILE) $(GOINCLUDES) $<
Index: gcc/go/go-gcc.cc
===================================================================
--- gcc/go/go-gcc.cc	(revision 242724)
+++ gcc/go/go-gcc.cc	(working copy)
@@ -412,9 +412,8 @@  class Gcc_backend : public Backend
   { return new Bvariable(error_mark_node); }
 
   Bvariable*
-  global_variable(const std::string& package_name,
-		  const std::string& pkgpath,
-		  const std::string& name,
+  global_variable(const std::string& var_name,
+		  const std::string& asm_name,
 		  Btype* btype,
 		  bool is_external,
 		  bool is_hidden,
@@ -440,25 +439,27 @@  class Gcc_backend : public Backend
 		     Location, Bstatement**);
 
   Bvariable*
-  implicit_variable(const std::string&, Btype*, bool, bool, bool,
-		    int64_t);
+  implicit_variable(const std::string&, const std::string&, Btype*,
+                    bool, bool, bool, int64_t);
 
   void
   implicit_variable_set_init(Bvariable*, const std::string&, Btype*,
 			     bool, bool, bool, Bexpression*);
 
   Bvariable*
-  implicit_variable_reference(const std::string&, Btype*);
+  implicit_variable_reference(const std::string&, const std::string&, Btype*);
 
   Bvariable*
-  immutable_struct(const std::string&, bool, bool, Btype*, Location);
+  immutable_struct(const std::string&, const std::string&,
+                   bool, bool, Btype*, Location);
 
   void
   immutable_struct_set_init(Bvariable*, const std::string&, bool, bool, Btype*,
 			    Location, Bexpression*);
 
   Bvariable*
-  immutable_struct_reference(const std::string&, Btype*, Location);
+  immutable_struct_reference(const std::string&, const std::string&,
+                             Btype*, Location);
 
   // Labels.
 
@@ -550,102 +551,6 @@  get_identifier_from_string(const std::st
   return get_identifier_with_length(str.data(), str.length());
 }
 
-// Return whether the character c is OK to use in the assembler.
-
-static bool
-char_needs_encoding(char c)
-{
-  switch (c)
-    {
-    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
-    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
-    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
-    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
-    case 'Y': case 'Z':
-    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
-    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
-    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
-    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
-    case 'y': case 'z':
-    case '0': case '1': case '2': case '3': case '4':
-    case '5': case '6': case '7': case '8': case '9':
-    case '_': case '.': case '$': case '/':
-      return false;
-    default:
-      return true;
-    }
-}
-
-// Return whether the identifier needs to be translated because it
-// contains non-ASCII characters.
-
-static bool
-needs_encoding(const std::string& str)
-{
-  for (std::string::const_iterator p = str.begin();
-       p != str.end();
-       ++p)
-    if (char_needs_encoding(*p))
-      return true;
-  return false;
-}
-
-// Pull the next UTF-8 character out of P and store it in *PC.  Return
-// the number of bytes read.
-
-static size_t
-fetch_utf8_char(const char* p, unsigned int* pc)
-{
-  unsigned char c = *p;
-  if ((c & 0x80) == 0)
-    {
-      *pc = c;
-      return 1;
-    }
-  size_t len = 0;
-  while ((c & 0x80) != 0)
-    {
-      ++len;
-      c <<= 1;
-    }
-  unsigned int rc = *p & ((1 << (7 - len)) - 1);
-  for (size_t i = 1; i < len; i++)
-    {
-      unsigned int u = p[i];
-      rc <<= 6;
-      rc |= u & 0x3f;
-    }
-  *pc = rc;
-  return len;
-}
-
-// Encode an identifier using ASCII characters.
-
-static std::string
-encode_id(const std::string id)
-{
-  std::string ret;
-  const char* p = id.c_str();
-  const char* pend = p + id.length();
-  while (p < pend)
-    {
-      unsigned int c;
-      size_t len = fetch_utf8_char(p, &c);
-      if (len == 1 && !char_needs_encoding(c))
-	ret += c;
-      else
-	{
-	  ret += "$U";
-	  char buf[30];
-	  snprintf(buf, sizeof buf, "%x", c);
-	  ret += buf;
-	  ret += "$";
-	}
-      p += len;
-    }
-  return ret;
-}
-
 // Define the built-in functions that are exposed to GCCGo.
 
 Gcc_backend::Gcc_backend()
@@ -2580,9 +2485,8 @@  Gcc_backend::non_zero_size_type(tree typ
 // Make a global variable.
 
 Bvariable*
-Gcc_backend::global_variable(const std::string& package_name,
-			     const std::string& pkgpath,
-			     const std::string& name,
+Gcc_backend::global_variable(const std::string& var_name,
+			     const std::string& asm_name,
 			     Btype* btype,
 			     bool is_external,
 			     bool is_hidden,
@@ -2598,9 +2502,6 @@  Gcc_backend::global_variable(const std::
   if ((is_external || !is_hidden) && int_size_in_bytes(type_tree) == 0)
     type_tree = this->non_zero_size_type(type_tree);
 
-  std::string var_name(package_name);
-  var_name.push_back('.');
-  var_name.append(name);
   tree decl = build_decl(location.gcc_location(), VAR_DECL,
 			 get_identifier_from_string(var_name),
 			 type_tree);
@@ -2611,17 +2512,12 @@  Gcc_backend::global_variable(const std::
   if (!is_hidden)
     {
       TREE_PUBLIC(decl) = 1;
-
-      std::string asm_name(pkgpath);
-      asm_name.push_back('.');
-      asm_name.append(name);
-      if (needs_encoding(asm_name))
-	asm_name = encode_id(asm_name);
       SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
     }
-  else if (needs_encoding(var_name))
-    SET_DECL_ASSEMBLER_NAME(decl,
-			    get_identifier_from_string(encode_id(var_name)));
+  else
+    {
+      SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
+    }
 
   TREE_USED(decl) = 1;
 
@@ -2814,8 +2710,9 @@  Gcc_backend::temporary_variable(Bfunctio
 // generating GC root variables and storing the values of a slice initializer.
 
 Bvariable*
-Gcc_backend::implicit_variable(const std::string& name, Btype* type,
-			       bool is_hidden, bool is_constant,
+Gcc_backend::implicit_variable(const std::string& name,
+                               const std::string& asm_name,
+                               Btype* type, bool is_hidden, bool is_constant,
 			       bool is_common, int64_t alignment)
 {
   tree type_tree = type->get_tree();
@@ -2857,8 +2754,8 @@  Gcc_backend::implicit_variable(const std
       SET_DECL_ALIGN(decl, alignment * BITS_PER_UNIT);
       DECL_USER_ALIGN(decl) = 1;
     }
-  if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
+  if (! asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
 
   go_preserve_from_gc(decl);
   return new Bvariable(decl);
@@ -2899,7 +2796,9 @@  Gcc_backend::implicit_variable_set_init(
 // Return a reference to an implicit variable defined in another package.
 
 Bvariable*
-Gcc_backend::implicit_variable_reference(const std::string& name, Btype* btype)
+Gcc_backend::implicit_variable_reference(const std::string& name,
+                                         const std::string& asm_name,
+                                         Btype* btype)
 {
   tree type_tree = btype->get_tree();
   if (type_tree == error_mark_node)
@@ -2911,8 +2810,8 @@  Gcc_backend::implicit_variable_reference
   TREE_PUBLIC(decl) = 1;
   TREE_STATIC(decl) = 1;
   DECL_ARTIFICIAL(decl) = 1;
-  if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
+  if (! asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
   go_preserve_from_gc(decl);
   return new Bvariable(decl);
 }
@@ -2920,7 +2819,9 @@  Gcc_backend::implicit_variable_reference
 // Create a named immutable initialized data structure.
 
 Bvariable*
-Gcc_backend::immutable_struct(const std::string& name, bool is_hidden,
+Gcc_backend::immutable_struct(const std::string& name,
+                              const std::string& asm_name,
+                              bool is_hidden,
 			      bool is_common, Btype* btype, Location location)
 {
   tree type_tree = btype->get_tree();
@@ -2937,8 +2838,8 @@  Gcc_backend::immutable_struct(const std:
   DECL_ARTIFICIAL(decl) = 1;
   if (!is_hidden)
     TREE_PUBLIC(decl) = 1;
-  if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
+  if (! asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
 
   // When the initializer for one immutable_struct refers to another,
   // it needs to know the visibility of the referenced struct so that
@@ -2998,7 +2899,9 @@  Gcc_backend::immutable_struct_set_init(B
 // defined in another package.
 
 Bvariable*
-Gcc_backend::immutable_struct_reference(const std::string& name, Btype* btype,
+Gcc_backend::immutable_struct_reference(const std::string& name,
+                                        const std::string& asm_name,
+                                        Btype* btype,
 					Location location)
 {
   tree type_tree = btype->get_tree();
@@ -3013,8 +2916,8 @@  Gcc_backend::immutable_struct_reference(
   DECL_ARTIFICIAL(decl) = 1;
   TREE_PUBLIC(decl) = 1;
   DECL_EXTERNAL(decl) = 1;
-  if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
+  if (! asm_name.empty())
+    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
   go_preserve_from_gc(decl);
   return new Bvariable(decl);
 }
@@ -3104,10 +3007,8 @@  Gcc_backend::function(Btype* fntype, con
     return this->error_function();
 
   tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype);
-  if (!asm_name.empty())
+  if (! asm_name.empty())
     SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
-  else if (needs_encoding(name))
-    SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(encode_id(name)));
   if (is_visible)
     TREE_PUBLIC(decl) = 1;
   if (is_declaration)
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 242724)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -1,4 +1,4 @@ 
-e66f30e862cb5d02b9d55bf44ac439bb8fc4ea19
+4d8e00e730897cc7e73b1582522ecab031cfcaf2
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/backend.h
===================================================================
--- gcc/go/gofrontend/backend.h	(revision 242724)
+++ gcc/go/gofrontend/backend.h	(working copy)
@@ -482,21 +482,19 @@  class Backend
   virtual Bvariable*
   error_variable() = 0;
 
-  // Create a global variable.  PACKAGE_NAME is the name of the
-  // package where the variable is defined.  PKGPATH is the package
-  // path for that package, from the -fgo-pkgpath or -fgo-prefix
-  // option.  NAME is the name of the variable.  BTYPE is the type of
-  // the variable.  IS_EXTERNAL is true if the variable is defined in
-  // some other package.  IS_HIDDEN is true if the variable is not
-  // exported (name begins with a lower case letter).
-  // IN_UNIQUE_SECTION is true if the variable should be put into a
-  // unique section if possible; this is intended to permit the linker
-  // to garbage collect the variable if it is not referenced.
-  // LOCATION is where the variable was defined.
-  virtual Bvariable*
-  global_variable(const std::string& package_name,
-		  const std::string& pkgpath,
-		  const std::string& name,
+  // Create a global variable. NAME is the package-qualified name of
+  // the variable.  ASM_NAME is the encoded identifier for the
+  // variable, incorporating the package, and made safe for the
+  // assembler.  BTYPE is the type of the variable.  IS_EXTERNAL is
+  // true if the variable is defined in some other package.  IS_HIDDEN
+  // is true if the variable is not exported (name begins with a lower
+  // case letter).  IN_UNIQUE_SECTION is true if the variable should
+  // be put into a unique section if possible; this is intended to
+  // permit the linker to garbage collect the variable if it is not
+  // referenced.  LOCATION is where the variable was defined.
+  virtual Bvariable*
+  global_variable(const std::string& name,
+                  const std::string& asm_name,
 		  Btype* btype,
 		  bool is_external,
 		  bool is_hidden,
@@ -561,6 +559,9 @@  class Backend
   //
   // NAME is the name to use for the initialized variable this will create.
   //
+  // ASM_NAME is encoded assembler-friendly version of the name, or the
+  // empty string if no encoding is needed.
+  //
   // TYPE is the type of the implicit variable. 
   //
   // IS_HIDDEN will be true if the descriptor should only be visible
@@ -578,8 +579,9 @@  class Backend
   //
   // If ALIGNMENT is not zero, it is the desired alignment of the variable.
   virtual Bvariable*
-  implicit_variable(const std::string& name, Btype* type, bool is_hidden,
-		    bool is_constant, bool is_common, int64_t alignment) = 0;
+  implicit_variable(const std::string& name, const std::string& asm_name,
+                    Btype* type, bool is_hidden, bool is_constant,
+                    bool is_common, int64_t alignment) = 0;
 
 
   // Set the initial value of a variable created by implicit_variable.
@@ -597,12 +599,15 @@  class Backend
 			     bool is_hidden, bool is_constant, bool is_common,
 			     Bexpression* init) = 0;
 
-  // Create a reference to a named implicit variable defined in some other
-  // package.  This will be a variable created by a call to implicit_variable
-  // with the same NAME and TYPE and with IS_COMMON passed as false.  This
-  // corresponds to an extern global variable in C.
-  virtual Bvariable*
-  implicit_variable_reference(const std::string& name, Btype* type) = 0;
+  // Create a reference to a named implicit variable defined in some
+  // other package.  This will be a variable created by a call to
+  // implicit_variable with the same NAME, ASM_NAME and TYPE and with
+  // IS_COMMON passed as false.  This corresponds to an extern global
+  // variable in C.
+  virtual Bvariable*
+  implicit_variable_reference(const std::string& name,
+                              const std::string& asm_name,
+                              Btype* type) = 0;
 
   // Create a named immutable initialized data structure.  This is
   // used for type descriptors, map descriptors, and function
@@ -612,6 +617,9 @@  class Backend
   // NAME is the name to use for the initialized global variable which
   // this call will create.
   //
+  // ASM_NAME is the encoded, assembler-friendly version of NAME, or
+  // the empty string if no encoding is needed.
+  //
   // IS_HIDDEN will be true if the descriptor should only be visible
   // within the current object.
   //
@@ -630,7 +638,9 @@  class Backend
   // address.  After calling this the frontend will call
   // immutable_struct_set_init.
   virtual Bvariable*
-  immutable_struct(const std::string& name, bool is_hidden, bool is_common,
+  immutable_struct(const std::string& name,
+                   const std::string& asm_name,
+                   bool is_hidden, bool is_common,
 		   Btype* type, Location) = 0;
 
   // Set the initial value of a variable created by immutable_struct.
@@ -648,11 +658,12 @@  class Backend
   // Create a reference to a named immutable initialized data
   // structure defined in some other package.  This will be a
   // structure created by a call to immutable_struct with the same
-  // NAME and TYPE and with IS_COMMON passed as false.  This
+  // NAME, ASM_NAME and TYPE and with IS_COMMON passed as false.  This
   // corresponds to an extern const global variable in C.
   virtual Bvariable*
-  immutable_struct_reference(const std::string& name, Btype* type,
-			     Location) = 0;
+  immutable_struct_reference(const std::string& name,
+                             const std::string& asm_name,
+                             Btype* type, Location) = 0;
 
   // Labels.
   
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 242724)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -11,6 +11,7 @@ 
 #include "go-c.h"
 #include "gogo.h"
 #include "go-diagnostics.h"
+#include "go-encode-id.h"
 #include "types.h"
 #include "export.h"
 #include "import.h"
@@ -1304,16 +1305,18 @@  Func_descriptor_expression::do_get_backe
   Btype* btype = this->type()->get_backend(gogo);
 
   Bvariable* bvar;
+  std::string asm_name(go_selectively_encode_id(var_name));
   if (no->package() != NULL || is_descriptor)
-    bvar = context->backend()->immutable_struct_reference(var_name, btype,
-							  loc);
+    bvar = context->backend()->immutable_struct_reference(var_name, asm_name,
+                                                          btype, loc);
   else
     {
       Location bloc = Linemap::predeclared_location();
       bool is_hidden = ((no->is_function()
 			 && no->func_value()->enclosing() != NULL)
 			|| Gogo::is_thunk(no));
-      bvar = context->backend()->immutable_struct(var_name, is_hidden, false,
+      bvar = context->backend()->immutable_struct(var_name, asm_name,
+                                                  is_hidden, false,
 						  btype, bloc);
       Expression_list* vals = new Expression_list();
       vals->push_back(Expression::make_func_code_reference(this->fn_, bloc));
@@ -4283,9 +4286,11 @@  Unary_expression::do_get_backend(Transla
 	      // read-only, because the program is permitted to change it.
 	      copy_to_heap = context->function() != NULL;
 	    }
+          std::string asm_name(go_selectively_encode_id(buf));
 	  Bvariable* implicit =
-	    gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap,
-					       false, 0);
+              gogo->backend()->implicit_variable(buf, asm_name,
+                                                 btype, true, copy_to_heap,
+                                                 false, 0);
 	  gogo->backend()->implicit_variable_set_init(implicit, buf, btype,
 						      true, copy_to_heap, false,
 						      bexpr);
@@ -4299,8 +4304,10 @@  Unary_expression::do_get_backend(Transla
           snprintf(buf, sizeof buf, "C%u", counter);
           ++counter;
 
+          std::string asm_name(go_selectively_encode_id(buf));
           Bvariable* decl =
-              gogo->backend()->immutable_struct(buf, true, false, btype, loc);
+              gogo->backend()->immutable_struct(buf, asm_name,
+                                                true, false, btype, loc);
           gogo->backend()->immutable_struct_set_init(decl, buf, true, false,
                                                      btype, loc, bexpr);
           bexpr = gogo->backend()->var_expression(decl, loc);
@@ -15074,8 +15081,10 @@  Interface_mtable_expression::do_get_back
       && this->type_->named_type()->named_object()->package() != NULL)
     {
       Btype* btype = this->type()->get_backend(gogo);
+      std::string asm_name(go_selectively_encode_id(mangled_name));
       this->bvar_ =
-          gogo->backend()->immutable_struct_reference(mangled_name, btype, loc);
+          gogo->backend()->immutable_struct_reference(mangled_name, asm_name,
+                                                      btype, loc);
       return gogo->backend()->var_expression(this->bvar_, this->location());
     }
 
@@ -15119,7 +15128,8 @@  Interface_mtable_expression::do_get_back
   Bexpression* ctor = mtable->get_backend(context);
 
   bool is_public = has_hidden_methods && this->type_->named_type() != NULL;
-  this->bvar_ = gogo->backend()->immutable_struct(mangled_name, false,
+  std::string asm_name(go_selectively_encode_id(mangled_name));
+  this->bvar_ = gogo->backend()->immutable_struct(mangled_name, asm_name, false,
 						  !is_public, btype, loc);
   gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false,
                                              !is_public, btype, loc, ctor);
Index: gcc/go/gofrontend/go-encode-id.cc
===================================================================
--- gcc/go/gofrontend/go-encode-id.cc	(revision 0)
+++ gcc/go/gofrontend/go-encode-id.cc	(working copy)
@@ -0,0 +1,113 @@ 
+// go-encode-id.cc -- Go identifier encoding hooks
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "go-location.h"
+#include "go-linemap.h"
+#include "go-encode-id.h"
+
+// Return whether the character c is OK to use in the assembler.
+
+static bool
+char_needs_encoding(char c)
+{
+  switch (c)
+    {
+    case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
+    case 'G': case 'H': case 'I': case 'J': case 'K': case 'L':
+    case 'M': case 'N': case 'O': case 'P': case 'Q': case 'R':
+    case 'S': case 'T': case 'U': case 'V': case 'W': case 'X':
+    case 'Y': case 'Z':
+    case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
+    case 'g': case 'h': case 'i': case 'j': case 'k': case 'l':
+    case 'm': case 'n': case 'o': case 'p': case 'q': case 'r':
+    case 's': case 't': case 'u': case 'v': case 'w': case 'x':
+    case 'y': case 'z':
+    case '0': case '1': case '2': case '3': case '4':
+    case '5': case '6': case '7': case '8': case '9':
+    case '_': case '.': case '$': case '/':
+      return false;
+    default:
+      return true;
+    }
+}
+
+// Return whether the identifier needs to be translated because it
+// contains non-ASCII characters.
+
+bool
+go_id_needs_encoding(const std::string& str)
+{
+  for (std::string::const_iterator p = str.begin();
+       p != str.end();
+       ++p)
+    if (char_needs_encoding(*p))
+      return true;
+  return false;
+}
+
+// Pull the next UTF-8 character out of P and store it in *PC.  Return
+// the number of bytes read.
+
+static size_t
+fetch_utf8_char(const char* p, unsigned int* pc)
+{
+  unsigned char c = *p;
+  if ((c & 0x80) == 0)
+    {
+      *pc = c;
+      return 1;
+    }
+  size_t len = 0;
+  while ((c & 0x80) != 0)
+    {
+      ++len;
+      c <<= 1;
+    }
+  unsigned int rc = *p & ((1 << (7 - len)) - 1);
+  for (size_t i = 1; i < len; i++)
+    {
+      unsigned int u = p[i];
+      rc <<= 6;
+      rc |= u & 0x3f;
+    }
+  *pc = rc;
+  return len;
+}
+
+// Encode an identifier using ASCII characters.
+
+std::string
+go_encode_id(const std::string &id)
+{
+  std::string ret;
+  const char* p = id.c_str();
+  const char* pend = p + id.length();
+  while (p < pend)
+    {
+      unsigned int c;
+      size_t len = fetch_utf8_char(p, &c);
+      if (len == 1 && !char_needs_encoding(c))
+        ret += c;
+      else
+        {
+          ret += "$U";
+          char buf[30];
+          snprintf(buf, sizeof buf, "%x", c);
+          ret += buf;
+          ret += "$";
+        }
+      p += len;
+    }
+  return ret;
+}
+
+std::string
+go_selectively_encode_id(const std::string &id)
+{
+  if (go_id_needs_encoding(id))
+    return go_encode_id(id);
+  return std::string();
+}
Index: gcc/go/gofrontend/go-encode-id.h
===================================================================
--- gcc/go/gofrontend/go-encode-id.h	(revision 0)
+++ gcc/go/gofrontend/go-encode-id.h	(working copy)
@@ -0,0 +1,30 @@ 
+// go-encode-id.h -- Go identifier encoding utilities  -*- C++ -*-
+
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#ifndef GO_ENCODE_ID_H
+#define GO_ENCODE_ID_H
+
+#include "backend.h"
+
+// Given an identifier corresponding to a function or variable,
+// this helper returns TRUE if the identifier needs special
+// encoding to be used as an ASM name (symbol), FALSE if the name
+// is OK as is.
+extern bool
+go_id_needs_encoding(const std::string& str);
+
+// Encodes the specified identifier for ASM name safety, returning a
+// string with the encoded value.
+extern std::string
+go_encode_id(const std::string &id);
+
+// Returns the empty string if the specified name needs encoding,
+// otherwise invokes go_encode_id() on the name and returns the
+// result.
+extern std::string
+go_selectively_encode_id(const std::string &id);
+
+#endif // !defined(GO_ENCODE_ID_H)
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 242724)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -12,6 +12,7 @@ 
 
 #include "go-c.h"
 #include "go-diagnostics.h"
+#include "go-encode-id.h"
 #include "go-dump.h"
 #include "go-optimize.h"
 #include "lex.h"
@@ -5326,6 +5327,10 @@  Function::get_or_make_decl(Gogo* gogo, N
       if ((this->pragmas_ & GOPRAGMA_NOSPLIT) != 0)
 	disable_split_stack = true;
 
+      // Encode name if asm_name not already set at this point
+      if (asm_name.empty() && go_id_needs_encoding(no->get_id(gogo)))
+        asm_name = go_encode_id(no->get_id(gogo));
+
       // This should go into a unique section if that has been
       // requested elsewhere, or if this is a nointerface function.
       // We want to put a nointerface function into a unique section
@@ -5379,6 +5384,8 @@  Function_declaration::get_or_make_decl(G
               asm_name.append(rtype->mangled_name(gogo));
             }
         }
+      else if (go_id_needs_encoding(no->get_id(gogo)))
+        asm_name = go_encode_id(no->get_id(gogo));
 
       Btype* functype = this->fntype_->get_backend_fntype(gogo);
       this->fndecl_ =
@@ -6594,25 +6601,39 @@  Variable::get_backend_variable(Gogo* gog
 	      type = Type::make_pointer_type(type);
 	    }
 
-	  std::string n = Gogo::unpack_hidden_name(name);
+	  const std::string n = Gogo::unpack_hidden_name(name);
 	  Btype* btype = type->get_backend(gogo);
 
 	  Bvariable* bvar;
 	  if (Map_type::is_zero_value(this))
 	    bvar = Map_type::backend_zero_value(gogo);
 	  else if (this->is_global_)
-	    bvar = backend->global_variable((package == NULL
-					     ? gogo->package_name()
-					     : package->package_name()),
-					    (package == NULL
-					     ? gogo->pkgpath_symbol()
-					     : package->pkgpath_symbol()),
-					    n,
-					    btype,
-					    package != NULL,
-					    Gogo::is_hidden_name(name),
-					    this->in_unique_section_,
-					    this->location_);
+	    {
+	      std::string var_name(package != NULL
+				   ? package->package_name()
+				   : gogo->package_name());
+	      var_name.push_back('.');
+	      var_name.append(n);
+              std::string asm_name;
+              if (Gogo::is_hidden_name(name))
+                asm_name = var_name;
+              else
+                {
+                  asm_name = package != NULL
+                      ? package->pkgpath_symbol()
+                      : gogo->pkgpath_symbol();
+                  asm_name.push_back('.');
+                  asm_name.append(n);
+                }
+	      asm_name = go_encode_id(asm_name);
+	      bvar = backend->global_variable(var_name,
+					      asm_name,
+					      btype,
+					      package != NULL,
+					      Gogo::is_hidden_name(name),
+					      this->in_unique_section_,
+					      this->location_);
+	    }
 	  else if (function == NULL)
 	    {
 	      go_assert(saw_errors());
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc	(revision 242724)
+++ gcc/go/gofrontend/types.cc	(working copy)
@@ -11,6 +11,7 @@ 
 #include "go-c.h"
 #include "gogo.h"
 #include "go-diagnostics.h"
+#include "go-encode-id.h"
 #include "operator.h"
 #include "expressions.h"
 #include "statements.h"
@@ -1217,10 +1218,12 @@  Type::make_type_descriptor_var(Gogo* gog
 
       Type* td_type = Type::make_type_descriptor_type();
       Btype* td_btype = td_type->get_backend(gogo);
+      const char *name = "__go_tdn_unsafe.Pointer";
+      std::string asm_name(go_selectively_encode_id(name));
       this->type_descriptor_var_ =
-	gogo->backend()->immutable_struct_reference("__go_tdn_unsafe.Pointer",
-						    td_btype,
-						    bloc);
+	  gogo->backend()->immutable_struct_reference(name, asm_name,
+						      td_btype,
+						      bloc);
 
       if (phash != NULL)
 	*phash = this->type_descriptor_var_;
@@ -1239,10 +1242,11 @@  Type::make_type_descriptor_var(Gogo* gog
   const Package* dummy;
   if (this->type_descriptor_defined_elsewhere(nt, &dummy))
     {
+      std::string asm_name(go_selectively_encode_id(var_name));
       this->type_descriptor_var_ =
-	gogo->backend()->immutable_struct_reference(var_name,
-						    initializer_btype,
-						    loc);
+	  gogo->backend()->immutable_struct_reference(var_name, asm_name,
+						      initializer_btype,
+						      loc);
       if (phash != NULL)
 	*phash = this->type_descriptor_var_;
       return;
@@ -1271,8 +1275,9 @@  Type::make_type_descriptor_var(Gogo* gog
   // ensure that type_descriptor_pointer will work if called while
   // converting INITIALIZER.
 
+  std::string asm_name(go_selectively_encode_id(var_name));
   this->type_descriptor_var_ =
-    gogo->backend()->immutable_struct(var_name, false, is_common,
+      gogo->backend()->immutable_struct(var_name, asm_name, false, is_common,
 				      initializer_btype, loc);
   if (phash != NULL)
     *phash = this->type_descriptor_var_;
@@ -2187,8 +2192,10 @@  Type::make_gc_symbol_var(Gogo* gogo)
   const Package* dummy;
   if (this->type_descriptor_defined_elsewhere(nt, &dummy))
     {
+      std::string asm_name(go_selectively_encode_id(sym_name));
       this->gc_symbol_var_ =
-	gogo->backend()->implicit_variable_reference(sym_name, sym_btype);
+          gogo->backend()->implicit_variable_reference(sym_name, asm_name,
+                                                       sym_btype);
       if (phash != NULL)
 	*phash = this->gc_symbol_var_;
       return;
@@ -2213,8 +2220,10 @@  Type::make_gc_symbol_var(Gogo* gogo)
   // Since we are building the GC symbol in this package, we must create the
   // variable before converting the initializer to its backend representation
   // because the initializer may refer to the GC symbol for this type.
+  std::string asm_name(go_selectively_encode_id(sym_name));
   this->gc_symbol_var_ =
-    gogo->backend()->implicit_variable(sym_name, sym_btype, false, true, is_common, 0);
+      gogo->backend()->implicit_variable(sym_name, asm_name,
+                                         sym_btype, false, true, is_common, 0);
   if (phash != NULL)
     *phash = this->gc_symbol_var_;
 
@@ -7034,8 +7043,10 @@  Map_type::backend_zero_value(Gogo* gogo)
   Btype* barray_type = gogo->backend()->array_type(buint8_type, blength);
 
   std::string zname = Map_type::zero_value->name();
+  std::string asm_name(go_selectively_encode_id(zname));
   Bvariable* zvar =
-    gogo->backend()->implicit_variable(zname, barray_type, false, true, true,
+      gogo->backend()->implicit_variable(zname, asm_name,
+                                         barray_type, false, true, true,
 				       Map_type::zero_value_align);
   gogo->backend()->implicit_variable_set_init(zvar, zname, barray_type,
 					      false, true, true, NULL);