From 92f0112cab96a60bb777b81e93a5d10437c5fa60 Mon Sep 17 00:00:00 2001 From: Than McIntosh Date: Fri, 1 Dec 2017 23:12:13 +0000 Subject: [PATCH] compiler: introduce size threshold for nil checks Add a new control variable to the Gogo class that stores the size threshold for nil checks. This value can be used to control the policy for deciding when a given deference operation needs a check and when it does not. A size threshold of -1 means that every potentially faulting dereference needs an explicit check (and branch to error call). A size threshold of K (where K > 0) means that if the size of the object being dereferenced is >= K, then we need a check. Reviewed-on: https://go-review.googlesource.com/80996 * go-c.h (go_create_gogo_args): Add nil_check_size_threshold field. * go-lang.c (go_langhook_init): Set nil_check_size_threshold. From-SVN: r255340 --- gcc/go/ChangeLog | 6 ++ gcc/go/go-c.h | 1 + gcc/go/go-lang.c | 1 + gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 158 ++++++++++++++++++++----------- gcc/go/gofrontend/expressions.h | 43 ++++++++- gcc/go/gofrontend/go.cc | 1 + gcc/go/gofrontend/gogo.cc | 6 +- gcc/go/gofrontend/gogo.h | 16 ++++ gcc/go/gofrontend/parse.cc | 7 +- gcc/go/gofrontend/statements.cc | 28 ++++-- gcc/go/gofrontend/types.cc | 29 +++--- gcc/go/gofrontend/wb.cc | 3 +- 13 files changed, 220 insertions(+), 81 deletions(-) diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 01af4678684..26f823e0442 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,9 @@ +2017-12-01 Than McIntosh + + * go-c.h (go_create_gogo_args): Add nil_check_size_threshold + field. + * go-lang.c (go_langhook_init): Set nil_check_size_threshold. + 2017-11-28 Jakub Jelinek * go-gcc.cc (Gcc_backend::switch_statement): Build SWITCH_EXPR using diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h index 029b5d5f6bd..f5a1bde51b2 100644 --- a/gcc/go/go-c.h +++ b/gcc/go/go-c.h @@ -47,6 +47,7 @@ struct go_create_gogo_args bool check_divide_overflow; bool compiling_runtime; int debug_escape_level; + int64_t nil_check_size_threshold; }; extern void go_create_gogo (const struct go_create_gogo_args*); diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c index 81eeb5c9cdc..fda069aee6d 100644 --- a/gcc/go/go-lang.c +++ b/gcc/go/go-lang.c @@ -112,6 +112,7 @@ go_langhook_init (void) args.check_divide_overflow = go_check_divide_overflow; args.compiling_runtime = go_compiling_runtime; args.debug_escape_level = go_debug_escape_level; + args.nil_check_size_threshold = 4096; args.linemap = go_get_linemap(); args.backend = go_get_backend(); go_create_gogo (&args); diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 9aee310c9b8..ca329c2de32 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -0d6b3abcbfe04949db947081651a503ceb12fe6e +8cd42a3e9e0e618bb09e67be73f7d2f2477a0faa 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 7f816110d62..e9b86831dc9 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -290,7 +290,7 @@ Expression::get_interface_type_descriptor(Expression* rhs) Expression::make_interface_info(rhs, INTERFACE_INFO_METHODS, location); Expression* descriptor = - Expression::make_unary(OPERATOR_MULT, mtable, location); + Expression::make_dereference(mtable, NIL_CHECK_NOT_NEEDED, location); descriptor = Expression::make_field_reference(descriptor, 0, location); Expression* nil = Expression::make_nil(location); @@ -393,7 +393,8 @@ Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs, { obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), obj, location); - obj = Expression::make_unary(OPERATOR_MULT, obj, location); + obj = Expression::make_dereference(obj, NIL_CHECK_NOT_NEEDED, + location); } return Expression::make_compound(check_iface, obj, location); } @@ -3842,24 +3843,20 @@ Unary_expression::do_flatten(Gogo* gogo, Named_object*, && !this->expr_->is_variable()) { go_assert(this->expr_->type()->points_to() != NULL); - Type* ptype = this->expr_->type()->points_to(); - if (!ptype->is_void_type()) + switch (this->requires_nil_check(gogo)) { - int64_t s; - bool ok = ptype->backend_type_size(gogo, &s); - if (!ok) + case NIL_CHECK_ERROR_ENCOUNTERED: { go_assert(saw_errors()); return Expression::make_error(this->location()); } - if (s >= 4096 || this->issue_nil_check_) - { - Temporary_statement* temp = - Statement::make_temporary(NULL, this->expr_, location); - inserter->insert(temp); - this->expr_ = - Expression::make_temporary_reference(temp, location); - } + case NIL_CHECK_NOT_NEEDED: + break; + case NIL_CHECK_NEEDED: + this->create_temp_ = true; + break; + case NIL_CHECK_DEFAULT: + go_unreachable(); } } @@ -3960,6 +3957,41 @@ Unary_expression::base_is_static_initializer(Expression* expr) return false; } +// Return whether this dereference expression requires an explicit nil +// check. If we are dereferencing the pointer to a large struct +// (greater than the specified size threshold), we need to check for +// nil. We don't bother to check for small structs because we expect +// the system to crash on a nil pointer dereference. However, if we +// know the address of this expression is being taken, we must always +// check for nil. +Unary_expression::Nil_check_classification +Unary_expression::requires_nil_check(Gogo* gogo) +{ + go_assert(this->op_ == OPERATOR_MULT); + go_assert(this->expr_->type()->points_to() != NULL); + + if (this->issue_nil_check_ == NIL_CHECK_NEEDED) + return NIL_CHECK_NEEDED; + else if (this->issue_nil_check_ == NIL_CHECK_NOT_NEEDED) + return NIL_CHECK_NOT_NEEDED; + + Type* ptype = this->expr_->type()->points_to(); + int64_t type_size = -1; + if (!ptype->is_void_type()) + { + bool ok = ptype->backend_type_size(gogo, &type_size); + if (!ok) + return NIL_CHECK_ERROR_ENCOUNTERED; + } + + int64_t size_cutoff = gogo->nil_check_size_threshold(); + if (size_cutoff == -1 || (type_size != -1 && type_size >= size_cutoff)) + this->issue_nil_check_ = NIL_CHECK_NEEDED; + else + this->issue_nil_check_ = NIL_CHECK_NOT_NEEDED; + return this->issue_nil_check_; +} + // Apply unary opcode OP to UNC, setting NC. Return true if this // could be done, false if not. On overflow, issues an error and sets // *ISSUED_ERROR. @@ -4408,43 +4440,42 @@ Unary_expression::do_get_backend(Translate_context* context) { go_assert(this->expr_->type()->points_to() != NULL); - // If we are dereferencing the pointer to a large struct, we - // need to check for nil. We don't bother to check for small - // structs because we expect the system to crash on a nil - // pointer dereference. However, if we know the address of this - // expression is being taken, we must always check for nil. - + bool known_valid = false; Type* ptype = this->expr_->type()->points_to(); Btype* pbtype = ptype->get_backend(gogo); - if (!ptype->is_void_type()) - { - int64_t s; - bool ok = ptype->backend_type_size(gogo, &s); - if (!ok) + switch (this->requires_nil_check(gogo)) + { + case NIL_CHECK_NOT_NEEDED: + break; + case NIL_CHECK_ERROR_ENCOUNTERED: { go_assert(saw_errors()); return gogo->backend()->error_expression(); } - if (s >= 4096 || this->issue_nil_check_) - { + case NIL_CHECK_NEEDED: + { go_assert(this->expr_->is_variable()); Bexpression* nil = - Expression::make_nil(loc)->get_backend(context); + Expression::make_nil(loc)->get_backend(context); Bexpression* compare = gogo->backend()->binary_expression(OPERATOR_EQEQ, bexpr, nil, loc); Bexpression* crash = - gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, - loc)->get_backend(context); + gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, + loc)->get_backend(context); Bfunction* bfn = context->function()->func_value()->get_decl(); bexpr = gogo->backend()->conditional_expression(bfn, btype, compare, crash, bexpr, loc); - - } - } - ret = gogo->backend()->indirect_expression(pbtype, bexpr, false, loc); + known_valid = true; + break; + } + case NIL_CHECK_DEFAULT: + go_unreachable(); + } + ret = gogo->backend()->indirect_expression(pbtype, bexpr, + known_valid, loc); } break; @@ -4529,6 +4560,19 @@ Expression::make_unary(Operator op, Expression* expr, Location location) return new Unary_expression(op, expr, location); } +Expression* +Expression::make_dereference(Expression* ptr, + Nil_check_classification docheck, + Location location) +{ + Expression* deref = Expression::make_unary(OPERATOR_MULT, ptr, location); + if (docheck == NIL_CHECK_NEEDED) + deref->unary_expression()->set_requires_nil_check(true); + else if (docheck == NIL_CHECK_NOT_NEEDED) + deref->unary_expression()->set_requires_nil_check(false); + return deref; +} + // If this is an indirection through a pointer, return the expression // being pointed through. Otherwise return this. @@ -6829,7 +6873,7 @@ Bound_method_expression::create_thunk(Gogo* gogo, const Method* method, // Field 0 of the closure is the function code pointer, field 1 is // the value on which to invoke the method. Expression* arg = Expression::make_var_reference(cp, loc); - arg = Expression::make_unary(OPERATOR_MULT, arg, loc); + arg = Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED, loc); arg = Expression::make_field_reference(arg, 1, loc); Expression* bme = Expression::make_bound_method(arg, method, fn, loc); @@ -6893,7 +6937,8 @@ bme_check_nil(const Method::Field_indexes* field_indexes, Location loc, Expression::make_nil(loc), loc); cond = Expression::make_binary(OPERATOR_OROR, cond, n, loc); - *ref = Expression::make_unary(OPERATOR_MULT, *ref, loc); + *ref = Expression::make_dereference(*ref, Expression::NIL_CHECK_DEFAULT, + loc); go_assert((*ref)->type()->struct_type() == stype); } *ref = Expression::make_field_reference(*ref, field_indexes->field_index, @@ -6948,7 +6993,7 @@ Bound_method_expression::do_flatten(Gogo* gogo, Named_object*, Expression* val = expr; if (fntype->receiver()->type()->points_to() == NULL && val->type()->points_to() != NULL) - val = Expression::make_unary(OPERATOR_MULT, val, loc); + val = Expression::make_dereference(val, NIL_CHECK_DEFAULT, loc); // Note that we are ignoring this->expr_type_ here. The thunk will // expect a closure whose second field has type this->expr_type_ (if @@ -8919,7 +8964,8 @@ Builtin_call_expression::do_get_backend(Translate_context* context) arg_type = arg_type->points_to(); go_assert(arg_type->array_type() != NULL && !arg_type->is_slice_type()); - arg = Expression::make_unary(OPERATOR_MULT, arg, location); + arg = Expression::make_dereference(arg, NIL_CHECK_DEFAULT, + location); } Type* int_type = Type::lookup_integer_type("int"); @@ -8953,8 +8999,9 @@ Builtin_call_expression::do_get_backend(Translate_context* context) arg, nil, location); Expression* zero = Expression::make_integer_ul(0, int_type, location); - Expression* indir = Expression::make_unary(OPERATOR_MULT, - arg, location); + Expression* indir = + Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED, + location); val = Expression::make_conditional(cmp, zero, indir, location); } else @@ -8995,8 +9042,9 @@ Builtin_call_expression::do_get_backend(Translate_context* context) arg, nil, location); Expression* zero = Expression::make_integer_ul(0, int_type, location); - Expression* indir = Expression::make_unary(OPERATOR_MULT, - parg, location); + Expression* indir = + Expression::make_dereference(parg, NIL_CHECK_NOT_NEEDED, + location); val = Expression::make_conditional(cmp, zero, indir, location); } else @@ -10274,7 +10322,7 @@ Call_expression::do_get_backend(Translate_context* context) Type::make_pointer_type( Type::make_pointer_type(Type::make_void_type())); fn = Expression::make_unsafe_cast(pfntype, this->fn_, location); - fn = Expression::make_unary(OPERATOR_MULT, fn, location); + fn = Expression::make_dereference(fn, NIL_CHECK_NOT_NEEDED, location); } else { @@ -10532,8 +10580,8 @@ Index_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int) && type->points_to()->array_type() != NULL && !type->points_to()->is_slice_type()) { - Expression* deref = Expression::make_unary(OPERATOR_MULT, left, - location); + Expression* deref = + Expression::make_dereference(left, NIL_CHECK_DEFAULT, location); // For an ordinary index into the array, the pointer will be // dereferenced. For a slice it will not--the resulting slice @@ -11297,7 +11345,8 @@ String_index_expression::do_get_backend(Translate_context* context) Location loc = this->location(); Expression* string_arg = this->string_; if (this->string_->type()->points_to() != NULL) - string_arg = Expression::make_unary(OPERATOR_MULT, this->string_, loc); + string_arg = Expression::make_dereference(this->string_, + NIL_CHECK_NOT_NEEDED, loc); Expression* bad_index = Expression::check_bounds(this->start_, loc); @@ -11531,8 +11580,9 @@ Map_index_expression::do_get_backend(Translate_context* context) go_assert(this->value_pointer_ != NULL && this->value_pointer_->is_variable()); - Expression* val = Expression::make_unary(OPERATOR_MULT, this->value_pointer_, - this->location()); + Expression* val = Expression::make_dereference(this->value_pointer_, + NIL_CHECK_NOT_NEEDED, + this->location()); return val->get_backend(context); } @@ -11768,7 +11818,7 @@ Interface_field_reference_expression::get_function() Expression* ref = this->expr_; Location loc = this->location(); if (ref->type()->points_to() != NULL) - ref = Expression::make_unary(OPERATOR_MULT, ref, loc); + ref = Expression::make_dereference(ref, NIL_CHECK_DEFAULT, loc); Expression* mtable = Expression::make_interface_info(ref, INTERFACE_INFO_METHODS, loc); @@ -11778,7 +11828,8 @@ Interface_field_reference_expression::get_function() unsigned int index; const Struct_field* field = mtable_type->find_local_field(name, &index); go_assert(field != NULL); - mtable = Expression::make_unary(OPERATOR_MULT, mtable, loc); + + mtable = Expression::make_dereference(mtable, NIL_CHECK_NOT_NEEDED, loc); return Expression::make_field_reference(mtable, index, loc); } @@ -11790,7 +11841,8 @@ Interface_field_reference_expression::get_underlying_object() { Expression* expr = this->expr_; if (expr->type()->points_to() != NULL) - expr = Expression::make_unary(OPERATOR_MULT, expr, this->location()); + expr = Expression::make_dereference(expr, NIL_CHECK_DEFAULT, + this->location()); return Expression::make_interface_info(expr, INTERFACE_INFO_OBJECT, this->location()); } @@ -11963,7 +12015,7 @@ Interface_field_reference_expression::create_thunk(Gogo* gogo, // Field 0 of the closure is the function code pointer, field 1 is // the value on which to invoke the method. Expression* arg = Expression::make_var_reference(cp, loc); - arg = Expression::make_unary(OPERATOR_MULT, arg, loc); + arg = Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED, loc); arg = Expression::make_field_reference(arg, 1, loc); Expression *ifre = Expression::make_interface_field_reference(arg, name, diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 9f58f497f8e..9de734e636f 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -506,6 +506,23 @@ class Expression static Expression* make_backend(Bexpression*, Type*, Location); + enum Nil_check_classification + { + // Use the default policy for deciding if this deref needs a check. + NIL_CHECK_DEFAULT, + // An explicit check is required for this dereference operation. + NIL_CHECK_NEEDED, + // No check needed for this dereference operation. + NIL_CHECK_NOT_NEEDED, + // A type error or error construct was encountered when determining + // whether this deref needs an explicit check. + NIL_CHECK_ERROR_ENCOUNTERED + }; + + // Make a dereference expression. + static Expression* + make_dereference(Expression*, Nil_check_classification, Location); + // Return the expression classification. Expression_classification classification() const @@ -1730,7 +1747,8 @@ class Unary_expression : public Expression Unary_expression(Operator op, Expression* expr, Location location) : Expression(EXPRESSION_UNARY, location), op_(op), escapes_(true), create_temp_(false), is_gc_root_(false), - is_slice_init_(false), expr_(expr), issue_nil_check_(false) + is_slice_init_(false), expr_(expr), + issue_nil_check_(NIL_CHECK_DEFAULT) { } // Return the operator. @@ -1792,6 +1810,17 @@ class Unary_expression : public Expression static Expression* do_import(Import*); + // Declare that this deref does or does not require an explicit nil check. + void + set_requires_nil_check(bool needed) + { + go_assert(this->op_ == OPERATOR_MULT); + if (needed) + this->issue_nil_check_ = NIL_CHECK_NEEDED; + else + this->issue_nil_check_ = NIL_CHECK_NOT_NEEDED; + } + protected: int do_traverse(Traverse* traverse) @@ -1847,12 +1876,20 @@ class Unary_expression : public Expression void do_issue_nil_check() - { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); } + { + if (this->op_ == OPERATOR_MULT) + this->set_requires_nil_check(true); + } private: static bool base_is_static_initializer(Expression*); + // Return a determination as to whether this dereference expression + // requires a nil check. + Nil_check_classification + requires_nil_check(Gogo*); + // The unary operator to apply. Operator op_; // Normally true. False if this is an address expression which does @@ -1874,7 +1911,7 @@ class Unary_expression : public Expression Expression* expr_; // Whether or not to issue a nil check for this expression if its address // is being taken. - bool issue_nil_check_; + Nil_check_classification issue_nil_check_; }; // A binary expression. diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc index e3f17bccbef..a2b8cecb3fe 100644 --- a/gcc/go/gofrontend/go.cc +++ b/gcc/go/gofrontend/go.cc @@ -41,6 +41,7 @@ go_create_gogo(const struct go_create_gogo_args* args) if (args->c_header != NULL) ::gogo->set_c_header(args->c_header); ::gogo->set_debug_escape_level(args->debug_escape_level); + ::gogo->set_nil_check_size_threshold(args->nil_check_size_threshold); } // Parse the input files. diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 54617360060..74b45958f61 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -55,6 +55,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size) check_divide_overflow_(true), compiling_runtime_(false), debug_escape_level_(0), + nil_check_size_threshold_(4096), verify_types_(), interface_types_(), specific_type_functions_(), @@ -5567,7 +5568,10 @@ Function::build(Gogo* gogo, Named_object* named_function) vars.push_back(bvar); Expression* parm_ref = Expression::make_var_reference(parm_no, loc); - parm_ref = Expression::make_unary(OPERATOR_MULT, parm_ref, loc); + parm_ref = + Expression::make_dereference(parm_ref, + Expression::NIL_CHECK_DEFAULT, + loc); if ((*p)->var_value()->is_in_heap()) parm_ref = Expression::make_heap_expression(parm_ref, loc); var_inits.push_back(parm_ref->get_backend(&context)); diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 338770f5c3c..e48a89926c8 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -318,6 +318,20 @@ class Gogo set_debug_escape_level(int level) { this->debug_escape_level_ = level; } + // Return the size threshold used to determine whether to issue + // a nil-check for a given pointer dereference. A threshold of -1 + // implies that all potentially faulting dereference ops should + // be nil-checked. A positive threshold of N implies that a deref + // of *P where P has size less than N doesn't need a nil check. + int64_t + nil_check_size_threshold() const + { return this->nil_check_size_threshold_; } + + // Set the nil-check size threshold, as described above. + void + set_nil_check_size_threshold(int64_t bytes) + { this->nil_check_size_threshold_ = bytes; } + // Import a package. FILENAME is the file name argument, LOCAL_NAME // is the local name to give to the package. If LOCAL_NAME is empty // the declarations are added to the global scope. @@ -1025,6 +1039,8 @@ class Gogo // The level of escape analysis debug information to emit, from the // -fgo-debug-escape option. int debug_escape_level_; + // Nil-check size threshhold. + int64_t nil_check_size_threshold_; // A list of types to verify. std::vector verify_types_; // A list of interface types defined while parsing. diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index f7d53af6e21..be6f3f16339 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -2745,14 +2745,17 @@ Parse::enclosing_var_reference(Named_object* in_function, Named_object* var, Expression* closure_ref = Expression::make_var_reference(closure, location); - closure_ref = Expression::make_unary(OPERATOR_MULT, closure_ref, location); + closure_ref = + Expression::make_dereference(closure_ref, + Expression::NIL_CHECK_DEFAULT, + location); // The closure structure holds pointers to the variables, so we need // to introduce an indirection. Expression* e = Expression::make_field_reference(closure_ref, ins.first->index(), location); - e = Expression::make_unary(OPERATOR_MULT, e, location); + e = Expression::make_dereference(e, Expression::NIL_CHECK_DEFAULT, location); return Expression::make_enclosing_var_reference(e, var, location); } diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index e97798008ea..d3878a6ba05 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -315,7 +315,8 @@ Variable_declaration_statement::do_get_backend(Translate_context* context) if (binit != NULL) { Expression* e = Expression::make_temporary_reference(temp, loc); - e = Expression::make_unary(OPERATOR_MULT, e, loc); + e = Expression::make_dereference(e, Expression::NIL_CHECK_NOT_NEEDED, + loc); Bexpression* be = e->get_backend(context); set = context->backend()->assignment_statement(bfunction, be, binit, loc); } @@ -740,7 +741,9 @@ Assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, a1, a2, a3); Type* ptrval_type = Type::make_pointer_type(mt->val_type()); call = Expression::make_cast(ptrval_type, call, loc); - Expression* indir = Expression::make_unary(OPERATOR_MULT, call, loc); + Expression* indir = + Expression::make_dereference(call, Expression::NIL_CHECK_NOT_NEEDED, + loc); ref = Expression::make_temporary_reference(val_temp, loc); b->add_statement(Statement::make_assignment(indir, ref, loc)); @@ -1292,7 +1295,8 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*, // val = *val__ptr_temp ref = Expression::make_temporary_reference(val_ptr_temp, loc); - Expression* ind = Expression::make_unary(OPERATOR_MULT, ref, loc); + Expression* ind = + Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc); s = Statement::make_assignment(this->val_, ind, loc); b->add_statement(s); @@ -2367,8 +2371,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name) // ones used in build_struct. Expression* thunk_parameter = Expression::make_var_reference(named_parameter, location); - thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter, - location); + thunk_parameter = + Expression::make_dereference(thunk_parameter, + Expression::NIL_CHECK_NOT_NEEDED, + location); Interface_field_reference_expression* interface_method = ce->fn()->interface_field_reference_expression(); @@ -2421,8 +2427,10 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name) { Expression* thunk_param = Expression::make_var_reference(named_parameter, location); - thunk_param = - Expression::make_unary(OPERATOR_MULT, thunk_param, location); + thunk_param = + Expression::make_dereference(thunk_param, + Expression::NIL_CHECK_NOT_NEEDED, + location); param = Expression::make_field_reference(thunk_param, next_index, location); @@ -5837,7 +5845,8 @@ For_range_statement::lower_range_map(Gogo* gogo, Expression* lhs = Expression::make_temporary_reference(index_temp, loc); Expression* rhs = Expression::make_temporary_reference(hiter, loc); rhs = Expression::make_field_reference(ref, 0, loc); - rhs = Expression::make_unary(OPERATOR_MULT, ref, loc); + rhs = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, + loc); Statement* set = Statement::make_assignment(lhs, rhs, loc); iter_init->add_statement(set); @@ -5846,7 +5855,8 @@ For_range_statement::lower_range_map(Gogo* gogo, lhs = Expression::make_temporary_reference(value_temp, loc); rhs = Expression::make_temporary_reference(hiter, loc); rhs = Expression::make_field_reference(rhs, 1, loc); - rhs = Expression::make_unary(OPERATOR_MULT, rhs, loc); + rhs = Expression::make_dereference(rhs, Expression::NIL_CHECK_NOT_NEEDED, + loc); set = Statement::make_assignment(lhs, rhs, loc); iter_init->add_statement(set); } diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 2c8d1437040..2274c313467 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -2215,10 +2215,10 @@ Type::write_named_equal(Gogo* gogo, Named_type* name) // Compare the values for equality. Expression* t1 = Expression::make_temporary_reference(p1, bloc); - t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc); + t1 = Expression::make_dereference(t1, Expression::NIL_CHECK_NOT_NEEDED, bloc); Expression* t2 = Expression::make_temporary_reference(p2, bloc); - t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc); + t2 = Expression::make_dereference(t2, Expression::NIL_CHECK_NOT_NEEDED, bloc); Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc); @@ -5911,7 +5911,9 @@ Struct_type::field_reference_depth(Expression* struct_expr, Expression* here = Expression::make_field_reference(struct_expr, i, location); if (pf->type()->points_to() != NULL) - here = Expression::make_unary(OPERATOR_MULT, here, location); + here = Expression::make_dereference(here, + Expression::NIL_CHECK_DEFAULT, + location); while (sub->expr() != NULL) { sub = sub->expr()->deref()->field_reference_expression(); @@ -6342,11 +6344,13 @@ Struct_type::write_equal_function(Gogo* gogo, Named_type* name) // Compare one field in both P1 and P2. Expression* f1 = Expression::make_temporary_reference(p1, bloc); - f1 = Expression::make_unary(OPERATOR_MULT, f1, bloc); + f1 = Expression::make_dereference(f1, Expression::NIL_CHECK_DEFAULT, + bloc); f1 = Expression::make_field_reference(f1, field_index, bloc); Expression* f2 = Expression::make_temporary_reference(p2, bloc); - f2 = Expression::make_unary(OPERATOR_MULT, f2, bloc); + f2 = Expression::make_dereference(f2, Expression::NIL_CHECK_DEFAULT, + bloc); f2 = Expression::make_field_reference(f2, field_index, bloc); Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, f1, f2, bloc); @@ -7193,12 +7197,12 @@ Array_type::write_equal_function(Gogo* gogo, Named_type* name) // Compare element in P1 and P2. Expression* e1 = Expression::make_temporary_reference(p1, bloc); - e1 = Expression::make_unary(OPERATOR_MULT, e1, bloc); + e1 = Expression::make_dereference(e1, Expression::NIL_CHECK_DEFAULT, bloc); ref = Expression::make_temporary_reference(index, bloc); e1 = Expression::make_array_index(e1, ref, NULL, NULL, bloc); Expression* e2 = Expression::make_temporary_reference(p2, bloc); - e2 = Expression::make_unary(OPERATOR_MULT, e2, bloc); + e2 = Expression::make_dereference(e2, Expression::NIL_CHECK_DEFAULT, bloc); ref = Expression::make_temporary_reference(index, bloc); e2 = Expression::make_array_index(e2, ref, NULL, NULL, bloc); @@ -11219,7 +11223,8 @@ Type::apply_field_indexes(Expression* expr, if (expr->type()->struct_type() == NULL) { go_assert(expr->type()->points_to() != NULL); - expr = Expression::make_unary(OPERATOR_MULT, expr, location); + expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT, + location); go_assert(expr->type()->struct_type() == stype); } return Expression::make_field_reference(expr, field_indexes->field_index, @@ -11323,7 +11328,8 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, && type->points_to() != NULL && type->points_to()->points_to() != NULL) { - expr = Expression::make_unary(OPERATOR_MULT, expr, location); + expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT, + location); type = type->points_to(); if (type->deref()->is_error_type()) return Expression::make_error(location); @@ -11356,8 +11362,9 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, return Expression::make_error(location); } go_assert(type->points_to() != NULL); - expr = Expression::make_unary(OPERATOR_MULT, expr, - location); + expr = Expression::make_dereference(expr, + Expression::NIL_CHECK_DEFAULT, + location); go_assert(expr->type()->struct_type() == st); } ret = st->field_reference(expr, name, location); diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc index d0226fca6bb..0085667ee04 100644 --- a/gcc/go/gofrontend/wb.cc +++ b/gcc/go/gofrontend/wb.cc @@ -417,7 +417,8 @@ Gogo::assign_with_write_barrier(Function* function, Block* enclosing, rhs = Expression::make_temporary_reference(rhs_temp, loc); } - Expression* indir = Expression::make_unary(OPERATOR_MULT, lhs, loc); + Expression* indir = + Expression::make_dereference(lhs, Expression::NIL_CHECK_DEFAULT, loc); Statement* assign = Statement::make_assignment(indir, rhs, loc); lhs = Expression::make_temporary_reference(lhs_temp, loc); -- 2.30.2