This Go patch by Cherry Zhang open codes some type assertions.  Now
that type equality is just simple pointer equality, we can open code
some type assertions instead of making runtime calls.  Bootstrapped
and ran Go testsuite on x86_64-pc-linux-gnu.  Committed to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 272550)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-593f94f008c24f5abfe7f917a717cf2b0a2585e2
+5bca69ab3b41df535193474baecc3a8a4c0b3dbe
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc    (revision 272549)
+++ gcc/go/gofrontend/expressions.cc    (working copy)
@@ -486,9 +486,11 @@ Expression::convert_interface_to_type(Ty
   // We are going to evaluate RHS multiple times.
   go_assert(rhs->is_variable());
 
-  // Call a function to check that the type is valid.  The function
-  // will panic with an appropriate runtime type error if the type is
-  // not valid.
+  // Build an expression to check that the type is valid.  It will
+  // panic with an appropriate runtime type error if the type is not
+  // valid.
+  // (lhs_type != rhs_type ? panicdottype(lhs_type, rhs_type, inter_type) :
+  //    nil /*dummy*/)
   Expression* lhs_type_expr = Expression::make_type_descriptor(lhs_type,
                                                                 location);
   Expression* rhs_descriptor =
@@ -498,11 +500,18 @@ Expression::convert_interface_to_type(Ty
   Expression* rhs_inter_expr = Expression::make_type_descriptor(rhs_type,
                                                                 location);
 
-  Expression* check_iface = Runtime::make_call(Runtime::ASSERTI2T,
-                                               location, 3, lhs_type_expr,
-                                               rhs_descriptor, rhs_inter_expr);
+  Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, lhs_type_expr,
+                                             rhs_descriptor, location);
+  rhs_descriptor = Expression::get_interface_type_descriptor(rhs);
+  Expression* panic = Runtime::make_call(Runtime::PANICDOTTYPE, location,
+                                         3, lhs_type_expr->copy(),
+                                         rhs_descriptor,
+                                         rhs_inter_expr);
+  Expression* nil = Expression::make_nil(location);
+  Expression* check = Expression::make_conditional(cond, panic, nil,
+                                                   location);
 
-  // If the call succeeds, pull out the value.
+  // If the conversion succeeds, pull out the value.
   Expression* obj = Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT,
                                                     location);
 
@@ -517,7 +526,7 @@ Expression::convert_interface_to_type(Ty
       obj = Expression::make_dereference(obj, NIL_CHECK_NOT_NEEDED,
                                          location);
     }
-  return Expression::make_compound(check_iface, obj, location);
+  return Expression::make_compound(check, obj, location);
 }
 
 // Convert an expression to its backend representation.  This is implemented by
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h     (revision 272549)
+++ gcc/go/gofrontend/expressions.h     (working copy)
@@ -1074,6 +1074,11 @@ class Expression
   static Expression*
   unpack_direct_iface(Expression*, Location);
 
+  // Return an expression representing the type descriptor field of an
+  // interface.
+  static Expression*
+  get_interface_type_descriptor(Expression*);
+
   // Look through the expression of a Slice_value_expression's valmem to
   // find an call to makeslice.
   static std::pair<Call_expression*, Temporary_statement*>
@@ -1257,9 +1262,6 @@ class Expression
   }
 
   static Expression*
-  get_interface_type_descriptor(Expression*);
-
-  static Expression*
   convert_interface_to_type(Type*, Expression*, Location);
 
   static Expression*
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc   (revision 272133)
+++ gcc/go/gofrontend/gogo.cc   (working copy)
@@ -6243,7 +6243,8 @@ Function_declaration::get_or_make_decl(G
            }
 
          if (this->asm_name_ == "runtime.gopanic"
-             || this->asm_name_ == "__go_runtime_error")
+             || this->asm_name_ == "__go_runtime_error"
+              || this->asm_name_ == "runtime.panicdottype")
            flags |= Backend::function_does_not_return;
        }
 
