From: Ian Lance Taylor Date: Wed, 9 Nov 2016 21:41:58 +0000 (+0000) Subject: compiler: rework static initializer code X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=39de19551b6b39d83ad791a39c72ec51f958b48b;p=gcc.git compiler: rework static initializer code Rename is_immutable to is_static_initializer to try to capture what it really means. Be more precise about when an address expression, or a binary expression, can be a static initializer. Don't check whether a type has pointers when deciding whether an initializer must be read-write, just check whether it is being used to initialize a global variable. To make that work set the Translate_context function to NULL for a global variable with a static initializer. The effect of this is to let more global variables be initialized directly, rather than being initialized in the generated init function. Reviewed-on: https://go-review.googlesource.com/32917 From-SVN: r242024 --- diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 9049bc37476..40046113d3f 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -afe0456d25e3c6c0d91a8fd4c0fdfdbaa35cc251 +cac897bd27885c18a16dacfe27d5efd4526455c5 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 69f4e016ba4..d6fa04b6215 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -535,10 +535,6 @@ class Error_expression : public Expression do_is_constant() const { return true; } - bool - do_is_immutable() const - { return true; } - bool do_numeric_constant_value(Numeric_constant* nc) const { @@ -1374,7 +1370,7 @@ class Func_code_reference_expression : public Expression { return TRAVERSE_CONTINUE; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -1520,7 +1516,7 @@ class Boolean_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -1889,7 +1885,7 @@ class Integer_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -2285,7 +2281,7 @@ class Float_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -2475,7 +2471,7 @@ class Complex_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -2691,7 +2687,7 @@ class Const_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -3047,7 +3043,7 @@ class Nil_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -3284,10 +3280,11 @@ Type_conversion_expression::do_is_constant() const return true; } -// Return whether a type conversion is immutable. +// Return whether a type conversion can be used in a constant +// initializer. bool -Type_conversion_expression::do_is_immutable() const +Type_conversion_expression::do_is_static_initializer() const { Type* type = this->type_; Type* expr_type = this->expr_->type(); @@ -3296,7 +3293,7 @@ Type_conversion_expression::do_is_immutable() const || expr_type->interface_type() != NULL) return false; - if (!this->expr_->is_immutable()) + if (!this->expr_->is_static_initializer()) return false; if (Type::are_identical(type, expr_type, false, NULL)) @@ -3542,10 +3539,11 @@ Unsafe_type_conversion_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Return whether an unsafe type conversion is immutable. +// Return whether an unsafe type conversion can be used as a constant +// initializer. bool -Unsafe_type_conversion_expression::do_is_immutable() const +Unsafe_type_conversion_expression::do_is_static_initializer() const { Type* type = this->type_; Type* expr_type = this->expr_->type(); @@ -3554,7 +3552,7 @@ Unsafe_type_conversion_expression::do_is_immutable() const || expr_type->interface_type() != NULL) return false; - if (!this->expr_->is_immutable()) + if (!this->expr_->is_static_initializer()) return false; if (Type::are_convertible(type, expr_type, NULL)) @@ -3855,6 +3853,44 @@ Unary_expression::do_is_constant() const return this->expr_->is_constant(); } +// Return whether a unary expression can be used as a constant +// initializer. + +bool +Unary_expression::do_is_static_initializer() const +{ + if (this->op_ == OPERATOR_MULT) + return false; + else if (this->op_ == OPERATOR_AND) + { + // The address of a global variable can used as a static + // initializer. + Var_expression* ve = this->expr_->var_expression(); + if (ve != NULL) + { + Named_object* no = ve->named_object(); + return no->is_variable() && no->var_value()->is_global(); + } + + // The address of a composite literal can be used as a static + // initializer if the composite literal is itself usable as a + // static initializer. + if (this->expr_->is_composite_literal() + && this->expr_->is_static_initializer()) + return true; + + // The address of a string constant can be used as a static + // initializer. This can not be written in Go itself but this + // is used when building a type descriptor. + if (this->expr_->string_expression() != NULL) + return true; + + return false; + } + else + return this->expr_->is_static_initializer(); +} + // Apply unary opcode OP to UNC, setting NC. Return true if this // could be done, false if not. Issue errors for overflow. @@ -4207,7 +4243,7 @@ Unary_expression::do_get_backend(Translate_context* context) // constructor will not do what the programmer expects. go_assert(!this->expr_->is_composite_literal() - || this->expr_->is_immutable()); + || this->expr_->is_static_initializer()); if (this->expr_->classification() == EXPRESSION_UNARY) { Unary_expression* ue = @@ -4245,8 +4281,7 @@ Unary_expression::do_get_backend(Translate_context* context) // initialize the value once, so we can use this directly // rather than copying it. In that case we can't make it // read-only, because the program is permitted to change it. - copy_to_heap = (at->element_type()->has_pointer() - && !context->is_const()); + copy_to_heap = context->function() != NULL; } Bvariable* implicit = gogo->backend()->implicit_variable(buf, btype, true, copy_to_heap, @@ -4257,8 +4292,8 @@ Unary_expression::do_get_backend(Translate_context* context) bexpr = gogo->backend()->var_expression(implicit, loc); } else if ((this->expr_->is_composite_literal() - || this->expr_->string_expression() != NULL) - && this->expr_->is_immutable()) + || this->expr_->string_expression() != NULL) + && this->expr_->is_static_initializer()) { // Build a decl for a constant constructor. snprintf(buf, sizeof buf, "C%u", counter); @@ -4426,6 +4461,33 @@ Binary_expression::do_traverse(Traverse* traverse) return Expression::traverse(&this->right_, traverse); } +// Return whether this expression may be used as a static initializer. + +bool +Binary_expression::do_is_static_initializer() const +{ + if (!this->left_->is_static_initializer() + || !this->right_->is_static_initializer()) + return false; + + // Addresses can be static initializers, but we can't implement + // arbitray binary expressions of them. + Unary_expression* lu = this->left_->unary_expression(); + Unary_expression* ru = this->right_->unary_expression(); + if (lu != NULL && lu->op() == OPERATOR_AND) + { + if (ru != NULL && ru->op() == OPERATOR_AND) + return this->op_ == OPERATOR_MINUS; + else + return this->op_ == OPERATOR_PLUS || this->op_ == OPERATOR_MINUS; + } + else if (ru != NULL && ru->op() == OPERATOR_AND) + return this->op_ == OPERATOR_PLUS || this->op_ == OPERATOR_MINUS; + + // Other cases should resolve in the backend. + return true; +} + // Return the type to use for a binary operation on operands of // LEFT_TYPE and RIGHT_TYPE. These are the types of constants and as // such may be NULL or abstract. @@ -6325,13 +6387,13 @@ String_concat_expression::do_is_constant() const } bool -String_concat_expression::do_is_immutable() const +String_concat_expression::do_is_static_initializer() const { for (Expression_list::const_iterator pe = this->exprs_->begin(); pe != this->exprs_->end(); ++pe) { - if (!(*pe)->is_immutable()) + if (!(*pe)->is_static_initializer()) return false; } return true; @@ -12275,10 +12337,10 @@ Struct_construction_expression::is_constant_struct() const return true; } -// Return whether this struct is immutable. +// Return whether this struct can be used as a constant initializer. bool -Struct_construction_expression::do_is_immutable() const +Struct_construction_expression::do_is_static_initializer() const { if (this->vals() == NULL) return true; @@ -12286,7 +12348,7 @@ Struct_construction_expression::do_is_immutable() const pv != this->vals()->end(); ++pv) { - if (*pv != NULL && !(*pv)->is_immutable()) + if (*pv != NULL && !(*pv)->is_static_initializer()) return false; } return true; @@ -12523,10 +12585,10 @@ Array_construction_expression::is_constant_array() const return true; } -// Return whether this is an immutable array initializer. +// Return whether this can be used a constant initializer. bool -Array_construction_expression::do_is_immutable() const +Array_construction_expression::do_is_static_initializer() const { if (this->vals() == NULL) return true; @@ -12534,7 +12596,7 @@ Array_construction_expression::do_is_immutable() const pv != this->vals()->end(); ++pv) { - if (*pv != NULL && !(*pv)->is_immutable()) + if (*pv != NULL && !(*pv)->is_static_initializer()) return false; } return true; @@ -12904,19 +12966,12 @@ Slice_construction_expression::do_get_backend(Translate_context* context) } Location loc = this->location(); - Array_type* array_type = this->type()->array_type(); - Type* element_type = array_type->element_type(); - bool is_constant_initializer = this->array_val_->is_immutable(); + bool is_static_initializer = this->array_val_->is_static_initializer(); // We have to copy the initial values into heap memory if we are in - // a function or if the values are not constants. We also have to - // copy them if they may contain pointers in a non-constant context, - // as otherwise the garbage collector won't see them. - bool copy_to_heap = (context->function() != NULL - || !is_constant_initializer - || (element_type->has_pointer() - && !context->is_const())); + // a function or if the values are not constants. + bool copy_to_heap = context->function() != NULL || !is_static_initializer; Expression* space; @@ -14206,7 +14261,7 @@ class Type_descriptor_expression : public Expression { return Type::make_type_descriptor_ptr_type(); } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } void @@ -14274,7 +14329,7 @@ class GC_symbol_expression : public Expression { return Type::lookup_integer_type("uintptr"); } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } void @@ -14332,7 +14387,7 @@ class Type_info_expression : public Expression protected: bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* @@ -14913,7 +14968,7 @@ class Interface_mtable_expression : public Expression do_type(); bool - is_immutable() const + do_is_static_initializer() const { return true; } void @@ -15104,7 +15159,7 @@ class Struct_field_offset_expression : public Expression protected: bool - do_is_immutable() const + do_is_static_initializer() const { return true; } Type* diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index a02fd19feb3..96d314ffbda 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -500,10 +500,20 @@ class Expression is_constant() const { return this->do_is_constant(); } - // Return whether this is an immutable expression. - bool - is_immutable() const - { return this->do_is_immutable(); } + // Return whether this expression can be used as a static + // initializer. This is true for an expression that has only + // numbers and pointers to global variables or composite literals + // that do not require runtime initialization. It is false if we + // must generate code to compute this expression when it is used to + // initialize a global variable. This is not a language-level + // concept, but an implementation-level one. If this expression is + // used to initialize a global variable, this is true if we can pass + // an initializer to the backend, false if we must generate code to + // initialize the variable. It is always safe for this method to + // return false, but the resulting code may be less efficient. + bool + is_static_initializer() const + { return this->do_is_static_initializer(); } // If this is not a numeric constant, return false. If it is one, // return true, and set VAL to hold the value. @@ -991,9 +1001,10 @@ class Expression do_is_constant() const { return false; } - // Return whether this is an immutable expression. + // Return whether this expression can be used as a constant + // initializer. virtual bool - do_is_immutable() const + do_is_static_initializer() const { return false; } // Return whether this is a constant expression of numeric type, and @@ -1508,7 +1519,7 @@ class String_expression : public Expression { return true; } bool - do_is_immutable() const + do_is_static_initializer() const { return true; } bool @@ -1595,7 +1606,7 @@ class Type_conversion_expression : public Expression do_is_constant() const; bool - do_is_immutable() const; + do_is_static_initializer() const; bool do_numeric_constant_value(Numeric_constant*) const; @@ -1659,7 +1670,7 @@ class Unsafe_type_conversion_expression : public Expression do_traverse(Traverse* traverse); bool - do_is_immutable() const; + do_is_static_initializer() const; Type* do_type() @@ -1770,11 +1781,7 @@ class Unary_expression : public Expression do_is_constant() const; bool - do_is_immutable() const - { - return (this->expr_->is_immutable() - || (this->op_ == OPERATOR_AND && this->expr_->is_variable())); - } + do_is_static_initializer() const; bool do_numeric_constant_value(Numeric_constant*) const; @@ -1913,8 +1920,7 @@ class Binary_expression : public Expression { return this->left_->is_constant() && this->right_->is_constant(); } bool - do_is_immutable() const - { return this->left_->is_immutable() && this->right_->is_immutable(); } + do_is_static_initializer() const; bool do_numeric_constant_value(Numeric_constant*) const; @@ -2029,7 +2035,7 @@ class String_concat_expression : public Expression do_is_constant() const; bool - do_is_immutable() const; + do_is_static_initializer() const; Type* do_type(); @@ -3295,7 +3301,7 @@ class Struct_construction_expression : public Expression, do_traverse(Traverse* traverse); bool - do_is_immutable() const; + do_is_static_initializer() const; Type* do_type() @@ -3370,7 +3376,7 @@ protected: do_traverse(Traverse* traverse); bool - do_is_immutable() const; + do_is_static_initializer() const; Type* do_type() diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 9491e51258e..a166d1c5c4e 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1299,29 +1299,35 @@ Gogo::write_globals() // The initializer is constant if it is the zero-value of the // variable's type or if the initial value is an immutable value // that is not copied to the heap. - bool is_constant_initializer = false; + bool is_static_initializer = false; if (var->init() == NULL) - is_constant_initializer = true; + is_static_initializer = true; else { Type* var_type = var->type(); Expression* init = var->init(); Expression* init_cast = Expression::make_cast(var_type, init, var->location()); - is_constant_initializer = - init_cast->is_immutable() && !var_type->has_pointer(); + is_static_initializer = init_cast->is_static_initializer(); } // Non-constant variable initializations might need to create // temporary variables, which will need the initialization // function as context. - if (!is_constant_initializer && init_fndecl == NULL) - init_fndecl = this->initialization_function_decl(); - Bexpression* var_binit = var->get_init(this, init_fndecl); + Named_object* var_init_fn; + if (is_static_initializer) + var_init_fn = NULL; + else + { + if (init_fndecl == NULL) + init_fndecl = this->initialization_function_decl(); + var_init_fn = init_fndecl; + } + Bexpression* var_binit = var->get_init(this, var_init_fn); if (var_binit == NULL) ; - else if (is_constant_initializer) + else if (is_static_initializer) { if (expression_requires(var->init(), NULL, this->var_depends_on(var), no))