From: Ian Lance Taylor Date: Fri, 21 Jun 2019 22:00:57 +0000 (+0000) Subject: compiler: open code some type assertions X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0514cb33749fefd2542e7294a35d0ef0ccae30b3;p=gcc.git compiler: open code some type assertions 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 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 4bc337c7c54..252e9b1bc52 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -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. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index a764d06509c..b9cf0f3b1e0 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -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 diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 2c505a9743f..2c6a08094d1 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -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 @@ -1256,9 +1261,6 @@ class Expression : NULL); } - static Expression* - get_interface_type_descriptor(Expression*); - static Expression* convert_interface_to_type(Type*, Expression*, Location); diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 42a76745925..b135a699e13 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -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; } diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index ffc747bb575..a966cd422ec 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -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)) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index e8380be0bb0..ad4a353fb4a 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -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) diff --git a/libgo/go/runtime/iface.go b/libgo/go/runtime/iface.go index 1c3a5f3d87f..6def7388df7 100644 --- a/libgo/go/runtime/iface.go +++ b/libgo/go/runtime/iface.go @@ -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