diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-10-12 18:17:52 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2016-10-12 18:17:52 +0000 |
commit | 1ad16c52842e0513b96a0e02d2a431dc0f338c5d (patch) | |
tree | f6eaddf65fba9d031ed9b3008a3c3ba4ff0ebd0b /gcc | |
parent | 2ec69f566076547b618447ba5531260c25abed3e (diff) | |
download | gcc-1ad16c52842e0513b96a0e02d2a431dc0f338c5d.zip gcc-1ad16c52842e0513b96a0e02d2a431dc0f338c5d.tar.gz gcc-1ad16c52842e0513b96a0e02d2a431dc0f338c5d.tar.bz2 |
compiler, runtime: copy string code from Go 1.7
Add compiler support for turning concatenating strings into a call to
a runtime function that takes the appropriate number of arguments.
Rename some local variables in mgc0.c to avoid macros that the new
rune.go causes to appear in runtime.inc.
Reviewed-on: https://go-review.googlesource.com/30827
From-SVN: r241074
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/escape.cc | 50 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 252 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 88 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.cc | 36 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 39 |
6 files changed, 391 insertions, 76 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index a6ea428..9c1ed01 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -c18d9f0e7270144ebd1f67d85995f434bbdab0b0 +f38ba8837a0c961e18d982930e192132870f3836 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/escape.cc b/gcc/go/gofrontend/escape.cc index 732af77..73be757 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -1233,13 +1233,17 @@ Escape_analysis_assign::expression(Expression** pexpr) case Runtime::MAKESLICE2: case Runtime::MAKESLICE1BIG: case Runtime::MAKESLICE2BIG: - case Runtime::BYTE_ARRAY_TO_STRING: - case Runtime::INT_ARRAY_TO_STRING: - case Runtime::STRING_TO_BYTE_ARRAY: - case Runtime::STRING_TO_INT_ARRAY: - case Runtime::STRING_PLUS: + case Runtime::SLICEBYTETOSTRING: + case Runtime::SLICERUNETOSTRING: + case Runtime::STRINGTOSLICEBYTE: + case Runtime::STRINGTOSLICERUNE: + case Runtime::CONCATSTRINGS: + case Runtime::CONCATSTRING2: + case Runtime::CONCATSTRING3: + case Runtime::CONCATSTRING4: + case Runtime::CONCATSTRING5: case Runtime::CONSTRUCT_MAP: - case Runtime::INT_TO_STRING: + case Runtime::INTSTRING: { Node* runtime_node = Node::make_node(fe); this->context_->track(runtime_node); @@ -1842,21 +1846,25 @@ Escape_analysis_assign::assign(Node* dst, Node* src) case Runtime::MAKESLICE1BIG: case Runtime::MAKESLICE2BIG: // DST = make(...). - case Runtime::BYTE_ARRAY_TO_STRING: + case Runtime::SLICEBYTETOSTRING: // DST = string([]byte{...}). - case Runtime::INT_ARRAY_TO_STRING: + case Runtime::SLICERUNETOSTRING: // DST = string([]int{...}). - case Runtime::STRING_TO_BYTE_ARRAY: + case Runtime::STRINGTOSLICEBYTE: // DST = []byte(str). - case Runtime::STRING_TO_INT_ARRAY: - // DST = []int(str). - case Runtime::STRING_PLUS: + case Runtime::STRINGTOSLICERUNE: + // DST = []rune(str). + case Runtime::CONCATSTRINGS: + case Runtime::CONCATSTRING2: + case Runtime::CONCATSTRING3: + case Runtime::CONCATSTRING4: + case Runtime::CONCATSTRING5: // DST = str1 + str2 case Runtime::CONSTRUCT_MAP: // When building a map literal's backend representation. // Likely never seen here and covered in // Expression::EXPRESSION_MAP_CONSTRUCTION. - case Runtime::INT_TO_STRING: + case Runtime::INTSTRING: // DST = string(i). case Runtime::IFACEE2E2: case Runtime::IFACEI2E2: @@ -2614,13 +2622,17 @@ Escape_analysis_flood::flood(Level level, Node* dst, Node* src, case Runtime::MAKESLICE2: case Runtime::MAKESLICE1BIG: case Runtime::MAKESLICE2BIG: - case Runtime::BYTE_ARRAY_TO_STRING: - case Runtime::INT_ARRAY_TO_STRING: - case Runtime::STRING_TO_BYTE_ARRAY: - case Runtime::STRING_TO_INT_ARRAY: - case Runtime::STRING_PLUS: + case Runtime::SLICEBYTETOSTRING: + case Runtime::SLICERUNETOSTRING: + case Runtime::STRINGTOSLICEBYTE: + case Runtime::STRINGTOSLICERUNE: + case Runtime::CONCATSTRINGS: + case Runtime::CONCATSTRING2: + case Runtime::CONCATSTRING3: + case Runtime::CONCATSTRING4: + case Runtime::CONCATSTRING5: case Runtime::CONSTRUCT_MAP: - case Runtime::INT_TO_STRING: + case Runtime::INTSTRING: case Runtime::CONVERT_INTERFACE: // All runtime calls that involve allocation of memory // except new. Runtime::NEW gets lowered into an diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 4f8a519..40c8a4e 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3419,7 +3419,8 @@ Type_conversion_expression::do_get_backend(Translate_context* context) } Expression* i2s_expr = - Runtime::make_call(Runtime::INT_TO_STRING, loc, 1, this->expr_); + Runtime::make_call(Runtime::INTSTRING, loc, 2, + Expression::make_nil(loc), this->expr_); return Expression::make_cast(type, i2s_expr, loc)->get_backend(context); } else if (type->is_string_type() && expr_type->is_slice_type()) @@ -3431,16 +3432,14 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Runtime::Function code; if (e->integer_type()->is_byte()) - code = Runtime::BYTE_ARRAY_TO_STRING; + code = Runtime::SLICEBYTETOSTRING; else { go_assert(e->integer_type()->is_rune()); - code = Runtime::INT_ARRAY_TO_STRING; + code = Runtime::SLICERUNETOSTRING; } - Expression* valptr = a->get_value_pointer(gogo, this->expr_); - Expression* len = a->get_length(gogo, this->expr_); - return Runtime::make_call(code, loc, 2, valptr, - len)->get_backend(context); + return Runtime::make_call(code, loc, 2, Expression::make_nil(loc), + this->expr_)->get_backend(context); } else if (type->is_slice_type() && expr_type->is_string_type()) { @@ -3449,13 +3448,15 @@ Type_conversion_expression::do_get_backend(Translate_context* context) Runtime::Function code; if (e->integer_type()->is_byte()) - code = Runtime::STRING_TO_BYTE_ARRAY; + code = Runtime::STRINGTOSLICEBYTE; else { go_assert(e->integer_type()->is_rune()); - code = Runtime::STRING_TO_INT_ARRAY; + code = Runtime::STRINGTOSLICERUNE; } - Expression* s2a = Runtime::make_call(code, loc, 1, this->expr_); + Expression* s2a = Runtime::make_call(code, loc, 2, + Expression::make_nil(loc), + this->expr_); return Expression::make_unsafe_cast(type, s2a, loc)->get_backend(context); } else if (type->is_numeric_type()) @@ -5068,6 +5069,31 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, return this->lower_interface_value_comparison(gogo, inserter); } + // Lower string concatenation to String_concat_expression, so that + // we can group sequences of string additions. + if (this->left_->type()->is_string_type() && this->op_ == OPERATOR_PLUS) + { + Expression_list* exprs; + String_concat_expression* left_sce = + this->left_->string_concat_expression(); + if (left_sce != NULL) + exprs = left_sce->exprs(); + else + { + exprs = new Expression_list(); + exprs->push_back(this->left_); + } + + String_concat_expression* right_sce = + this->right_->string_concat_expression(); + if (right_sce != NULL) + exprs->append(right_sce->exprs()); + else + exprs->push_back(this->right_); + + return Expression::make_string_concat(exprs); + } + return this; } @@ -5277,25 +5303,6 @@ Binary_expression::do_flatten(Gogo* gogo, Named_object*, } Temporary_statement* temp; - if (this->left_->type()->is_string_type() - && this->op_ == OPERATOR_PLUS) - { - if (!this->left_->is_variable() - && !this->left_->is_constant()) - { - temp = Statement::make_temporary(NULL, this->left_, loc); - inserter->insert(temp); - this->left_ = Expression::make_temporary_reference(temp, loc); - } - if (!this->right_->is_variable() - && !this->right_->is_constant()) - { - temp = - Statement::make_temporary(this->left_->type(), this->right_, loc); - this->right_ = Expression::make_temporary_reference(temp, loc); - inserter->insert(temp); - } - } Type* left_type = this->left_->type(); bool is_shift_op = (this->op_ == OPERATOR_LSHIFT @@ -5792,14 +5799,9 @@ Binary_expression::do_get_backend(Translate_context* context) go_unreachable(); } - if (left_type->is_string_type()) - { - go_assert(this->op_ == OPERATOR_PLUS); - Expression* string_plus = - Runtime::make_call(Runtime::STRING_PLUS, loc, 2, - this->left_, this->right_); - return string_plus->get_backend(context); - } + // The only binary operation for string is +, and that should have + // been converted to a String_concat_expression in do_lower. + go_assert(!left_type->is_string_type()); // For complex division Go might want slightly different results than the // backend implementation provides, so we have our own runtime routine. @@ -6294,6 +6296,182 @@ Expression::comparison(Translate_context* context, Type* result_type, return ret; } +// Class String_concat_expression. + +bool +String_concat_expression::do_is_constant() const +{ + for (Expression_list::const_iterator pe = this->exprs_->begin(); + pe != this->exprs_->end(); + ++pe) + { + if (!(*pe)->is_constant()) + return false; + } + return true; +} + +bool +String_concat_expression::do_is_immutable() const +{ + for (Expression_list::const_iterator pe = this->exprs_->begin(); + pe != this->exprs_->end(); + ++pe) + { + if (!(*pe)->is_immutable()) + return false; + } + return true; +} + +Type* +String_concat_expression::do_type() +{ + Type* t = this->exprs_->front()->type(); + Expression_list::iterator pe = this->exprs_->begin(); + ++pe; + for (; pe != this->exprs_->end(); ++pe) + { + Type* t1; + if (!Binary_expression::operation_type(OPERATOR_PLUS, t, + (*pe)->type(), + &t1)) + return Type::make_error_type(); + t = t1; + } + return t; +} + +void +String_concat_expression::do_determine_type(const Type_context* context) +{ + Type_context subcontext(*context); + for (Expression_list::iterator pe = this->exprs_->begin(); + pe != this->exprs_->end(); + ++pe) + { + Type* t = (*pe)->type(); + if (!t->is_abstract()) + { + subcontext.type = t; + break; + } + } + if (subcontext.type == NULL) + subcontext.type = this->exprs_->front()->type(); + for (Expression_list::iterator pe = this->exprs_->begin(); + pe != this->exprs_->end(); + ++pe) + (*pe)->determine_type(&subcontext); +} + +void +String_concat_expression::do_check_types(Gogo*) +{ + if (this->is_error_expression()) + return; + Type* t = this->exprs_->front()->type(); + if (t->is_error()) + { + this->set_is_error(); + return; + } + Expression_list::iterator pe = this->exprs_->begin(); + ++pe; + for (; pe != this->exprs_->end(); ++pe) + { + Type* t1 = (*pe)->type(); + if (!Type::are_compatible_for_binop(t, t1)) + { + this->report_error("incompatible types in binary expression"); + return; + } + if (!Binary_expression::check_operator_type(OPERATOR_PLUS, t, t1, + this->location())) + { + this->set_is_error(); + return; + } + } +} + +Expression* +String_concat_expression::do_flatten(Gogo*, Named_object*, + Statement_inserter*) +{ + if (this->is_error_expression()) + return this; + Location loc = this->location(); + Type* type = this->type(); + Expression* nil_arg = Expression::make_nil(loc); + Expression* call; + switch (this->exprs_->size()) + { + case 0: case 1: + go_unreachable(); + + case 2: case 3: case 4: case 5: + { + Expression* len = Expression::make_integer_ul(this->exprs_->size(), + NULL, loc); + Array_type* arg_type = Type::make_array_type(type, len); + arg_type->set_is_array_incomparable(); + Expression* arg = + Expression::make_array_composite_literal(arg_type, this->exprs_, + loc); + Runtime::Function code; + switch (this->exprs_->size()) + { + default: + go_unreachable(); + case 2: + code = Runtime::CONCATSTRING2; + break; + case 3: + code = Runtime::CONCATSTRING3; + break; + case 4: + code = Runtime::CONCATSTRING4; + break; + case 5: + code = Runtime::CONCATSTRING5; + break; + } + call = Runtime::make_call(code, loc, 2, nil_arg, arg); + } + break; + + default: + { + Type* arg_type = Type::make_array_type(type, NULL); + Slice_construction_expression* sce = + Expression::make_slice_composite_literal(arg_type, this->exprs_, + loc); + sce->set_storage_does_not_escape(); + call = Runtime::make_call(Runtime::CONCATSTRINGS, loc, 2, nil_arg, + sce); + } + break; + } + + return Expression::make_cast(type, call, loc); +} + +void +String_concat_expression::do_dump_expression( + Ast_dump_context* ast_dump_context) const +{ + ast_dump_context->ostream() << "concat("; + ast_dump_context->dump_expression_list(this->exprs_, false); + ast_dump_context->ostream() << ")"; +} + +Expression* +Expression::make_string_concat(Expression_list* exprs) +{ + return new String_concat_expression(exprs); +} + // Class Bound_method_expression. // Traversal. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 6db6edd..11614c3 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -37,6 +37,7 @@ class Type_conversion_expression; class Unsafe_type_conversion_expression; class Unary_expression; class Binary_expression; +class String_concat_expression; class Call_expression; class Call_result_expression; class Func_expression; @@ -85,6 +86,7 @@ class Expression EXPRESSION_TYPE, EXPRESSION_UNARY, EXPRESSION_BINARY, + EXPRESSION_STRING_CONCAT, EXPRESSION_CONST_REFERENCE, EXPRESSION_VAR_REFERENCE, EXPRESSION_ENCLOSED_VAR_REFERENCE, @@ -160,6 +162,10 @@ class Expression static Expression* make_binary(Operator, Expression*, Expression*, Location); + // Make a string concatenation expression. + static Expression* + make_string_concat(Expression_list*); + // Make a reference to a constant in an expression. static Expression* make_const_reference(Named_object*, Location); @@ -620,6 +626,14 @@ class Expression binary_expression() { return this->convert<Binary_expression, EXPRESSION_BINARY>(); } + // If this is a string concatenation expression, return the + // String_concat_expression structure. Otherwise, return NULL. + String_concat_expression* + string_concat_expression() + { + return this->convert<String_concat_expression, EXPRESSION_STRING_CONCAT>(); + } + // If this is a call expression, return the Call_expression // structure. Otherwise, return NULL. This is a controlled dynamic // cast. @@ -1877,6 +1891,13 @@ class Binary_expression : public Expression static bool check_operator_type(Operator op, Type* type, Type* otype, Location); + // Set *RESULT_TYPE to the resulting type when OP is applied to + // operands of type LEFT_TYPE and RIGHT_TYPE. Return true on + // success, false on failure. + static bool + operation_type(Operator op, Type* left_type, Type* right_type, + Type** result_type); + protected: int do_traverse(Traverse* traverse); @@ -1928,10 +1949,6 @@ class Binary_expression : public Expression private: static bool - operation_type(Operator op, Type* left_type, Type* right_type, - Type** result_type); - - static bool cmp_to_bool(Operator op, int cmp); static bool @@ -1980,6 +1997,69 @@ class Binary_expression : public Expression Type* type_; }; +// A string concatenation expression. This is a sequence of strings +// added together. It is created when lowering Binary_expression. + +class String_concat_expression : public Expression +{ + public: + String_concat_expression(Expression_list* exprs) + : Expression(EXPRESSION_STRING_CONCAT, exprs->front()->location()), + exprs_(exprs) + { } + + // Return the list of string expressions to be concatenated. + Expression_list* + exprs() + { return this->exprs_; } + + protected: + int + do_traverse(Traverse* traverse) + { return this->exprs_->traverse(traverse); } + + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int) + { return this; } + + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + + bool + do_is_constant() const; + + bool + do_is_immutable() const; + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { return Expression::make_string_concat(this->exprs_->copy()); } + + Bexpression* + do_get_backend(Translate_context*) + { go_unreachable(); } + + void + do_export(Export*) const + { go_unreachable(); } + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The string expressions to concatenate. + Expression_list* exprs_; +}; + // A call expression. The go statement needs to dig inside this. class Call_expression : public Expression diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc index 98678f4..4072920 100644 --- a/gcc/go/gofrontend/runtime.cc +++ b/gcc/go/gofrontend/runtime.cc @@ -64,6 +64,14 @@ enum Runtime_function_type RFT_FUNC_PTR, // Pointer to Go type descriptor. RFT_TYPE, + // [2]string. + RFT_ARRAY2STRING, + // [3]string. + RFT_ARRAY3STRING, + // [4]string. + RFT_ARRAY4STRING, + // [5]string. + RFT_ARRAY5STRING, NUMBER_OF_RUNTIME_FUNCTION_TYPES }; @@ -180,6 +188,30 @@ runtime_function_type(Runtime_function_type bft) case RFT_TYPE: t = Type::make_type_descriptor_ptr_type(); break; + + case RFT_ARRAY2STRING: + t = Type::make_array_type(Type::make_string_type(), + Expression::make_integer_ul(2, NULL, + bloc)); + break; + + case RFT_ARRAY3STRING: + t = Type::make_array_type(Type::make_string_type(), + Expression::make_integer_ul(3, NULL, + bloc)); + break; + + case RFT_ARRAY4STRING: + t = Type::make_array_type(Type::make_string_type(), + Expression::make_integer_ul(4, NULL, + bloc)); + break; + + case RFT_ARRAY5STRING: + t = Type::make_array_type(Type::make_string_type(), + Expression::make_integer_ul(5, NULL, + bloc)); + break; } runtime_function_types[bft] = t; @@ -226,6 +258,10 @@ convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, case RFT_CHAN: case RFT_IFACE: case RFT_EFACE: + case RFT_ARRAY2STRING: + case RFT_ARRAY3STRING: + case RFT_ARRAY4STRING: + case RFT_ARRAY5STRING: return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc); case RFT_TYPE: diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index e7edfa6..4e4c3e3 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -38,8 +38,17 @@ DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT)) DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT), R2(INT, RUNE)) -// Concatenate two strings. -DEF_GO_RUNTIME(STRING_PLUS, "__go_string_plus", P2(STRING, STRING), R1(STRING)) +// Concatenate strings. +DEF_GO_RUNTIME(CONCATSTRINGS, "runtime.concatstrings", P2(POINTER, SLICE), + R1(STRING)) +DEF_GO_RUNTIME(CONCATSTRING2, "runtime.concatstring2", + P2(POINTER, ARRAY2STRING), R1(STRING)) +DEF_GO_RUNTIME(CONCATSTRING3, "runtime.concatstring3", + P2(POINTER, ARRAY3STRING), R1(STRING)) +DEF_GO_RUNTIME(CONCATSTRING4, "runtime.concatstring4", + P2(POINTER, ARRAY4STRING), R1(STRING)) +DEF_GO_RUNTIME(CONCATSTRING5, "runtime.concatstring5", + P2(POINTER, ARRAY5STRING), R1(STRING)) // Compare two strings. DEF_GO_RUNTIME(STRCMP, "__go_strcmp", P2(STRING, STRING), R1(INT)) @@ -49,23 +58,23 @@ DEF_GO_RUNTIME(STRING_SLICE, "__go_string_slice", P3(STRING, INT, INT), R1(STRING)) // Convert an integer to a string. -DEF_GO_RUNTIME(INT_TO_STRING, "__go_int_to_string", P1(INT), R1(STRING)) +DEF_GO_RUNTIME(INTSTRING, "runtime.intstring", P2(POINTER, INT64), R1(STRING)) -// Convert a byte array to a string. -DEF_GO_RUNTIME(BYTE_ARRAY_TO_STRING, "__go_byte_array_to_string", - P2(POINTER, INT), R1(STRING)) +// Convert a []byte to a string. +DEF_GO_RUNTIME(SLICEBYTETOSTRING, "runtime.slicebytetostring", + P2(POINTER, SLICE), R1(STRING)) -// Convert an int array to a string. -DEF_GO_RUNTIME(INT_ARRAY_TO_STRING, "__go_int_array_to_string", - P2(POINTER, INT), R1(STRING)) +// Convert a []rune to a string. +DEF_GO_RUNTIME(SLICERUNETOSTRING, "runtime.slicerunetostring", + P2(POINTER, SLICE), R1(STRING)) -// Convert a string to a byte slice. -DEF_GO_RUNTIME(STRING_TO_BYTE_ARRAY, "__go_string_to_byte_array", - P1(STRING), R1(SLICE)) +// Convert a string to a []byte. +DEF_GO_RUNTIME(STRINGTOSLICEBYTE, "runtime.stringtoslicebyte", + P2(POINTER, STRING), R1(SLICE)) -// Convert a string to an int slice. -DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array", - P1(STRING), R1(SLICE)) +// Convert a string to a []rune. +DEF_GO_RUNTIME(STRINGTOSLICERUNE, "runtime.stringtoslicerune", + P2(POINTER, STRING), R1(SLICE)) // Complex division. |