diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/go/ChangeLog | 8 | ||||
-rw-r--r-- | gcc/go/Make-lang.in | 12 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 128 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 7 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.cc | 383 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 341 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.h | 47 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 523 |
9 files changed, 1009 insertions, 443 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 9f400f1..79f9a11 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,11 @@ +2011-04-13 Ian Lance Taylor <iant@google.com> + + * Make-lang.in (GO_OBJS): Add go/runtime.o. + (GO_RUNTIME_H): New variable. + (go/runtime.o): New target. + (go/gogo.o): Depend on $(GO_RUNTIME_H). + (go/statements.o): Likewise. + 2011-04-12 Nathan Froyd <froydnj@codesourcery.com> * go-lang.c (union lang_tree_node): Check for TS_COMMON before diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index 0dc8942..c5289c6 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -59,6 +59,7 @@ GO_OBJS = \ go/import-archive.o \ go/lex.o \ go/parse.o \ + go/runtime.o \ go/statements.o \ go/types.o \ go/unsafe.o @@ -220,6 +221,7 @@ GO_TYPES_H = go/gofrontend/types.h GO_STATEMENTS_H = go/gofrontend/statements.h go/gofrontend/operator.h GO_EXPRESSIONS_H = go/gofrontend/expressions.h go/gofrontend/operator.h GO_IMPORT_H = go/gofrontend/import.h go/gofrontend/export.h +GO_RUNTIME_H = go/gofrontend/runtime.h go/gofrontend/runtime.def go/go-backend.o: go/go-backend.c $(CONFIG_H) $(SYSTEM_H) coretypes.h \ $(TM_H) $(RTL_H) $(TREE_H) $(TM_P_H) $(TARGET_H) @@ -263,8 +265,9 @@ go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TOPLEV_H) \ $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_GOGO_H) go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) $(GO_C_H) \ go/gofrontend/go-dump.h $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) \ - $(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_IMPORT_H) \ - go/gofrontend/export.h go/gofrontend/backend.h $(GO_GOGO_H) + $(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_RUNTIME_H) \ + $(GO_IMPORT_H) go/gofrontend/export.h go/gofrontend/backend.h \ + $(GO_GOGO_H) go/import.o: go/gofrontend/import.cc $(GO_SYSTEM_H) \ $(srcdir)/../include/filenames.h $(srcdir)/../include/simple-object.h \ $(GO_C_H) $(GO_GOGO_H) $(GO_TYPES_H) go/gofrontend/export.h \ @@ -274,10 +277,13 @@ go/import-archive.o: go/gofrontend/import-archive.cc $(GO_SYSTEM_H) \ go/lex.o: go/gofrontend/lex.cc $(GO_LEX_H) $(GO_SYSTEM_H) go/parse.o: go/gofrontend/parse.cc $(GO_SYSTEM_H) $(GO_LEX_H) $(GO_GOGO_H) \ $(GO_TYPES_H) $(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) $(GO_PARSE_H) +go/runtime.o: go/gofrontend/runtime.cc $(GO_SYSTEM_H) $(GO_GOGO_H) \ + $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_RUNTIME_H) \ + go/gofrontend/runtime.def go/statements.o: go/gofrontend/statements.cc $(GO_SYSTEM_H) intl.h $(TREE_H) \ $(GIMPLE_H) convert.h tree-iterator.h $(TREE_FLOW_H) $(REAL_H) \ $(GO_C_H) $(GO_TYPES_H) $(GO_EXPRESSIONS_H) $(GO_GOGO_H) \ - go/gofrontend/backend.h $(GO_STATEMENTS_H) + $(GO_RUNTIME_H) go/gofrontend/backend.h $(GO_STATEMENTS_H) go/types.o: go/gofrontend/types.cc $(GO_SYSTEM_H) $(TOPLEV_H) intl.h $(TREE_H) \ $(GIMPLE_H) $(REAL_H) convert.h $(GO_C_H) $(GO_GOGO_H) \ go/gofrontend/operator.h $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) \ diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index c516485..7f291d4 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3410,7 +3410,7 @@ Type_conversion_expression::do_get_tree(Translate_context* context) tree valptr = fold_convert(const_ptr_type_node, a->value_pointer_tree(gogo, expr_tree)); tree len = a->length_tree(gogo, expr_tree); - len = fold_convert_loc(this->location(), size_type_node, len); + len = fold_convert_loc(this->location(), integer_type_node, len); if (e->integer_type()->is_unsigned() && e->integer_type()->bits() == 8) { @@ -3422,7 +3422,7 @@ Type_conversion_expression::do_get_tree(Translate_context* context) type_tree, const_ptr_type_node, valptr, - size_type_node, + integer_type_node, len); } else @@ -3436,7 +3436,7 @@ Type_conversion_expression::do_get_tree(Translate_context* context) type_tree, const_ptr_type_node, valptr, - size_type_node, + integer_type_node, len); } } @@ -3523,6 +3523,122 @@ Expression::make_cast(Type* type, Expression* val, source_location location) return new Type_conversion_expression(type, val, location); } +// An unsafe type conversion, used to pass values to builtin functions. + +class Unsafe_type_conversion_expression : public Expression +{ + public: + Unsafe_type_conversion_expression(Type* type, Expression* expr, + source_location location) + : Expression(EXPRESSION_UNSAFE_CONVERSION, location), + type_(type), expr_(expr) + { } + + protected: + int + do_traverse(Traverse* traverse); + + Type* + do_type() + { return this->type_; } + + void + do_determine_type(const Type_context*) + { } + + Expression* + do_copy() + { + return new Unsafe_type_conversion_expression(this->type_, + this->expr_->copy(), + this->location()); + } + + tree + do_get_tree(Translate_context*); + + private: + // The type to convert to. + Type* type_; + // The expression to convert. + Expression* expr_; +}; + +// Traversal. + +int +Unsafe_type_conversion_expression::do_traverse(Traverse* traverse) +{ + if (Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT + || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return TRAVERSE_CONTINUE; +} + +// Convert to backend representation. + +tree +Unsafe_type_conversion_expression::do_get_tree(Translate_context* context) +{ + // We are only called for a limited number of cases. + + Type* t = this->type_; + Type* et = this->expr_->type(); + + tree type_tree = this->type_->get_tree(context->gogo()); + tree expr_tree = this->expr_->get_tree(context); + if (type_tree == error_mark_node || expr_tree == error_mark_node) + return error_mark_node; + + source_location loc = this->location(); + + bool use_view_convert = false; + if (t->is_open_array_type()) + { + gcc_assert(et->is_open_array_type()); + use_view_convert = true; + } + else if (t->map_type() != NULL) + gcc_assert(et->map_type() != NULL); + else if (t->channel_type() != NULL) + gcc_assert(et->channel_type() != NULL); + else if (t->points_to() != NULL && t->points_to()->channel_type() != NULL) + gcc_assert(et->points_to() != NULL + && et->points_to()->channel_type() != NULL); + else if (t->is_unsafe_pointer_type()) + gcc_assert(et->points_to() != NULL); + else if (et->is_unsafe_pointer_type()) + gcc_assert(t->points_to() != NULL); + else if (t->interface_type() != NULL && !t->interface_type()->is_empty()) + { + gcc_assert(et->interface_type() != NULL + && !et->interface_type()->is_empty()); + use_view_convert = true; + } + else if (t->interface_type() != NULL && t->interface_type()->is_empty()) + { + gcc_assert(et->interface_type() != NULL + && et->interface_type()->is_empty()); + use_view_convert = true; + } + else + gcc_unreachable(); + + if (use_view_convert) + return fold_build1_loc(loc, VIEW_CONVERT_EXPR, type_tree, expr_tree); + else + return fold_convert_loc(loc, type_tree, expr_tree); +} + +// Make an unsafe type conversion expression. + +Expression* +Expression::make_unsafe_cast(Type* type, Expression* expr, + source_location location) +{ + return new Unsafe_type_conversion_expression(type, expr, location); +} + // Unary expressions. class Unary_expression : public Expression @@ -7654,7 +7770,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context) location, "__go_map_len", 1, - sizetype, + integer_type_node, arg_type->get_tree(gogo), arg_tree); } @@ -7665,7 +7781,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context) location, "__go_chan_len", 1, - sizetype, + integer_type_node, arg_type->get_tree(gogo), arg_tree); } @@ -7693,7 +7809,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context) location, "__go_chan_cap", 1, - sizetype, + integer_type_node, arg_type->get_tree(gogo), arg_tree); } diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index fa240a6..66aabeb 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -81,6 +81,7 @@ class Expression EXPRESSION_MAKE, EXPRESSION_TYPE_GUARD, EXPRESSION_CONVERSION, + EXPRESSION_UNSAFE_CONVERSION, EXPRESSION_STRUCT_CONSTRUCTION, EXPRESSION_FIXED_ARRAY_CONSTRUCTION, EXPRESSION_OPEN_ARRAY_CONSTRUCTION, @@ -247,6 +248,12 @@ class Expression static Expression* make_cast(Type*, Expression*, source_location); + // Make an unsafe type cast expression. This is only used when + // passing parameter to builtin functions that are part of the Go + // runtime. + static Expression* + make_unsafe_cast(Type*, Expression*, source_location); + // Make a composite literal. The DEPTH parameter is how far down we // are in a list of composite literals with omitted types. static Expression* diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 31549ac..e22de4b 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -13,6 +13,7 @@ #include "statements.h" #include "expressions.h" #include "dataflow.h" +#include "runtime.h" #include "import.h" #include "export.h" #include "backend.h" @@ -2598,6 +2599,8 @@ Gogo::convert_named_types() Interface_type::make_interface_type_descriptor_type(); Type::convert_builtin_named_types(this); + Runtime::convert_types(this); + this->named_types_are_converted_ = true; } diff --git a/gcc/go/gofrontend/runtime.cc b/gcc/go/gofrontend/runtime.cc new file mode 100644 index 0000000..7249dff --- /dev/null +++ b/gcc/go/gofrontend/runtime.cc @@ -0,0 +1,383 @@ +// runtime.cc -- runtime functions called by generated code + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go-system.h" + +#include <gmp.h> + +#include "gogo.h" +#include "types.h" +#include "expressions.h" +#include "runtime.h" + +// The frontend generates calls to various runtime functions. They +// are implemented in libgo/runtime. This is how the runtime +// functions are represented in the frontend. Note that there is +// currently nothing which ensures that the compiler's understanding +// of the runtime function matches the actual implementation in +// libgo/runtime. + +// Parameter and result types used by runtime functions. + +enum Runtime_function_type +{ + // General indicator that value is not used. + RFT_VOID, + // Go type bool, C type _Bool. + RFT_BOOL, + // Go type *bool, C type _Bool*. + RFT_BOOLPTR, + // Go type int, C type int. + RFT_INT, + // Go type int64, C type int64_t. + RFT_INT64, + // Go type uint64, C type uint64_t. + RFT_UINT64, + // Go type uintptr, C type uintptr_t. + RFT_UINTPTR, + // Go type float64, C type double. + RFT_FLOAT64, + // Go type complex128, C type __complex double. + RFT_COMPLEX128, + // Go type string, C type struct __go_string. + RFT_STRING, + // Go type unsafe.Pointer, C type "void *". + RFT_POINTER, + // Go type []any, C type struct __go_open_array. + RFT_SLICE, + // Go type map[any]any, C type struct __go_map *. + RFT_MAP, + // Pointer to map iteration type. + RFT_MAPITER, + // Go type chan any, C type struct __go_channel *. + RFT_CHAN, + // Go type *chan any, C type struct __go_channel **. + RFT_CHANPTR, + // Go type non-empty interface, C type struct __go_interface. + RFT_IFACE, + // Go type interface{}, C type struct __go_empty_interface. + RFT_EFACE, + // Go type func(unsafe.Pointer), C type void (*) (void *). + RFT_FUNC_PTR, + // Pointer to Go type descriptor. + RFT_TYPE, + + NUMBER_OF_RUNTIME_FUNCTION_TYPES +}; + +// The Type structures for the runtime function types. + +static Type* runtime_function_types[NUMBER_OF_RUNTIME_FUNCTION_TYPES]; + +// Get the Type for a Runtime_function_type code. + +static Type* +runtime_function_type(Runtime_function_type bft) +{ + gcc_assert(bft < NUMBER_OF_RUNTIME_FUNCTION_TYPES); + if (runtime_function_types[bft] == NULL) + { + const source_location bloc = BUILTINS_LOCATION; + Type* t; + switch (bft) + { + default: + case RFT_VOID: + gcc_unreachable(); + + case RFT_BOOL: + t = Type::lookup_bool_type(); + break; + + case RFT_BOOLPTR: + t = Type::make_pointer_type(Type::lookup_bool_type()); + break; + + case RFT_INT: + t = Type::lookup_integer_type("int"); + break; + + case RFT_INT64: + t = Type::lookup_integer_type("int64"); + break; + + case RFT_UINT64: + t = Type::lookup_integer_type("uint64"); + break; + + case RFT_UINTPTR: + t = Type::lookup_integer_type("uintptr"); + break; + + case RFT_FLOAT64: + t = Type::lookup_float_type("float64"); + break; + + case RFT_COMPLEX128: + t = Type::lookup_complex_type("complex128"); + break; + + case RFT_STRING: + t = Type::lookup_string_type(); + break; + + case RFT_POINTER: + t = Type::make_pointer_type(Type::make_void_type()); + break; + + case RFT_SLICE: + t = Type::make_array_type(Type::make_void_type(), NULL); + break; + + case RFT_MAP: + t = Type::make_map_type(Type::make_void_type(), + Type::make_void_type(), + bloc); + break; + + case RFT_MAPITER: + t = Type::make_pointer_type(Runtime::map_iteration_type()); + break; + + case RFT_CHAN: + t = Type::make_channel_type(true, true, Type::make_void_type()); + break; + + case RFT_CHANPTR: + t = Type::make_pointer_type(runtime_function_type(RFT_CHAN)); + break; + + case RFT_IFACE: + { + Typed_identifier_list* methods = new Typed_identifier_list(); + Type* mtype = Type::make_function_type(NULL, NULL, NULL, bloc); + methods->push_back(Typed_identifier("x", mtype, bloc)); + t = Type::make_interface_type(methods, bloc); + } + break; + + case RFT_EFACE: + t = Type::make_interface_type(NULL, bloc); + break; + + case RFT_FUNC_PTR: + { + Typed_identifier_list* param_types = new Typed_identifier_list(); + Type* ptrtype = runtime_function_type(RFT_POINTER); + param_types->push_back(Typed_identifier("", ptrtype, bloc)); + t = Type::make_function_type(NULL, param_types, NULL, bloc); + } + break; + + case RFT_TYPE: + t = Type::make_type_descriptor_ptr_type(); + break; + } + + runtime_function_types[bft] = t; + } + + return runtime_function_types[bft]; +} + +// Convert an expression to the type to pass to a runtime function. + +static Expression* +convert_to_runtime_function_type(Runtime_function_type bft, Expression* e, + source_location loc) +{ + switch (bft) + { + default: + case RFT_VOID: + gcc_unreachable(); + + case RFT_BOOL: + case RFT_BOOLPTR: + case RFT_INT: + case RFT_INT64: + case RFT_UINT64: + case RFT_UINTPTR: + case RFT_FLOAT64: + case RFT_COMPLEX128: + case RFT_STRING: + case RFT_POINTER: + case RFT_MAPITER: + case RFT_FUNC_PTR: + { + Type* t = runtime_function_type(bft); + if (!Type::are_identical(t, e->type(), true, NULL)) + e = Expression::make_cast(t, e, loc); + return e; + } + + case RFT_SLICE: + case RFT_MAP: + case RFT_CHAN: + case RFT_CHANPTR: + case RFT_IFACE: + case RFT_EFACE: + return Expression::make_unsafe_cast(runtime_function_type(bft), e, loc); + + case RFT_TYPE: + gcc_assert(e->type() == Type::make_type_descriptor_ptr_type()); + return e; + } +} + +// Convert all the types used for runtime functions to the backend +// representation. + +void +Runtime::convert_types(Gogo* gogo) +{ + for (int i = 0; i < static_cast<int>(NUMBER_OF_RUNTIME_FUNCTION_TYPES); ++i) + { + Type* t = runtime_function_types[i]; + if (t != NULL && t->named_type() != NULL) + { + bool r = t->verify(); + gcc_assert(r); + t->named_type()->convert(gogo); + } + } +} + +// The type used to define a runtime function. + +struct Runtime_function +{ + // Function name. + const char* name; + // Parameter types. Never more than 6, as it happens. RFT_VOID if + // not used. + Runtime_function_type parameter_types[6]; + // Result types. Never more than 2, as it happens. RFT_VOID if not + // used. + Runtime_function_type result_types[2]; +}; + +static const Runtime_function runtime_functions[] = +{ + +#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) { NAME, PARAMS, RESULTS } , + +#include "runtime.def" + +#undef DEF_GO_RUNTIME + +}; + +static Named_object* +runtime_function_declarations[Runtime::NUMBER_OF_FUNCTIONS]; + +// Get the declaration of a runtime function. + +Named_object* +Runtime::runtime_declaration(Function code) +{ + gcc_assert(code < Runtime::NUMBER_OF_FUNCTIONS); + if (runtime_function_declarations[code] == NULL) + { + const Runtime_function* pb = &runtime_functions[code]; + + source_location bloc = BUILTINS_LOCATION; + + Typed_identifier_list* param_types = NULL; + if (pb->parameter_types[0] != RFT_VOID) + { + param_types = new Typed_identifier_list(); + for (unsigned int i = 0; + i < (sizeof(pb->parameter_types) + / sizeof (pb->parameter_types[0])); + i++) + { + if (pb->parameter_types[i] == RFT_VOID) + break; + Type* t = runtime_function_type(pb->parameter_types[i]); + param_types->push_back(Typed_identifier("", t, bloc)); + } + } + + Typed_identifier_list* result_types = NULL; + if (pb->result_types[0] != RFT_VOID) + { + result_types = new Typed_identifier_list(); + for (unsigned int i = 0; + i < sizeof(pb->result_types) / sizeof(pb->result_types[0]); + i++) + { + if (pb->result_types[i] == RFT_VOID) + break; + Type* t = runtime_function_type(pb->result_types[i]); + result_types->push_back(Typed_identifier("", t, bloc)); + } + } + + Function_type* fntype = Type::make_function_type(NULL, param_types, + result_types, bloc); + const char* n = pb->name; + const char* n1 = strchr(n, '.'); + if (n1 != NULL) + n = n1 + 1; + Named_object* no = Named_object::make_function_declaration(n, NULL, + fntype, bloc); + no->func_declaration_value()->set_asm_name(pb->name); + + runtime_function_declarations[code] = no; + } + + return runtime_function_declarations[code]; +} + +// Make a call to a runtime function. + +Call_expression* +Runtime::make_call(Runtime::Function code, source_location loc, + int param_count, ...) +{ + gcc_assert(code < Runtime::NUMBER_OF_FUNCTIONS); + + const Runtime_function* pb = &runtime_functions[code]; + + gcc_assert(static_cast<size_t>(param_count) + <= sizeof(pb->parameter_types) / sizeof(pb->parameter_types[0])); + + Named_object* no = runtime_declaration(code); + Expression* func = Expression::make_func_reference(no, NULL, loc); + + Expression_list* args = new Expression_list(); + args->reserve(param_count); + + va_list ap; + va_start(ap, param_count); + for (int i = 0; i < param_count; ++i) + { + Expression* e = va_arg(ap, Expression*); + Runtime_function_type rft = pb->parameter_types[i]; + args->push_back(convert_to_runtime_function_type(rft, e, loc)); + } + va_end(ap); + + return Expression::make_call(func, args, false, loc); +} + +// The type we use for a map iteration. This is really a struct which +// is four pointers long. This must match the runtime struct +// __go_hash_iter. + +Type* +Runtime::map_iteration_type() +{ + const unsigned long map_iteration_size = 4; + + mpz_t ival; + mpz_init_set_ui(ival, map_iteration_size); + Expression* iexpr = Expression::make_integer(&ival, NULL, BUILTINS_LOCATION); + mpz_clear(ival); + + return Type::make_array_type(runtime_function_type(RFT_POINTER), iexpr); +} diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def new file mode 100644 index 0000000..6e7a807 --- /dev/null +++ b/gcc/go/gofrontend/runtime.def @@ -0,0 +1,341 @@ +// runtime.def -- runtime functions called by generated code. -*- C++ -*- + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +// Definitions for the Go runtime functions. + +// Parameter type helper macros. +#define ABFT6(T1, T2, T3, T4, T5, T6) \ + { RFT_ ## T1, RFT_ ## T2, RFT_ ## T3, RFT_ ## T4, RFT_ ## T5, RFT_ ## T6 } +#define P0() ABFT6(VOID, VOID, VOID, VOID, VOID, VOID) +#define P1(T) ABFT6(T, VOID, VOID, VOID, VOID, VOID) +#define P2(T1, T2) ABFT6(T1, T2, VOID, VOID, VOID, VOID) +#define P3(T1, T2, T3) ABFT6(T1, T2, T3, VOID, VOID, VOID) +#define P4(T1, T2, T3, T4) ABFT6(T1, T2, T3, T4, VOID, VOID) +#define P5(T1, T2, T3, T4, T5) ABFT6(T1, T2, T3, T4, T5, VOID) +#define P6(T1,T2,T3,T4,T5,T6) ABFT6(T1, T2, T3, T4, T5, T6) + +// Result type helper macros. +#define ABFT2(T1, T2) { RFT_ ## T1, RFT_ ## T2 } +#define R0() ABFT2(VOID, VOID) +#define R1(T) ABFT2(T, VOID) +#define R2(T1, T2) ABFT2(T1, T2) + +// Define all the Go runtime functions. The first parameter is the +// enum code used to refer to the function. The second parameter is +// the name. The third is the parameter types and the fourth is the +// result types. + +// Range over a string, returning the next index. +DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT)) + +// Range over a string, returning the next index and character. +DEF_GO_RUNTIME(STRINGITER2, "runtime.stringiter2", P2(STRING, INT), + R2(INT, INT)) + +// Concatenate two strings. +DEF_GO_RUNTIME(STRING_PLUS, "__go_string_plus", P2(STRING, STRING), R1(STRING)) + +// Compare two strings. +DEF_GO_RUNTIME(STRCMP, "__go_strcmp", P2(STRING, STRING), R1(INT)) + +// Take a slice of a string. +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)) + +// 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 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 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 an int slice. +DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array", + P1(STRING), R1(SLICE)) + + +// Make a map. +DEF_GO_RUNTIME(NEW_MAP, "__go_new_map", P2(TYPE, UINTPTR), R1(MAP)) + +// Build a map from a composite literal. +DEF_GO_RUNTIME(CONSTRUCT_MAP, "__go_construct_map", + P6(POINTER, UINTPTR, UINTPTR, UINTPTR, UINTPTR, POINTER), + R1(MAP)) + +// Get the length of a map (the number of entries). +DEF_GO_RUNTIME(MAP_LEN, "__go_map_len", P1(MAP), R1(INT)) + +// Look up a key in a map. +DEF_GO_RUNTIME(MAP_INDEX, "__go_map_index", P3(MAP, POINTER, BOOL), + R1(POINTER)) + +// Look up a key in a map returning whether it is present. +DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2", P3(MAP, POINTER, POINTER), + R1(BOOL)) + +// Tuple assignment to a map element. +DEF_GO_RUNTIME(MAPASSIGN2, "runtime.mapassign2", + P4(MAP, POINTER, POINTER, BOOL), R0()) + +// Begin a range over a map. +DEF_GO_RUNTIME(MAPITERINIT, "runtime.mapiterinit", P2(MAP, MAPITER), R0()) + +// Range over a map, returning the next key. +DEF_GO_RUNTIME(MAPITER1, "runtime.mapiter1", P2(MAPITER, POINTER), R0()) + +// Range over a map, returning the next key and value. +DEF_GO_RUNTIME(MAPITER2, "runtime.mapiter2", P3(MAPITER, POINTER, POINTER), + R0()) + +// Range over a map, moving to the next map entry. +DEF_GO_RUNTIME(MAPITERNEXT, "runtime.mapiternext", P1(MAPITER), R0()) + + +// Make a channel. +DEF_GO_RUNTIME(NEW_CHANNEL, "__go_new_channel", P2(UINTPTR, UINTPTR), R1(CHAN)) + +// Get the length of a channel (the number of unread values). +DEF_GO_RUNTIME(CHAN_LEN, "__go_chan_len", P1(CHAN), R1(INT)) + +// Get the capacity of a channel (the size of the buffer). +DEF_GO_RUNTIME(CHAN_CAP, "__go_chan_cap", P1(CHAN), R1(INT)) + +// Send a small value on a channel. +DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(CHAN, UINT64, BOOL), R0()) + +// Send a small value on a channel without blocking. +DEF_GO_RUNTIME(SEND_NONBLOCKING_SMALL, "__go_send_nonblocking_small", + P2(CHAN, UINT64), R1(BOOL)) + +// Send a big value on a channel. +DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(CHAN, POINTER, BOOL), R0()) + +// Send a big value on a channel without blocking. +DEF_GO_RUNTIME(SEND_NONBLOCKING_BIG, "__go_send_nonblocking_big", + P2(CHAN, POINTER), R1(BOOL)) + +// Receive a small value from a channel. +DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(CHAN, BOOL), R1(UINT64)) + +// Receive a big value from a channel. +DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(CHAN, POINTER, BOOL), + R1(BOOL)) + +// Receive a value from a channel returning whether it is closed. +DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL)) + +// Receive a value from a channel returning whether it is closed, for select. +DEF_GO_RUNTIME(CHANRECV3, "runtime.chanrecv3", P2(CHAN, POINTER), R1(BOOL)) + + +// Panic. +DEF_GO_RUNTIME(PANIC, "__go_panic", P1(EFACE), R0()) + +// Recover. +DEF_GO_RUNTIME(RECOVER, "__go_recover", P0(), R1(EFACE)) + +// Recover when called directly from defer. +DEF_GO_RUNTIME(DEFERRED_RECOVER, "__go_deferred_recover", P0(), R1(EFACE)) + +// Decide whether this function can call recover. +DEF_GO_RUNTIME(CAN_RECOVER, "__go_can_recover", P1(POINTER), R1(BOOL)) + +// Get the return address of the function. +DEF_GO_RUNTIME(RETURN_ADDRESS, "__go_return_address", P1(INT), R1(POINTER)) + +// Set the return address for defer in a defer thunk. +DEF_GO_RUNTIME(SET_DEFER_RETADDR, "__go_set_defer_retaddr", P1(POINTER), + R1(BOOL)) + +// Check for a deferred function in an exception handler. +DEF_GO_RUNTIME(CHECK_DEFER, "__go_check_defer", P1(POINTER), R0()) + +// Run deferred functions. +DEF_GO_RUNTIME(UNDEFER, "__go_undefer", P1(POINTER), R0()) + +// Panic with a runtime error. +DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT), R0()) + + +// Close. +DEF_GO_RUNTIME(CLOSE, "__go_close", P1(CHAN), R0()) + + +// Copy. +DEF_GO_RUNTIME(COPY, "__go_copy", P3(POINTER, POINTER, UINTPTR), R0()) + +// Append. +DEF_GO_RUNTIME(APPEND, "__go_append", P4(SLICE, POINTER, UINTPTR, UINTPTR), + R1(SLICE)) + + +// Register roots (global variables) for the garbage collector. +DEF_GO_RUNTIME(REGISTER_GC_ROOTS, "__go_register_gc_roots", P1(POINTER), R0()) + + +// Allocate memory. +DEF_GO_RUNTIME(NEW, "__go_new", P1(UINTPTR), R1(POINTER)) + +// Allocate memory which can not contain pointers. +DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER)) + + +// Allocate a trampoline for a function literal. +DEF_GO_RUNTIME(ALLOCATE_GO_TRAMPOLINE, "__go_allocate_trampoline", + P2(UINTPTR, POINTER), R1(POINTER)) + + +// Start a new goroutine. +DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0()) + + +// Defer a function. +DEF_GO_RUNTIME(DEFER, "__go_defer", P3(POINTER, FUNC_PTR, POINTER), R0()) + + +// Run a select statement. +DEF_GO_RUNTIME(SELECT, "__go_select", P4(UINTPTR, BOOL, CHANPTR, BOOLPTR), + R1(UINTPTR)) + + +// Convert an empty interface to an empty interface, returning ok. +DEF_GO_RUNTIME(IFACEE2E2, "runtime.ifaceE2E2", P1(EFACE), R2(EFACE, BOOL)) + +// Convert a non-empty interface to an empty interface, returning ok. +DEF_GO_RUNTIME(IFACEI2E2, "runtime.ifaceI2E2", P1(IFACE), R2(EFACE, BOOL)) + +// Convert an empty interface to a non-empty interface, returning ok. +DEF_GO_RUNTIME(IFACEE2I2, "runtime.ifaceE2I2", P2(TYPE, EFACE), + R2(IFACE, BOOL)) + +// Convert a non-empty interface to a non-empty interface, returning ok. +DEF_GO_RUNTIME(IFACEI2I2, "runtime.ifaceI2I2", P2(TYPE, IFACE), + R2(IFACE, BOOL)) + +// Convert an empty interface to a pointer type, returning ok. +DEF_GO_RUNTIME(IFACEE2T2P, "runtime.ifaceE2T2P", P2(TYPE, EFACE), + R2(POINTER, BOOL)) + +// Convert a non-empty interface to a pointer type, return ok. +DEF_GO_RUNTIME(IFACEI2T2P, "runtime.ifaceI2T2P", P2(TYPE, IFACE), + R2(POINTER, BOOL)) + +// Convert an empty interface to a non-pointer type, returning ok. +DEF_GO_RUNTIME(IFACEE2T2, "runtime.ifaceE2T2", P3(TYPE, EFACE, POINTER), + R1(BOOL)) + +// Convert a non-empty interface to a non-pointer type, returning ok. +DEF_GO_RUNTIME(IFACEI2T2, "runtime.ifaceI2T2", P3(TYPE, IFACE, POINTER), + R1(BOOL)) + +// A type assertion from one interface type to another. This is +// used for a type assertion. +DEF_GO_RUNTIME(ASSERT_INTERFACE, "__go_assert_interface", P2(TYPE, TYPE), R0()) + +// Convert one interface type to another. This is used for an +// assignment. +DEF_GO_RUNTIME(CONVERT_INTERFACE, "__go_convert_interface", P2(TYPE, TYPE), + R1(POINTER)) + +// Check whether an interface type may be converted to a +// non-interface type. +DEF_GO_RUNTIME(CHECK_INTERFACE_TYPE, "__go_check_interface_type", + P3(TYPE, TYPE, TYPE), R0()) + +// Return whether we can convert an interface type to a type. +DEF_GO_RUNTIME(IFACEI2TP, "runtime.ifaceI2Tp", 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(EMPTY_INTERFACE_COMPARE, "__go_empty_interface_compare", + P2(EFACE, EFACE), R1(INT)) + +// Compare an empty interface value to a non-interface value. +DEF_GO_RUNTIME(EMPTY_INTERFACE_VALUE_COMPARE, + "__go_empty_interface_value_compare", + P3(EFACE, TYPE, POINTER), R1(INT)) + +// Compare two non-empty interface values. +DEF_GO_RUNTIME(INTERFACE_COMPARE, "__go_interface_compare", + P2(IFACE, IFACE), R1(INT)) + +// Compare a non-empty interface value to a non-interface value. +DEF_GO_RUNTIME(INTERFACE_VALUE_COMPARE, "__go_interface_value_compare", + P3(IFACE, TYPE, POINTER), R1(INT)) + +// Compare a non-empty interface value to an interface value. +DEF_GO_RUNTIME(INTERFACE_EMPTY_COMPARE, "__go_interface_empty_compare", + P2(IFACE, EFACE), R1(INT)) + + +// Print a string (for print/println). +DEF_GO_RUNTIME(PRINT_STRING, "__go_print_string", P1(STRING), R0()) + +// Print a uint64 (for print/println). +DEF_GO_RUNTIME(PRINT_UINT64, "__go_print_uint64", P1(UINT64), R0()) + +// Print a int64 (for print/println). +DEF_GO_RUNTIME(PRINT_INT64, "__go_print_int64", P1(INT64), R0()) + +// Print a float64 (for print/println). +DEF_GO_RUNTIME(PRINT_DOUBLE, "__go_print_double", P1(FLOAT64), R0()) + +// Print a complex128 (for print/println). +DEF_GO_RUNTIME(PRINT_COMPLEX, "__go_print_complex", P1(COMPLEX128), R0()) + +// Print a bool (for print/println). +DEF_GO_RUNTIME(PRINT_BOOL, "__go_print_bool", P1(BOOL), R0()) + +// Print a pointer/map/channel/function (for print/println). +DEF_GO_RUNTIME(PRINT_POINTER, "__go_print_pointer", P1(POINTER), R0()) + +// Print an empty interface (for print/println). +DEF_GO_RUNTIME(PRINT_EMPTY_INTERFACE, "__go_print_empty_interface", + P1(EFACE), R0()) + +// Print a non-empty interface (for print/println). +DEF_GO_RUNTIME(PRINT_INTERFACE, "__go_print_interface", P1(IFACE), R0()) + +// Print a slice (for print/println). +DEF_GO_RUNTIME(PRINT_SLICE, "__go_print_slice", P1(SLICE), R0()) + +// Print a space (for println). +DEF_GO_RUNTIME(PRINT_SPACE, "__go_print_space", P0(), R0()) + +// Print a newline (for println). +DEF_GO_RUNTIME(PRINT_NL, "__go_print_nl", P0(), R0()) + + +// Remove helper macros. +#undef ABFT6 +#undef ABFT2 +#undef P0 +#undef P1 +#undef P2 +#undef P3 +#undef P4 +#undef P5 +#undef P6 +#undef R0 +#undef R1 +#undef R2 diff --git a/gcc/go/gofrontend/runtime.h b/gcc/go/gofrontend/runtime.h new file mode 100644 index 0000000..d8fb00c --- /dev/null +++ b/gcc/go/gofrontend/runtime.h @@ -0,0 +1,47 @@ +// runtime.h -- runtime functions called by generated code -*- C++ -*- + +// Copyright 2011 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef GO_RUNTIME_H +#define GO_RUNTIME_H + +class Gogo; +class Type; +class Named_object; +class Call_expression; + +class Runtime +{ + public: + + // The runtime functions which may be called by generated code. + enum Function + { + +#define DEF_GO_RUNTIME(CODE, NAME, PARAMS, RESULTS) CODE , + +#include "runtime.def" + +#undef DEF_GO_RUNTIME + + // Number of runtime functions. + NUMBER_OF_FUNCTIONS + }; + + static Call_expression* + make_call(Function, source_location, int, ...); + + static void + convert_types(Gogo*); + + static Type* + map_iteration_type(); + + private: + static Named_object* + runtime_declaration(Function); +}; + +#endif // !defined(GO_BUILTINS_H) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index f84b2d4..0b22e30 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -29,6 +29,7 @@ extern "C" #include "types.h" #include "expressions.h" #include "gogo.h" +#include "runtime.h" #include "backend.h" #include "statements.h" @@ -958,33 +959,13 @@ Tuple_map_assignment_statement::do_lower(Gogo*, Named_object*, Statement::make_temporary(Type::lookup_bool_type(), NULL, loc); b->add_statement(present_temp); - // func mapaccess2(hmap map[k]v, key *k, val *v) bool - source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("hmap", map_type, bloc)); - Type* pkey_type = Type::make_pointer_type(map_type->key_type()); - param_types->push_back(Typed_identifier("key", pkey_type, bloc)); - Type* pval_type = Type::make_pointer_type(map_type->val_type()); - param_types->push_back(Typed_identifier("val", pval_type, bloc)); - - Typed_identifier_list* ret_types = new Typed_identifier_list(); - ret_types->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc)); - - Function_type* fntype = Type::make_function_type(NULL, param_types, - ret_types, bloc); - Named_object* mapaccess2 = - Named_object::make_function_declaration("mapaccess2", NULL, fntype, bloc); - mapaccess2->func_declaration_value()->set_asm_name("runtime.mapaccess2"); - // present_temp = mapaccess2(MAP, &key_temp, &val_temp) - Expression* func = Expression::make_func_reference(mapaccess2, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(map_index->map()); Expression* ref = Expression::make_temporary_reference(key_temp, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); + Expression* a1 = Expression::make_unary(OPERATOR_AND, ref, loc); ref = Expression::make_temporary_reference(val_temp, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); - Expression* call = Expression::make_call(func, params, false, loc); + Expression* a2 = Expression::make_unary(OPERATOR_AND, ref, loc); + Expression* call = Runtime::make_call(Runtime::MAPACCESS2, loc, 3, + map_index->map(), a1, a2); ref = Expression::make_temporary_reference(present_temp, loc); Statement* s = Statement::make_assignment(ref, call, loc); @@ -1097,31 +1078,21 @@ Map_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing) Statement::make_temporary(map_type->val_type(), this->val_, loc); b->add_statement(val_temp); - // func mapassign2(hmap map[k]v, key *k, val *v, p) - source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("hmap", map_type, bloc)); - Type* pkey_type = Type::make_pointer_type(map_type->key_type()); - param_types->push_back(Typed_identifier("key", pkey_type, bloc)); - Type* pval_type = Type::make_pointer_type(map_type->val_type()); - param_types->push_back(Typed_identifier("val", pval_type, bloc)); - param_types->push_back(Typed_identifier("p", Type::lookup_bool_type(), bloc)); - Function_type* fntype = Type::make_function_type(NULL, param_types, - NULL, bloc); - Named_object* mapassign2 = - Named_object::make_function_declaration("mapassign2", NULL, fntype, bloc); - mapassign2->func_declaration_value()->set_asm_name("runtime.mapassign2"); + // var insert_temp bool = p + Temporary_statement* insert_temp = + Statement::make_temporary(Type::lookup_bool_type(), this->should_set_, + loc); + b->add_statement(insert_temp); // mapassign2(map_temp, &key_temp, &val_temp, p) - Expression* func = Expression::make_func_reference(mapassign2, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(Expression::make_temporary_reference(map_temp, loc)); + Expression* p1 = Expression::make_temporary_reference(map_temp, loc); Expression* ref = Expression::make_temporary_reference(key_temp, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); + Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); ref = Expression::make_temporary_reference(val_temp, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); - params->push_back(this->should_set_); - Expression* call = Expression::make_call(func, params, false, loc); + Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); + Expression* p4 = Expression::make_temporary_reference(insert_temp, loc); + Expression* call = Runtime::make_call(Runtime::MAPASSIGN2, loc, 4, + p1, p2, p3, p4); Statement* s = Statement::make_statement(call); b->add_statement(s); @@ -1225,40 +1196,13 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*, Statement::make_temporary(Type::lookup_bool_type(), NULL, loc); b->add_statement(closed_temp); - // func chanrecv2(c chan T, val *T) bool - // func chanrecv3(c chan T, val *T) bool (if for_select) - source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("c", channel_type, bloc)); - Type* pelement_type = Type::make_pointer_type(channel_type->element_type()); - param_types->push_back(Typed_identifier("val", pelement_type, bloc)); - - Typed_identifier_list* ret_types = new Typed_identifier_list(); - ret_types->push_back(Typed_identifier("", Type::lookup_bool_type(), bloc)); - - Function_type* fntype = Type::make_function_type(NULL, param_types, - ret_types, bloc); - Named_object* chanrecv; - if (!this->for_select_) - { - chanrecv = Named_object::make_function_declaration("chanrecv2", NULL, - fntype, bloc); - chanrecv->func_declaration_value()->set_asm_name("runtime.chanrecv2"); - } - else - { - chanrecv = Named_object::make_function_declaration("chanrecv3", NULL, - fntype, bloc); - chanrecv->func_declaration_value()->set_asm_name("runtime.chanrecv3"); - } - // closed_temp = chanrecv[23](channel, &val_temp) - Expression* func = Expression::make_func_reference(chanrecv, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(this->channel_); Expression* ref = Expression::make_temporary_reference(val_temp, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); - Expression* call = Expression::make_call(func, params, false, loc); + Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); + Expression* call = Runtime::make_call((this->for_select_ + ? Runtime::CHANRECV3 + : Runtime::CHANRECV2), + loc, 2, this->channel_, p2); ref = Expression::make_temporary_reference(closed_temp, loc); Statement* s = Statement::make_assignment(ref, call, loc); b->add_statement(s); @@ -1318,13 +1262,10 @@ class Tuple_type_guard_assignment_statement : public Statement private: Call_expression* - lower_to_empty_interface(const char*); - - Call_expression* - lower_to_type(const char*); + lower_to_type(Runtime::Function); void - lower_to_object_type(Block*, const char*); + lower_to_object_type(Block*, Runtime::Function); // The variable which recieves the converted value. Expression* val_; @@ -1377,23 +1318,32 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*, if (this->type_->interface_type() != NULL) { if (this->type_->interface_type()->is_empty()) - call = this->lower_to_empty_interface(expr_is_empty - ? "ifaceE2E2" - : "ifaceI2E2"); + call = Runtime::make_call((expr_is_empty + ? Runtime::IFACEE2E2 + : Runtime::IFACEI2E2), + loc, 1, this->expr_); else - call = this->lower_to_type(expr_is_empty ? "ifaceE2I2" : "ifaceI2I2"); + call = this->lower_to_type(expr_is_empty + ? Runtime::IFACEE2I2 + : Runtime::IFACEI2I2); } else if (this->type_->points_to() != NULL) - call = this->lower_to_type(expr_is_empty ? "ifaceE2T2P" : "ifaceI2T2P"); + call = this->lower_to_type(expr_is_empty + ? Runtime::IFACEE2T2P + : Runtime::IFACEI2T2P); else { - this->lower_to_object_type(b, expr_is_empty ? "ifaceE2T2" : "ifaceI2T2"); + this->lower_to_object_type(b, + (expr_is_empty + ? Runtime::IFACEE2T2 + : Runtime::IFACEI2T2)); call = NULL; } if (call != NULL) { Expression* res = Expression::make_call_result(call, 0); + res = Expression::make_unsafe_cast(this->type_, res, loc); Statement* s = Statement::make_assignment(this->val_, res, loc); b->add_statement(s); @@ -1405,74 +1355,23 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*, return Statement::make_block_statement(b, loc); } -// Lower a conversion to an empty interface type. - -Call_expression* -Tuple_type_guard_assignment_statement::lower_to_empty_interface( - const char *fnname) -{ - source_location loc = this->location(); - - // func FNNAME(interface) (empty, bool) - source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc)); - Typed_identifier_list* ret_types = new Typed_identifier_list(); - ret_types->push_back(Typed_identifier("ret", this->type_, bloc)); - ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc)); - Function_type* fntype = Type::make_function_type(NULL, param_types, - ret_types, bloc); - Named_object* fn = - Named_object::make_function_declaration(fnname, NULL, fntype, bloc); - std::string asm_name = "runtime."; - asm_name += fnname; - fn->func_declaration_value()->set_asm_name(asm_name); - - // val, ok = FNNAME(expr) - Expression* func = Expression::make_func_reference(fn, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(this->expr_); - return Expression::make_call(func, params, false, loc); -} - // Lower a conversion to a non-empty interface type or a pointer type. Call_expression* -Tuple_type_guard_assignment_statement::lower_to_type(const char* fnname) +Tuple_type_guard_assignment_statement::lower_to_type(Runtime::Function code) { source_location loc = this->location(); - - // func FNNAME(*descriptor, interface) (interface, bool) - source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("inter", - Type::make_type_descriptor_ptr_type(), - bloc)); - param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc)); - Typed_identifier_list* ret_types = new Typed_identifier_list(); - ret_types->push_back(Typed_identifier("ret", this->type_, bloc)); - ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc)); - Function_type* fntype = Type::make_function_type(NULL, param_types, - ret_types, bloc); - Named_object* fn = - Named_object::make_function_declaration(fnname, NULL, fntype, bloc); - std::string asm_name = "runtime."; - asm_name += fnname; - fn->func_declaration_value()->set_asm_name(asm_name); - - // val, ok = FNNAME(type_descriptor, expr) - Expression* func = Expression::make_func_reference(fn, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(Expression::make_type_descriptor(this->type_, loc)); - params->push_back(this->expr_); - return Expression::make_call(func, params, false, loc); + return Runtime::make_call(code, loc, 2, + Expression::make_type_descriptor(this->type_, loc), + this->expr_); } // Lower a conversion to a non-interface non-pointer type. void -Tuple_type_guard_assignment_statement::lower_to_object_type(Block* b, - const char *fnname) +Tuple_type_guard_assignment_statement::lower_to_object_type( + Block* b, + Runtime::Function code) { source_location loc = this->location(); @@ -1481,33 +1380,11 @@ Tuple_type_guard_assignment_statement::lower_to_object_type(Block* b, NULL, loc); b->add_statement(val_temp); - // func FNNAME(*descriptor, interface, *T) bool - source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("inter", - Type::make_type_descriptor_ptr_type(), - bloc)); - param_types->push_back(Typed_identifier("i", this->expr_->type(), bloc)); - Type* ptype = Type::make_pointer_type(this->type_); - param_types->push_back(Typed_identifier("v", ptype, bloc)); - Typed_identifier_list* ret_types = new Typed_identifier_list(); - ret_types->push_back(Typed_identifier("ok", Type::lookup_bool_type(), bloc)); - Function_type* fntype = Type::make_function_type(NULL, param_types, - ret_types, bloc); - Named_object* fn = - Named_object::make_function_declaration(fnname, NULL, fntype, bloc); - std::string asm_name = "runtime."; - asm_name += fnname; - fn->func_declaration_value()->set_asm_name(asm_name); - - // ok = FNNAME(type_descriptor, expr, &val_temp) - Expression* func = Expression::make_func_reference(fn, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(Expression::make_type_descriptor(this->type_, loc)); - params->push_back(this->expr_); + // ok = CODE(type_descriptor, expr, &val_temp) + Expression* p1 = Expression::make_type_descriptor(this->type_, loc); Expression* ref = Expression::make_temporary_reference(val_temp, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); - Expression* call = Expression::make_call(func, params, false, loc); + Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); + Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3); Statement* s = Statement::make_assignment(this->ok_, call, loc); b->add_statement(s); @@ -2146,34 +2023,8 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name, { retaddr_label = gogo->add_label_reference("retaddr"); Expression* arg = Expression::make_label_addr(retaddr_label, location); - Expression_list* args = new Expression_list(); - args->push_back(arg); - - static Named_object* set_defer_retaddr; - if (set_defer_retaddr == NULL) - { - const source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = new Typed_identifier_list(); - Type *voidptr_type = Type::make_pointer_type(Type::make_void_type()); - param_types->push_back(Typed_identifier("r", voidptr_type, bloc)); - - Typed_identifier_list* result_types = new Typed_identifier_list(); - result_types->push_back(Typed_identifier("", - Type::lookup_bool_type(), - bloc)); - - Function_type* t = Type::make_function_type(NULL, param_types, - result_types, bloc); - set_defer_retaddr = - Named_object::make_function_declaration("__go_set_defer_retaddr", - NULL, t, bloc); - const char* n = "__go_set_defer_retaddr"; - set_defer_retaddr->func_declaration_value()->set_asm_name(n); - } - - Expression* fn = Expression::make_func_reference(set_defer_retaddr, - NULL, location); - Expression* call = Expression::make_call(fn, args, false, location); + Expression* call = Runtime::make_call(Runtime::SET_DEFER_RETADDR, + location, 1, arg); // This is a hack to prevent the middle-end from deleting the // label. @@ -3610,92 +3461,24 @@ Type_case_clauses::Type_case_clause::lower(Block* b, { Type* type = this->type_; + Expression* ref = Expression::make_temporary_reference(descriptor_temp, + loc); + Expression* cond; // The language permits case nil, which is of course a constant // rather than a type. It will appear here as an invalid // forwarding type. if (type->is_nil_constant_as_type()) - { - Expression* ref = - Expression::make_temporary_reference(descriptor_temp, loc); - cond = Expression::make_binary(OPERATOR_EQEQ, ref, - Expression::make_nil(loc), - loc); - } + cond = Expression::make_binary(OPERATOR_EQEQ, ref, + Expression::make_nil(loc), + loc); else - { - Expression* func; - if (type->interface_type() == NULL) - { - // func ifacetypeeq(*descriptor, *descriptor) bool - static Named_object* ifacetypeeq; - if (ifacetypeeq == NULL) - { - const source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = - new Typed_identifier_list(); - Type* descriptor_type = Type::make_type_descriptor_ptr_type(); - param_types->push_back(Typed_identifier("a", descriptor_type, - bloc)); - param_types->push_back(Typed_identifier("b", descriptor_type, - bloc)); - Typed_identifier_list* ret_types = - new Typed_identifier_list(); - Type* bool_type = Type::lookup_bool_type(); - ret_types->push_back(Typed_identifier("", bool_type, bloc)); - Function_type* fntype = Type::make_function_type(NULL, - param_types, - ret_types, - bloc); - ifacetypeeq = - Named_object::make_function_declaration("ifacetypeeq", NULL, - fntype, bloc); - const char* n = "runtime.ifacetypeeq"; - ifacetypeeq->func_declaration_value()->set_asm_name(n); - } - - // ifacetypeeq(descriptor_temp, DESCRIPTOR) - func = Expression::make_func_reference(ifacetypeeq, NULL, loc); - } - else - { - // func ifaceI2Tp(*descriptor, *descriptor) bool - static Named_object* ifaceI2Tp; - if (ifaceI2Tp == NULL) - { - const source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = - new Typed_identifier_list(); - Type* descriptor_type = Type::make_type_descriptor_ptr_type(); - param_types->push_back(Typed_identifier("a", descriptor_type, - bloc)); - param_types->push_back(Typed_identifier("b", descriptor_type, - bloc)); - Typed_identifier_list* ret_types = - new Typed_identifier_list(); - Type* bool_type = Type::lookup_bool_type(); - ret_types->push_back(Typed_identifier("", bool_type, bloc)); - Function_type* fntype = Type::make_function_type(NULL, - param_types, - ret_types, - bloc); - ifaceI2Tp = - Named_object::make_function_declaration("ifaceI2Tp", NULL, - fntype, bloc); - const char* n = "runtime.ifaceI2Tp"; - ifaceI2Tp->func_declaration_value()->set_asm_name(n); - } - - // ifaceI2Tp(descriptor_temp, DESCRIPTOR) - func = Expression::make_func_reference(ifaceI2Tp, NULL, loc); - } - Expression_list* params = new Expression_list(); - params->push_back(Expression::make_type_descriptor(type, loc)); - Expression* ref = - Expression::make_temporary_reference(descriptor_temp, loc); - params->push_back(ref); - cond = Expression::make_call(func, params, false, loc); - } + cond = Runtime::make_call((type->interface_type() == NULL + ? Runtime::IFACETYPEEQ + : Runtime::IFACEI2TP), + loc, 2, + Expression::make_type_descriptor(type, loc), + ref); Unnamed_label* dest; if (!this->is_fallthrough_) @@ -3891,35 +3674,18 @@ Type_switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing) } else { - const source_location bloc = BUILTINS_LOCATION; - - // func {efacetype,ifacetype}(*interface) *descriptor + // descriptor_temp = ifacetype(val_temp) // FIXME: This should be inlined. - Typed_identifier_list* param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("i", val_type, bloc)); - Typed_identifier_list* ret_types = new Typed_identifier_list(); - ret_types->push_back(Typed_identifier("", descriptor_type, bloc)); - Function_type* fntype = Type::make_function_type(NULL, param_types, - ret_types, bloc); bool is_empty = val_type->interface_type()->is_empty(); - const char* fnname = is_empty ? "efacetype" : "ifacetype"; - Named_object* fn = - Named_object::make_function_declaration(fnname, NULL, fntype, bloc); - const char* asm_name = (is_empty - ? "runtime.efacetype" - : "runtime.ifacetype"); - fn->func_declaration_value()->set_asm_name(asm_name); - - // descriptor_temp = ifacetype(val_temp) - Expression* func = Expression::make_func_reference(fn, NULL, loc); - Expression_list* params = new Expression_list(); Expression* ref; if (this->var_ == NULL) ref = this->expr_; else ref = Expression::make_var_reference(this->var_, loc); - params->push_back(ref); - Expression* call = Expression::make_call(func, params, false, loc); + Expression* call = Runtime::make_call((is_empty + ? Runtime::EFACETYPE + : Runtime::IFACETYPE), + loc, 1, ref); Expression* lhs = Expression::make_temporary_reference(descriptor_temp, loc); Statement* s = Statement::make_assignment(lhs, call, loc); @@ -4935,7 +4701,7 @@ For_range_statement::lower_range_array(Gogo* gogo, // Lower a for range over a string. void -For_range_statement::lower_range_string(Gogo* gogo, +For_range_statement::lower_range_string(Gogo*, Block* enclosing, Block* body_block, Named_object* range_object, @@ -4996,66 +4762,12 @@ For_range_statement::lower_range_string(Gogo* gogo, Block* iter_init = new Block(body_block, loc); - Named_object* no; - if (value_temp == NULL) - { - static Named_object* stringiter; - if (stringiter == NULL) - { - source_location bloc = BUILTINS_LOCATION; - Type* int_type = gogo->lookup_global("int")->type_value(); - - Typed_identifier_list* params = new Typed_identifier_list(); - params->push_back(Typed_identifier("s", Type::make_string_type(), - bloc)); - params->push_back(Typed_identifier("k", int_type, bloc)); - - Typed_identifier_list* results = new Typed_identifier_list(); - results->push_back(Typed_identifier("", int_type, bloc)); - - Function_type* fntype = Type::make_function_type(NULL, params, - results, bloc); - stringiter = Named_object::make_function_declaration("stringiter", - NULL, fntype, - bloc); - const char* n = "runtime.stringiter"; - stringiter->func_declaration_value()->set_asm_name(n); - } - no = stringiter; - } - else - { - static Named_object* stringiter2; - if (stringiter2 == NULL) - { - source_location bloc = BUILTINS_LOCATION; - Type* int_type = gogo->lookup_global("int")->type_value(); - - Typed_identifier_list* params = new Typed_identifier_list(); - params->push_back(Typed_identifier("s", Type::make_string_type(), - bloc)); - params->push_back(Typed_identifier("k", int_type, bloc)); - - Typed_identifier_list* results = new Typed_identifier_list(); - results->push_back(Typed_identifier("", int_type, bloc)); - results->push_back(Typed_identifier("", int_type, bloc)); - - Function_type* fntype = Type::make_function_type(NULL, params, - results, bloc); - stringiter2 = Named_object::make_function_declaration("stringiter", - NULL, fntype, - bloc); - const char* n = "runtime.stringiter2"; - stringiter2->func_declaration_value()->set_asm_name(n); - } - no = stringiter2; - } - - Expression* func = Expression::make_func_reference(no, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(this->make_range_ref(range_object, range_temp, loc)); - params->push_back(Expression::make_temporary_reference(index_temp, loc)); - Call_expression* call = Expression::make_call(func, params, false, loc); + Expression* p1 = this->make_range_ref(range_object, range_temp, loc); + Expression* p2 = Expression::make_temporary_reference(index_temp, loc); + Call_expression* call = Runtime::make_call((value_temp == NULL + ? Runtime::STRINGITER + : Runtime::STRINGITER2), + loc, 2, p1, p2); if (value_temp == NULL) { @@ -5107,7 +4819,7 @@ For_range_statement::lower_range_string(Gogo* gogo, // Lower a for range over a map. void -For_range_statement::lower_range_map(Gogo* gogo, +For_range_statement::lower_range_map(Gogo*, Block* enclosing, Block* body_block, Named_object* range_object, @@ -5140,41 +4852,15 @@ For_range_statement::lower_range_map(Gogo* gogo, Block* init = new Block(enclosing, loc); - const unsigned long map_iteration_size = 4; - - mpz_t ival; - mpz_init_set_ui(ival, map_iteration_size); - Expression* iexpr = Expression::make_integer(&ival, NULL, loc); - mpz_clear(ival); - - Type* byte_type = gogo->lookup_global("byte")->type_value(); - Type* ptr_type = Type::make_pointer_type(byte_type); - - Type* map_iteration_type = Type::make_array_type(ptr_type, iexpr); - Type* map_iteration_ptr = Type::make_pointer_type(map_iteration_type); - + Type* map_iteration_type = Runtime::map_iteration_type(); Temporary_statement* hiter = Statement::make_temporary(map_iteration_type, NULL, loc); init->add_statement(hiter); - source_location bloc = BUILTINS_LOCATION; - Typed_identifier_list* param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("map", this->range_->type(), bloc)); - param_types->push_back(Typed_identifier("it", map_iteration_ptr, bloc)); - Function_type* fntype = Type::make_function_type(NULL, param_types, NULL, - bloc); - - Named_object* mapiterinit = - Named_object::make_function_declaration("mapiterinit", NULL, fntype, bloc); - const char* n = "runtime.mapiterinit"; - mapiterinit->func_declaration_value()->set_asm_name(n); - - Expression* func = Expression::make_func_reference(mapiterinit, NULL, loc); - Expression_list* params = new Expression_list(); - params->push_back(this->make_range_ref(range_object, range_temp, loc)); + Expression* p1 = this->make_range_ref(range_object, range_temp, loc); Expression* ref = Expression::make_temporary_reference(hiter, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); - Expression* call = Expression::make_call(func, params, false, loc); + Expression* p2 = Expression::make_unary(OPERATOR_AND, ref, loc); + Expression* call = Runtime::make_call(Runtime::MAPITERINIT, loc, 2, p1, p2); init->add_statement(Statement::make_statement(call)); *pinit = init; @@ -5204,34 +4890,18 @@ For_range_statement::lower_range_map(Gogo* gogo, Block* iter_init = new Block(body_block, loc); - param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("hiter", map_iteration_ptr, bloc)); - Type* pkey_type = Type::make_pointer_type(index_temp->type()); - param_types->push_back(Typed_identifier("key", pkey_type, bloc)); - if (value_temp != NULL) - { - Type* pval_type = Type::make_pointer_type(value_temp->type()); - param_types->push_back(Typed_identifier("val", pval_type, bloc)); - } - fntype = Type::make_function_type(NULL, param_types, NULL, bloc); - n = value_temp == NULL ? "mapiter1" : "mapiter2"; - Named_object* mapiter = Named_object::make_function_declaration(n, NULL, - fntype, bloc); - n = value_temp == NULL ? "runtime.mapiter1" : "runtime.mapiter2"; - mapiter->func_declaration_value()->set_asm_name(n); - - func = Expression::make_func_reference(mapiter, NULL, loc); - params = new Expression_list(); ref = Expression::make_temporary_reference(hiter, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); + p1 = Expression::make_unary(OPERATOR_AND, ref, loc); ref = Expression::make_temporary_reference(index_temp, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); - if (value_temp != NULL) + p2 = Expression::make_unary(OPERATOR_AND, ref, loc); + if (value_temp == NULL) + call = Runtime::make_call(Runtime::MAPITER1, loc, 2, p1, p2); + else { ref = Expression::make_temporary_reference(value_temp, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); + Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); + call = Runtime::make_call(Runtime::MAPITER2, loc, 3, p1, p2, p3); } - call = Expression::make_call(func, params, false, loc); iter_init->add_statement(Statement::make_statement(call)); *piter_init = iter_init; @@ -5241,24 +4911,9 @@ For_range_statement::lower_range_map(Gogo* gogo, Block* post = new Block(enclosing, loc); - static Named_object* mapiternext; - if (mapiternext == NULL) - { - param_types = new Typed_identifier_list(); - param_types->push_back(Typed_identifier("it", map_iteration_ptr, bloc)); - fntype = Type::make_function_type(NULL, param_types, NULL, bloc); - mapiternext = Named_object::make_function_declaration("mapiternext", - NULL, fntype, - bloc); - const char* n = "runtime.mapiternext"; - mapiternext->func_declaration_value()->set_asm_name(n); - } - - func = Expression::make_func_reference(mapiternext, NULL, loc); - params = new Expression_list(); ref = Expression::make_temporary_reference(hiter, loc); - params->push_back(Expression::make_unary(OPERATOR_AND, ref, loc)); - call = Expression::make_call(func, params, false, loc); + p1 = Expression::make_unary(OPERATOR_AND, ref, loc); + call = Runtime::make_call(Runtime::MAPITERNEXT, loc, 1, p1); post->add_statement(Statement::make_statement(call)); *ppost = post; |