compiler: open code some type assertions
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 21 Jun 2019 22:00:57 +0000 (22:00 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 21 Jun 2019 22:00:57 +0000 (22:00 +0000)
    Now that type equality is just simple pointer equality, we can
    open code some type assertions instead of making runtime calls.

    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/182977

From-SVN: r272577

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/runtime.def
gcc/go/gofrontend/statements.cc
libgo/go/runtime/iface.go

index 4bc337c7c5466d461d485d019e49ab9a4bf43a8c..252e9b1bc52565c424e27e55cc12ee269359a32a 100644 (file)
@@ -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 a764d06509c2fecd5e68577e4e1d2793ff27a67c..b9cf0f3b1e00aa98985a15bed50d7fd72e1288d4 100644 (file)
@@ -486,9 +486,11 @@ Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs,
   // 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(Type *lhs_type, Expression* rhs,
   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(Type *lhs_type, Expression* rhs,
       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 2c505a9743f61dd4f14c01f38be79f51d0eaea30..2c6a08094d102e51eed6098ed32dee992750d946 100644 (file)
@@ -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*>
@@ -1256,9 +1261,6 @@ class Expression
            : NULL);
   }
 
-  static Expression*
-  get_interface_type_descriptor(Expression*);
-
   static Expression*
   convert_interface_to_type(Type*, Expression*, Location);
 
index 42a76745925aa6034d86225cc0fdbf40f9696023..b135a699e13ac1cb587f14fae8d4e20c34b68f96 100644 (file)
@@ -6243,7 +6243,8 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no)
            }
 
          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 ffc747bb575af0a758fa215c6923bd8985e5c927..a966cd422ec00683e39e033330917516b4b67f0a 100644 (file)
@@ -320,23 +320,13 @@ DEF_GO_RUNTIME(ASSERTITAB, "runtime.assertitab", P2(TYPE, TYPE), R1(POINTER))
 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 e8380be0bb00fc69ad6f6ac15b62d0ace465f37e..ad4a353fb4aad3eb69db9ccf3052c674f37c07b0 100644 (file)
@@ -4614,11 +4614,12 @@ Type_case_clauses::Type_case_clause::lower(Type* switch_val_type,
        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*, Named_object*, Block* enclosing,
       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 1c3a5f3d87f23f40a71d89fcaf63f02ef6de5d4f..6def7388df7948a58f655aaee1eab77f87de8acf 100644 (file)
@@ -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.Pointer {
        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