Index: gcc/go/gofrontend/runtime.def
===================================================================
--- gcc/go/gofrontend/runtime.def       (revision 272549)
+++ gcc/go/gofrontend/runtime.def       (working copy)
@@ -320,23 +320,13 @@ DEF_GO_RUNTIME(ASSERTITAB, "runtime.asse
 DEF_GO_RUNTIME(REQUIREITAB, "runtime.requireitab", P2(TYPE, TYPE),
               R1(POINTER))
 
-// Check whether an interface type may be converted to a
-// non-interface type.
-DEF_GO_RUNTIME(ASSERTI2T, "runtime.assertI2T", P3(TYPE, TYPE, TYPE), R0())
+// Panic when an interface type to non-interface type conversion fails.
+DEF_GO_RUNTIME(PANICDOTTYPE, "runtime.panicdottype", P3(TYPE, TYPE, TYPE),
+               R0())
 
 // Return whether we can convert a type to an interface type.
 DEF_GO_RUNTIME(IFACET2IP, "runtime.ifaceT2Ip", P2(TYPE, TYPE), R1(BOOL))
 
-// Get the type descriptor of an empty interface.
-DEF_GO_RUNTIME(EFACETYPE, "runtime.efacetype", P1(EFACE), R1(TYPE))
-
-// Get the type descriptor of a non-empty interface.
-DEF_GO_RUNTIME(IFACETYPE, "runtime.ifacetype", P1(IFACE), R1(TYPE))
-
-
-// Compare two type descriptors for equality.
-DEF_GO_RUNTIME(IFACETYPEEQ, "runtime.ifacetypeeq", P2(TYPE, TYPE), R1(BOOL))
-
 // Compare two empty interface values.
 DEF_GO_RUNTIME(EFACEEQ, "runtime.efaceeq", P2(EFACE, EFACE), R1(BOOL))
 
Index: gcc/go/gofrontend/statements.cc
===================================================================
--- gcc/go/gofrontend/statements.cc     (revision 272549)
+++ gcc/go/gofrontend/statements.cc     (working copy)
@@ -4614,11 +4614,12 @@ Type_case_clauses::Type_case_clause::low
        cond = Expression::make_binary(OPERATOR_EQEQ, ref,
                                       Expression::make_nil(loc),
                                       loc);
+      else if (type->interface_type() == NULL)
+        cond = Expression::make_binary(OPERATOR_EQEQ, ref,
+                                       Expression::make_type_descriptor(type, 
loc),
+                                       loc);
       else
-       cond = Runtime::make_call((type->interface_type() == NULL
-                                  ? Runtime::IFACETYPEEQ
-                                  : Runtime::IFACET2IP),
-                                 loc, 2,
+       cond = Runtime::make_call(Runtime::IFACET2IP, loc, 2,
                                  Expression::make_type_descriptor(type, loc),
                                  ref);
 
@@ -4871,23 +4872,23 @@ Type_switch_statement::do_lower(Gogo*, N
       return Statement::make_error_statement(loc);
     }
 
+  Temporary_statement* val_temp =
+    Statement::make_temporary(NULL, this->expr_, loc);
+  b->add_statement(val_temp);
+
   // var descriptor_temp DESCRIPTOR_TYPE
   Type* descriptor_type = Type::make_type_descriptor_ptr_type();
   Temporary_statement* descriptor_temp =
     Statement::make_temporary(descriptor_type, NULL, loc);
   b->add_statement(descriptor_temp);
 
-  // descriptor_temp = ifacetype(val_temp) FIXME: This should be
-  // inlined.
-  bool is_empty = val_type->interface_type()->is_empty();
-  Expression* call = Runtime::make_call((is_empty
-                                        ? Runtime::EFACETYPE
-                                        : Runtime::IFACETYPE),
-                                       loc, 1, this->expr_);
+  // descriptor_temp = ifacetype(val_temp)
+  Expression* ref = Expression::make_temporary_reference(val_temp, loc);
+  Expression* td = Expression::get_interface_type_descriptor(ref);
   Temporary_reference_expression* lhs =
     Expression::make_temporary_reference(descriptor_temp, loc);
   lhs->set_is_lvalue();
-  Statement* s = Statement::make_assignment(lhs, call, loc);
+  Statement* s = Statement::make_assignment(lhs, td, loc);
   b->add_statement(s);
 
   if (this->clauses_ != NULL)
Index: libgo/go/runtime/iface.go
===================================================================
--- libgo/go/runtime/iface.go   (revision 272127)
+++ libgo/go/runtime/iface.go   (working copy)
@@ -15,10 +15,7 @@ import (
 //
 //go:linkname requireitab runtime.requireitab
 //go:linkname assertitab runtime.assertitab
-//go:linkname assertI2T runtime.assertI2T
-//go:linkname ifacetypeeq runtime.ifacetypeeq
-//go:linkname efacetype runtime.efacetype
-//go:linkname ifacetype runtime.ifacetype
+//go:linkname panicdottype runtime.panicdottype
 //go:linkname ifaceE2E2 runtime.ifaceE2E2
 //go:linkname ifaceI2E2 runtime.ifaceI2E2
 //go:linkname ifaceE2I2 runtime.ifaceE2I2
@@ -356,35 +353,9 @@ func assertitab(lhs, rhs *_type) unsafe.
        return getitab(lhs, rhs, false)
 }
 
-// Check whether an interface type may be converted to a non-interface
-// type, panicing if not.
-func assertI2T(lhs, rhs, inter *_type) {
-       if rhs == nil {
-               panic(&TypeAssertionError{nil, nil, lhs, ""})
-       }
-       if !eqtype(lhs, rhs) {
-               panic(&TypeAssertionError{inter, rhs, lhs, ""})
-       }
-}
-
-// Compare two type descriptors for equality.
-func ifacetypeeq(a, b *_type) bool {
-       return eqtype(a, b)
-}
-
-// Return the type descriptor of an empty interface.
-// FIXME: This should be inlined by the compiler.
-func efacetype(e eface) *_type {
-       return e._type
-}
-
-// Return the type descriptor of a non-empty interface.
-// FIXME: This should be inlined by the compiler.
-func ifacetype(i iface) *_type {
-       if i.tab == nil {
-               return nil
-       }
-       return *(**_type)(i.tab)
+// panicdottype is called when doing an i.(T) conversion and the conversion 
fails.
+func panicdottype(lhs, rhs, inter *_type) {
+       panic(&TypeAssertionError{inter, rhs, lhs, ""})
 }
 
 // Convert an empty interface to an empty interface, for a comma-ok

Reply via email to