From 2c809f8f2584460a5207662cc8e064486cb0ec30 Mon Sep 17 00:00:00 2001 From: ian Date: Mon, 14 Apr 2014 22:43:47 +0000 Subject: [PATCH] Sync to current external repository. user: Ian Lance Taylor date: Thu Apr 10 09:25:24 2014 -0700 files: go/expressions.cc description: compiler: add checks for constant overflow Prevent extremely large constants from eating all of memory. user: Chris Manghane date: Mon Apr 07 16:57:09 2014 -0700 files: go/gogo-tree.cc go/gogo.cc go/gogo.h go/statements.cc description: compiler: Use backend interface for variable initialization. user: Chris Manghane date: Thu Apr 03 19:56:05 2014 -0700 files: go/backend.h go/gogo-tree.cc go/gogo.cc go/gogo.h description: compiler: Use backend interface to build function code. changeset: 1269:6e30875d539e user: Chris Manghane date: Wed Apr 02 13:16:00 2014 -0700 files: go/backend.h go/gogo-tree.cc go/gogo.cc go/gogo.h description: compiler: Use backend interface for building function defer wrappers. user: Chris Manghane date: Mon Mar 31 12:42:49 2014 -0700 files: go/expressions.cc go/gogo-tree.cc go/gogo.cc go/gogo.h description: compiler: Use backend interface for memory allocation. user: Chris Manghane date: Thu Mar 27 14:22:49 2014 -0700 files: go/backend.h go/expressions.cc go/expressions.h description: compiler: Use backend interface for fixed array construction. user: Chris Manghane date: Mon Mar 17 21:25:04 2014 -0700 files: go/expressions.cc description: compiler: Check for loops in self-referential array types. Fixes issue 7525. user: Chris Manghane date: Mon Mar 17 14:31:59 2014 -0700 files: go/gogo.cc go/parse.cc description: compiler: Don't declare blank labels. Fixes issue 7539. user: Chris Manghane date: Mon Mar 17 13:12:32 2014 -0700 files: go/backend.h go/expressions.cc go/expressions.h go/runtime.def description: compiler: Use backend interface for call expressions. user: Chris Manghane date: Wed Mar 12 13:34:27 2014 -0700 files: go/expressions.cc go/expressions.h go/gogo-tree.cc go/statements.cc description: compiler: Use backend interface map construction. user: Chris Manghane date: Tue Mar 11 12:53:06 2014 -0700 files: go/backend.h go/expressions.cc go/gogo-tree.cc go/gogo.h description: compiler: Use backend interface for string expressions. user: Chris Manghane date: Sat Mar 08 15:56:59 2014 -0800 files: go/backend.h go/expressions.cc go/expressions.h description: compiler: Use backend interface for array and string indexing. user: Chris Manghane date: Fri Mar 07 16:02:18 2014 -0800 files: go/expressions.cc description: compiler: Use backend interface for constant expressions. user: Chris Manghane date: Thu Mar 06 16:00:18 2014 -0800 files: go/expressions.cc description: compiler: Use backend interface for struct construction. user: Chris Manghane date: Wed Mar 05 13:09:37 2014 -0800 files: go/expressions.cc description: compiler: Use backend interface for type conversions. user: Chris Manghane date: Tue Mar 04 07:03:47 2014 -0800 files: go/expressions.cc go/expressions.h go/gogo-tree.cc go/gogo.h go/runtime.def libgo/runtime/chan.c description: compiler: Use backend interface for channel receive. user: Chris Manghane date: Mon Mar 03 15:18:57 2014 -0800 files: go/backend.h go/expressions.cc go/runtime.def description: compiler: Use backend interface for builtin calls. user: Chris Manghane date: Mon Mar 03 07:44:35 2014 -0800 files: go/expressions.cc go/expressions.h go/types.cc go/types.h description: compiler: Use backend interface for string info. user: Chris Manghane date: Fri Feb 28 10:45:55 2014 -0800 files: go/expressions.cc go/expressions.h go/gogo-tree.cc go/statements.cc description: compiler: Use backend interface for map indexing. user: Chris Manghane date: Wed Feb 26 14:13:10 2014 -0800 files: go/expressions.cc go/expressions.h description: compiler: Use backend interface for slice value expressions. user: Chris Manghane date: Wed Feb 26 13:12:19 2014 -0800 files: go/backend.h go/expressions.cc go/expressions.h go/gogo-tree.cc go/runtime.def go/statements.cc description: compiler: Use backend interface for interface values. user: Chris Manghane date: Mon Feb 24 12:30:13 2014 -0800 files: go/expressions.cc go/expressions.h go/parse.cc go/statements.cc description: compiler: Change Heap_composite_expression to Heap_expression. user: Chris Manghane date: Thu Feb 20 19:47:06 2014 -0800 files: go/expressions.cc go/expressions.h go/gogo-tree.cc go/gogo.cc go/gogo.h go/types.cc go/types.h description: compiler: Use backend interface for interface method table expressions. user: Chris Manghane date: Mon Feb 03 14:36:20 2014 -0800 files: go/expressions.cc go/expressions.h description: compiler: Add compound expressions to the frontend. * go-gcc.cc: Include "convert.h". (Gcc_backend::string_constant_expression): New function. (Gcc_backend::real_part_expression): Likewise. (Gcc_backend::imag_part_expression): Likewise. (Gcc_backend::complex_expression): Likewise. (Gcc_backend::constructor_expression): Likewise. (Gcc_backend::array_constructor_expression): Likewise. (Gcc_backend::pointer_offset_expression): Likewise. (Gcc_backend::array_index_expression): Likewise. (Gcc_backend::call_expression): Likewise. (Gcc_backend::exception_handler_statement): Likewise. (Gcc_backend::function_defer_statement): Likewise. (Gcc_backend::function_set_parameters): Likewise. (Gcc_backend::function_set_body): Likewise. (Gcc_backend::convert_expression): Handle various type conversions. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@209393 138bc75d-0d04-0410-961f-82ee72b054a4 --- gcc/go/ChangeLog | 19 + gcc/go/go-gcc.cc | 447 ++++- gcc/go/gofrontend/backend.h | 77 + gcc/go/gofrontend/expressions.cc | 3664 +++++++++++++++++++------------------- gcc/go/gofrontend/expressions.h | 139 +- gcc/go/gofrontend/gogo-tree.cc | 924 +--------- gcc/go/gofrontend/gogo.cc | 390 +++- gcc/go/gofrontend/gogo.h | 66 +- gcc/go/gofrontend/parse.cc | 7 +- gcc/go/gofrontend/runtime.def | 16 +- gcc/go/gofrontend/statements.cc | 19 +- gcc/go/gofrontend/types.cc | 69 +- gcc/go/gofrontend/types.h | 26 +- libgo/runtime/chan.c | 27 +- 14 files changed, 2997 insertions(+), 2893 deletions(-) diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 689578e2064..0d153fa02e6 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,22 @@ +2014-04-14 Chris Manghane + + * go-gcc.cc: Include "convert.h". + (Gcc_backend::string_constant_expression): New function. + (Gcc_backend::real_part_expression): Likewise. + (Gcc_backend::imag_part_expression): Likewise. + (Gcc_backend::complex_expression): Likewise. + (Gcc_backend::constructor_expression): Likewise. + (Gcc_backend::array_constructor_expression): Likewise. + (Gcc_backend::pointer_offset_expression): Likewise. + (Gcc_backend::array_index_expression): Likewise. + (Gcc_backend::call_expression): Likewise. + (Gcc_backend::exception_handler_statement): Likewise. + (Gcc_backend::function_defer_statement): Likewise. + (Gcc_backend::function_set_parameters): Likewise. + (Gcc_backend::function_set_body): Likewise. + (Gcc_backend::convert_expression): Handle various type + conversions. + 2014-03-03 Ian Lance Taylor * go-gcc.cc (Gcc_backend::immutable_struct): If IS_COMMON, set diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 6aec2877d7b..3abefaee9e6 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -29,6 +29,7 @@ #include "stor-layout.h" #include "varasm.h" #include "tree-iterator.h" +#include "convert.h" #include "basic-block.h" #include "gimple-expr.h" #include "toplev.h" @@ -235,6 +236,18 @@ class Gcc_backend : public Backend complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag); Bexpression* + string_constant_expression(const std::string& val); + + Bexpression* + real_part_expression(Bexpression* bcomplex, Location); + + Bexpression* + imag_part_expression(Bexpression* bcomplex, Location); + + Bexpression* + complex_expression(Bexpression* breal, Bexpression* bimag, Location); + + Bexpression* convert_expression(Btype* type, Bexpression* expr, Location); Bexpression* @@ -259,6 +272,23 @@ class Gcc_backend : public Backend Bexpression* binary_expression(Operator, Bexpression*, Bexpression*, Location); + Bexpression* + constructor_expression(Btype*, const std::vector&, Location); + + Bexpression* + array_constructor_expression(Btype*, const std::vector&, + const std::vector&, Location); + + Bexpression* + pointer_offset_expression(Bexpression* base, Bexpression* offset, Location); + + Bexpression* + array_index_expression(Bexpression* array, Bexpression* index, Location); + + Bexpression* + call_expression(Bexpression* fn, const std::vector& args, + Location); + // Statements. Bstatement* @@ -294,6 +324,10 @@ class Gcc_backend : public Backend Bstatement* statement_list(const std::vector&); + Bstatement* + exception_handler_statement(Bstatement* bstat, Bstatement* except_stmt, + Bstatement* finally_stmt, Location); + // Blocks. Bblock* @@ -372,6 +406,16 @@ class Gcc_backend : public Backend bool is_visible, bool is_declaration, bool is_inlinable, bool disable_split_stack, bool in_unique_section, Location); + Bstatement* + function_defer_statement(Bfunction* function, Bexpression* undefer, + Bexpression* defer, Location); + + bool + function_set_parameters(Bfunction* function, const std::vector&); + + bool + function_set_body(Bfunction* function, Bstatement* code_stmt); + private: // Make a Bexpression from a tree. Bexpression* @@ -974,18 +1018,108 @@ Gcc_backend::complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag) return tree_to_expr(ret); } +// Make a constant string expression. + +Bexpression* +Gcc_backend::string_constant_expression(const std::string& val) +{ + tree index_type = build_index_type(size_int(val.length())); + tree const_char_type = build_qualified_type(unsigned_char_type_node, + TYPE_QUAL_CONST); + tree string_type = build_array_type(const_char_type, index_type); + string_type = build_variant_type_copy(string_type); + TYPE_STRING_FLAG(string_type) = 1; + tree string_val = build_string(val.length(), val.data()); + TREE_TYPE(string_val) = string_type; + + return this->make_expression(string_val); +} + +// Return the real part of a complex expression. + +Bexpression* +Gcc_backend::real_part_expression(Bexpression* bcomplex, Location location) +{ + tree complex_tree = bcomplex->get_tree(); + if (complex_tree == error_mark_node) + return this->error_expression(); + gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(complex_tree))); + tree ret = fold_build1_loc(location.gcc_location(), REALPART_EXPR, + TREE_TYPE(TREE_TYPE(complex_tree)), + complex_tree); + return this->make_expression(ret); +} + +// Return the imaginary part of a complex expression. + +Bexpression* +Gcc_backend::imag_part_expression(Bexpression* bcomplex, Location location) +{ + tree complex_tree = bcomplex->get_tree(); + if (complex_tree == error_mark_node) + return this->error_expression(); + gcc_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(complex_tree))); + tree ret = fold_build1_loc(location.gcc_location(), IMAGPART_EXPR, + TREE_TYPE(TREE_TYPE(complex_tree)), + complex_tree); + return this->make_expression(ret); +} + +// Make a complex expression given its real and imaginary parts. + +Bexpression* +Gcc_backend::complex_expression(Bexpression* breal, Bexpression* bimag, + Location location) +{ + tree real_tree = breal->get_tree(); + tree imag_tree = bimag->get_tree(); + if (real_tree == error_mark_node || imag_tree == error_mark_node) + return this->error_expression(); + gcc_assert(TYPE_MAIN_VARIANT(TREE_TYPE(real_tree)) + == TYPE_MAIN_VARIANT(TREE_TYPE(imag_tree))); + gcc_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(real_tree))); + tree ret = fold_build2_loc(location.gcc_location(), COMPLEX_EXPR, + build_complex_type(TREE_TYPE(real_tree)), + real_tree, imag_tree); + return this->make_expression(ret); +} + // An expression that converts an expression to a different type. Bexpression* -Gcc_backend::convert_expression(Btype* type, Bexpression* expr, Location) +Gcc_backend::convert_expression(Btype* type, Bexpression* expr, + Location location) { tree type_tree = type->get_tree(); tree expr_tree = expr->get_tree(); - if (type_tree == error_mark_node || expr_tree == error_mark_node) + if (type_tree == error_mark_node + || expr_tree == error_mark_node + || TREE_TYPE(expr_tree) == error_mark_node) return this->error_expression(); - tree ret = fold_convert(type_tree, expr_tree); - return tree_to_expr(ret); + tree ret; + if (this->type_size(type) == 0) + { + // Do not convert zero-sized types. + ret = expr_tree; + } + else if (TREE_CODE(type_tree) == INTEGER_TYPE) + ret = fold(convert_to_integer(type_tree, expr_tree)); + else if (TREE_CODE(type_tree) == REAL_TYPE) + ret = fold(convert_to_real(type_tree, expr_tree)); + else if (TREE_CODE(type_tree) == COMPLEX_TYPE) + ret = fold(convert_to_complex(type_tree, expr_tree)); + else if (TREE_CODE(type_tree) == POINTER_TYPE + && TREE_CODE(TREE_TYPE(expr_tree)) == INTEGER_TYPE) + ret = fold(convert_to_pointer(type_tree, expr_tree)); + else if (TREE_CODE(type_tree) == RECORD_TYPE + || TREE_CODE(type_tree) == ARRAY_TYPE) + ret = fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, + type_tree, expr_tree); + else + ret = fold_convert_loc(location.gcc_location(), type_tree, expr_tree); + + return this->make_expression(ret); } // Get the address of a function. @@ -1243,6 +1377,205 @@ Gcc_backend::binary_expression(Operator op, Bexpression* left, return this->make_expression(ret); } +// Return an expression that constructs BTYPE with VALS. + +Bexpression* +Gcc_backend::constructor_expression(Btype* btype, + const std::vector& vals, + Location location) +{ + tree type_tree = btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_expression(); + + vec *init; + vec_alloc(init, vals.size()); + + bool is_constant = true; + tree field = TYPE_FIELDS(type_tree); + for (std::vector::const_iterator p = vals.begin(); + p != vals.end(); + ++p, field = DECL_CHAIN(field)) + { + gcc_assert(field != NULL_TREE); + tree val = (*p)->get_tree(); + if (TREE_TYPE(field) == error_mark_node + || val == error_mark_node + || TREE_TYPE(val) == error_mark_node) + return this->error_expression(); + + constructor_elt empty = {NULL, NULL}; + constructor_elt* elt = init->quick_push(empty); + elt->index = field; + elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), + val); + if (!TREE_CONSTANT(elt->value)) + is_constant = false; + } + gcc_assert(field == NULL_TREE); + tree ret = build_constructor(type_tree, init); + if (is_constant) + TREE_CONSTANT(ret) = 1; + + return this->make_expression(ret); +} + +Bexpression* +Gcc_backend::array_constructor_expression( + Btype* array_btype, const std::vector& indexes, + const std::vector& vals, Location) +{ + tree type_tree = array_btype->get_tree(); + if (type_tree == error_mark_node) + return this->error_expression(); + + gcc_assert(indexes.size() == vals.size()); + vec *init; + vec_alloc(init, vals.size()); + + bool is_constant = true; + for (size_t i = 0; i < vals.size(); ++i) + { + tree index = size_int(indexes[i]); + tree val = (vals[i])->get_tree(); + + if (index == error_mark_node + || val == error_mark_node) + return this->error_expression(); + + if (!TREE_CONSTANT(val)) + is_constant = false; + + constructor_elt empty = {NULL, NULL}; + constructor_elt* elt = init->quick_push(empty); + elt->index = index; + elt->value = val; + } + + tree ret = build_constructor(type_tree, init); + if (is_constant) + TREE_CONSTANT(ret) = 1; + return this->make_expression(ret); +} + +// Return an expression for the address of BASE[INDEX]. + +Bexpression* +Gcc_backend::pointer_offset_expression(Bexpression* base, Bexpression* index, + Location location) +{ + tree base_tree = base->get_tree(); + tree index_tree = index->get_tree(); + tree element_type_tree = TREE_TYPE(TREE_TYPE(base_tree)); + if (base_tree == error_mark_node + || TREE_TYPE(base_tree) == error_mark_node + || index_tree == error_mark_node + || element_type_tree == error_mark_node) + return this->error_expression(); + + tree element_size = TYPE_SIZE_UNIT(element_type_tree); + index_tree = fold_convert_loc(location.gcc_location(), sizetype, index_tree); + tree offset = fold_build2_loc(location.gcc_location(), MULT_EXPR, sizetype, + index_tree, element_size); + tree ptr = fold_build2_loc(location.gcc_location(), POINTER_PLUS_EXPR, + TREE_TYPE(base_tree), base_tree, offset); + return this->make_expression(ptr); +} + +// Return an expression representing ARRAY[INDEX] + +Bexpression* +Gcc_backend::array_index_expression(Bexpression* array, Bexpression* index, + Location location) +{ + tree array_tree = array->get_tree(); + tree index_tree = index->get_tree(); + if (array_tree == error_mark_node + || TREE_TYPE(array_tree) == error_mark_node + || index_tree == error_mark_node) + return this->error_expression(); + + tree ret = build4_loc(location.gcc_location(), ARRAY_REF, + TREE_TYPE(TREE_TYPE(array_tree)), array_tree, + index_tree, NULL_TREE, NULL_TREE); + return this->make_expression(ret); +} + +// Create an expression for a call to FN_EXPR with FN_ARGS. +Bexpression* +Gcc_backend::call_expression(Bexpression* fn_expr, + const std::vector& fn_args, + Location location) +{ + tree fn = fn_expr->get_tree(); + if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node) + return this->error_expression(); + + gcc_assert(FUNCTION_POINTER_TYPE_P(TREE_TYPE(fn))); + tree rettype = TREE_TYPE(TREE_TYPE(TREE_TYPE(fn))); + + size_t nargs = fn_args.size(); + tree* args = nargs == 0 ? NULL : new tree[nargs]; + for (size_t i = 0; i < nargs; ++i) + { + args[i] = fn_args.at(i)->get_tree(); + if (args[i] == error_mark_node) + return this->error_expression(); + } + + tree fndecl = fn; + if (TREE_CODE(fndecl) == ADDR_EXPR) + fndecl = TREE_OPERAND(fndecl, 0); + + // This is to support builtin math functions when using 80387 math. + tree excess_type = NULL_TREE; + if (optimize + && TREE_CODE(fndecl) == FUNCTION_DECL + && DECL_IS_BUILTIN(fndecl) + && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL + && nargs > 0 + && ((SCALAR_FLOAT_TYPE_P(rettype) + && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0]))) + || (COMPLEX_FLOAT_TYPE_P(rettype) + && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0]))))) + { + excess_type = excess_precision_type(TREE_TYPE(args[0])); + if (excess_type != NULL_TREE) + { + tree excess_fndecl = mathfn_built_in(excess_type, + DECL_FUNCTION_CODE(fndecl)); + if (excess_fndecl == NULL_TREE) + excess_type = NULL_TREE; + else + { + fn = build_fold_addr_expr_loc(location.gcc_location(), + excess_fndecl); + for (size_t i = 0; i < nargs; ++i) + { + if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i])) + || COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[i]))) + args[i] = ::convert(excess_type, args[i]); + } + } + } + } + + tree ret = + build_call_array_loc(location.gcc_location(), + excess_type != NULL_TREE ? excess_type : rettype, + fn, nargs, args); + + if (excess_type != NULL_TREE) + { + // Calling convert here can undo our excess precision change. + // That may or may not be a bug in convert_to_real. + ret = build1_loc(location.gcc_location(), NOP_EXPR, rettype, ret); + } + + delete[] args; + return this->make_expression(ret); +} + // An expression as a statement. Bstatement* @@ -1402,6 +1735,40 @@ Gcc_backend::return_statement(Bfunction* bfunction, return this->make_statement(ret); } +// Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if an +// error occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and if not +// NULL, it will always be executed. This is used for handling defers in Go +// functions. In C++, the resulting code is of this form: +// try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; } + +Bstatement* +Gcc_backend::exception_handler_statement(Bstatement* bstat, + Bstatement* except_stmt, + Bstatement* finally_stmt, + Location location) +{ + tree stat_tree = bstat->get_tree(); + tree except_tree = except_stmt == NULL ? NULL_TREE : except_stmt->get_tree(); + tree finally_tree = finally_stmt == NULL + ? NULL_TREE + : finally_stmt->get_tree(); + + if (stat_tree == error_mark_node + || except_tree == error_mark_node + || finally_tree == error_mark_node) + return this->error_statement(); + + if (except_tree != NULL_TREE) + stat_tree = build2_loc(location.gcc_location(), TRY_CATCH_EXPR, + void_type_node, stat_tree, + build2_loc(location.gcc_location(), CATCH_EXPR, + void_type_node, NULL, except_tree)); + if (finally_tree != NULL_TREE) + stat_tree = build2_loc(location.gcc_location(), TRY_FINALLY_EXPR, + void_type_node, stat_tree, finally_tree); + return this->make_statement(stat_tree); +} + // If. Bstatement* @@ -2070,6 +2437,78 @@ Gcc_backend::function(Btype* fntype, const std::string& name, return new Bfunction(decl); } +// Create a statement that runs all deferred calls for FUNCTION. This should +// be a statement that looks like this in C++: +// finish: +// try { UNDEFER; } catch { CHECK_DEFER; goto finish; } + +Bstatement* +Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer, + Bexpression* defer, Location location) +{ + tree undefer_tree = undefer->get_tree(); + tree defer_tree = defer->get_tree(); + + if (undefer_tree == error_mark_node + || defer_tree == error_mark_node) + return this->error_statement(); + + tree stmt_list = NULL; + Blabel* blabel = this->label(function, "", location); + Bstatement* label_def = this->label_definition_statement(blabel); + append_to_statement_list(label_def->get_tree(), &stmt_list); + + Bstatement* jump_stmt = this->goto_statement(blabel, location); + tree jump = jump_stmt->get_tree(); + tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer_tree, jump); + catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); + tree try_catch = + build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body); + append_to_statement_list(try_catch, &stmt_list); + + return this->make_statement(stmt_list); +} + +// Record PARAM_VARS as the variables to use for the parameters of FUNCTION. +// This will only be called for a function definition. + +bool +Gcc_backend::function_set_parameters(Bfunction* function, + const std::vector& param_vars) +{ + tree func_tree = function->get_tree(); + if (func_tree == error_mark_node) + return false; + + tree params = NULL_TREE; + tree *pp = ¶ms; + for (std::vector::const_iterator pv = param_vars.begin(); + pv != param_vars.end(); + ++pv) + { + *pp = (*pv)->get_tree(); + gcc_assert(*pp != error_mark_node); + pp = &DECL_CHAIN(*pp); + } + *pp = NULL_TREE; + DECL_ARGUMENTS(func_tree) = params; + return true; +} + +// Set the function body for FUNCTION using the code in CODE_BLOCK. + +bool +Gcc_backend::function_set_body(Bfunction* function, Bstatement* code_stmt) +{ + tree func_tree = function->get_tree(); + tree code = code_stmt->get_tree(); + + if (func_tree == error_mark_node || code == error_mark_node) + return false; + DECL_SAVED_TREE(func_tree) = code; + return true; +} + // The single backend. static Gcc_backend gcc_backend; diff --git a/gcc/go/gofrontend/backend.h b/gcc/go/gofrontend/backend.h index cbe5f22b6ad..fd657ecc989 100644 --- a/gcc/go/gofrontend/backend.h +++ b/gcc/go/gofrontend/backend.h @@ -269,6 +269,22 @@ class Backend virtual Bexpression* complex_constant_expression(Btype* btype, mpfr_t real, mpfr_t imag) = 0; + // Return an expression for the string value VAL. + virtual Bexpression* + string_constant_expression(const std::string& val) = 0; + + // Return an expression for the real part of BCOMPLEX. + virtual Bexpression* + real_part_expression(Bexpression* bcomplex, Location) = 0; + + // Return an expression for the imaginary part of BCOMPLEX. + virtual Bexpression* + imag_part_expression(Bexpression* bcomplex, Location) = 0; + + // Return an expression for the complex number (BREAL, BIMAG). + virtual Bexpression* + complex_expression(Bexpression* breal, Bexpression* bimag, Location) = 0; + // Return an expression that converts EXPR to TYPE. virtual Bexpression* convert_expression(Btype* type, Bexpression* expr, Location) = 0; @@ -312,6 +328,38 @@ class Backend binary_expression(Operator op, Bexpression* left, Bexpression* right, Location) = 0; + // Return an expression that constructs BTYPE with VALS. BTYPE must be the + // backend representation a of struct. VALS must be in the same order as the + // corresponding fields in BTYPE. + virtual Bexpression* + constructor_expression(Btype* btype, const std::vector& vals, + Location) = 0; + + // Return an expression that constructs an array of BTYPE with INDEXES and + // VALS. INDEXES and VALS must have the same amount of elements. Each index + // in INDEXES must be in the same order as the corresponding value in VALS. + virtual Bexpression* + array_constructor_expression(Btype* btype, + const std::vector& indexes, + const std::vector& vals, + Location) = 0; + + // Return an expression for the address of BASE[INDEX]. + // BASE has a pointer type. This is used for slice indexing. + virtual Bexpression* + pointer_offset_expression(Bexpression* base, Bexpression* index, + Location) = 0; + + // Return an expression for ARRAY[INDEX] as an l-value. ARRAY is a valid + // fixed-length array, not a slice. + virtual Bexpression* + array_index_expression(Bexpression* array, Bexpression* index, Location) = 0; + + // Create an expression for a call to FN with ARGS. + virtual Bexpression* + call_expression(Bexpression* fn, const std::vector& args, + Location) = 0; + // Statements. // Create an error statement. This is used for cases which should @@ -367,6 +415,15 @@ class Backend virtual Bstatement* statement_list(const std::vector&) = 0; + // Create a statement that attempts to execute BSTAT and calls EXCEPT_STMT if + // an exception occurs. EXCEPT_STMT may be NULL. FINALLY_STMT may be NULL and + // if not NULL, it will always be executed. This is used for handling defers + // in Go functions. In C++, the resulting code is of this form: + // try { BSTAT; } catch { EXCEPT_STMT; } finally { FINALLY_STMT; } + virtual Bstatement* + exception_handler_statement(Bstatement* bstat, Bstatement* except_stmt, + Bstatement* finally_stmt, Location) = 0; + // Blocks. // Create a block. The frontend will call this function when it @@ -570,6 +627,26 @@ class Backend function(Btype* fntype, const std::string& name, const std::string& asm_name, bool is_visible, bool is_declaration, bool is_inlinable, bool disable_split_stack, bool in_unique_section, Location) = 0; + + // Create a statement that runs all deferred calls for FUNCTION. This should + // be a statement that looks like this in C++: + // finish: + // try { UNDEFER; } catch { CHECK_DEFER; goto finish; } + virtual Bstatement* + function_defer_statement(Bfunction* function, Bexpression* undefer, + Bexpression* check_defer, Location) = 0; + + // Record PARAM_VARS as the variables to use for the parameters of FUNCTION. + // This will only be called for a function definition. Returns true on + // success, false on failure. + virtual bool + function_set_parameters(Bfunction* function, + const std::vector& param_vars) = 0; + + // Set the function body for FUNCTION using the code in CODE_STMT. Returns + // true on success, false on failure. + virtual bool + function_set_body(Bfunction* function, Bstatement* code_stmt) = 0; }; // The backend interface has to define this function. diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index f45b4a22709..bd2e3183bfe 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -140,128 +140,81 @@ Expression::determine_type_no_context() this->do_determine_type(&context); } -// Return a tree handling any conversions which must be done during +// Return an expression handling any conversions which must be done during // assignment. -tree -Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, - Type* rhs_type, tree rhs_tree, - Location location) +Expression* +Expression::convert_for_assignment(Gogo* gogo, Type* lhs_type, + Expression* rhs, Location location) { - if (lhs_type->is_error() || rhs_type->is_error()) - return error_mark_node; - - if (rhs_tree == error_mark_node || TREE_TYPE(rhs_tree) == error_mark_node) - return error_mark_node; - - Gogo* gogo = context->gogo(); - - tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo)); - if (lhs_type_tree == error_mark_node) - return error_mark_node; + Type* rhs_type = rhs->type(); + if (lhs_type->is_error() + || rhs_type->is_error() + || rhs->is_error_expression()) + return Expression::make_error(location); if (lhs_type->forwarded() != rhs_type->forwarded() && lhs_type->interface_type() != NULL) { if (rhs_type->interface_type() == NULL) - return Expression::convert_type_to_interface(context, lhs_type, - rhs_type, rhs_tree, - location); + return Expression::convert_type_to_interface(lhs_type, rhs, location); else - return Expression::convert_interface_to_interface(context, lhs_type, - rhs_type, rhs_tree, - false, location); + return Expression::convert_interface_to_interface(lhs_type, rhs, false, + location); } else if (lhs_type->forwarded() != rhs_type->forwarded() && rhs_type->interface_type() != NULL) - return Expression::convert_interface_to_type(context, lhs_type, rhs_type, - rhs_tree, location); + return Expression::convert_interface_to_type(lhs_type, rhs, location); else if (lhs_type->is_slice_type() && rhs_type->is_nil_type()) { - // Assigning nil to an open array. - go_assert(TREE_CODE(lhs_type_tree) == RECORD_TYPE); - - vec *init; - vec_alloc(init, 3); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(lhs_type_tree); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__values") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__count") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), integer_zero_node); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__capacity") == 0); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), integer_zero_node); - - tree val = build_constructor(lhs_type_tree, init); - TREE_CONSTANT(val) = 1; - - return val; + // Assigning nil to a slice. + mpz_t zval; + mpz_init_set_ui(zval, 0UL); + Expression* zero = Expression::make_integer(&zval, NULL, location); + mpz_clear(zval); + Expression* nil = Expression::make_nil(location); + return Expression::make_slice_value(lhs_type, nil, zero, zero, location); } else if (rhs_type->is_nil_type()) - { - // The left hand side should be a pointer type at the tree - // level. - go_assert(POINTER_TYPE_P(lhs_type_tree)); - return fold_convert(lhs_type_tree, null_pointer_node); - } - else if (lhs_type_tree == TREE_TYPE(rhs_tree)) + return Expression::make_nil(location); + else if (Type::are_identical(lhs_type, rhs_type, false, NULL)) { // No conversion is needed. - return rhs_tree; - } - else if (POINTER_TYPE_P(lhs_type_tree) - || INTEGRAL_TYPE_P(lhs_type_tree) - || SCALAR_FLOAT_TYPE_P(lhs_type_tree) - || COMPLEX_FLOAT_TYPE_P(lhs_type_tree)) - return fold_convert_loc(location.gcc_location(), lhs_type_tree, rhs_tree); - else if ((TREE_CODE(lhs_type_tree) == RECORD_TYPE - && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE) - || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE - && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE)) + return rhs; + } + else if (lhs_type->points_to() != NULL) + return Expression::make_unsafe_cast(lhs_type, rhs, location); + else if (lhs_type->is_numeric_type()) + return Expression::make_cast(lhs_type, rhs, location); + else if ((lhs_type->struct_type() != NULL + && rhs_type->struct_type() != NULL) + || (lhs_type->array_type() != NULL + && rhs_type->array_type() != NULL)) { // Avoid confusion from zero sized variables which may be // represented as non-zero-sized. - if (int_size_in_bytes(lhs_type_tree) == 0 - || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) - return rhs_tree; + // TODO(cmang): This check is for a GCC-specific issue, and should be + // removed from the frontend. FIXME. + size_t lhs_size = gogo->backend()->type_size(lhs_type->get_backend(gogo)); + size_t rhs_size = gogo->backend()->type_size(rhs_type->get_backend(gogo)); + if (rhs_size == 0 || lhs_size == 0) + return rhs; // This conversion must be permitted by Go, or we wouldn't have // gotten here. - go_assert(int_size_in_bytes(lhs_type_tree) - == int_size_in_bytes(TREE_TYPE(rhs_tree))); - return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, - lhs_type_tree, rhs_tree); + return Expression::make_unsafe_cast(lhs_type, rhs, location); } else - { - go_assert(useless_type_conversion_p(lhs_type_tree, TREE_TYPE(rhs_tree))); - return rhs_tree; - } + return rhs; } -// Return a tree for a conversion from a non-interface type to an +// Return an expression for a conversion from a non-interface type to an // interface type. -tree -Expression::convert_type_to_interface(Translate_context* context, - Type* lhs_type, Type* rhs_type, - tree rhs_tree, Location location) +Expression* +Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs, + Location location) { - Gogo* gogo = context->gogo(); Interface_type* lhs_interface_type = lhs_type->interface_type(); bool lhs_is_empty = lhs_interface_type->is_empty(); @@ -270,29 +223,22 @@ Expression::convert_type_to_interface(Translate_context* context, // When setting an interface to nil, we just set both fields to // NULL. + Type* rhs_type = rhs->type(); if (rhs_type->is_nil_type()) { - Btype* lhs_btype = lhs_type->get_backend(gogo); - return expr_to_tree(gogo->backend()->zero_expression(lhs_btype)); + Expression* nil = Expression::make_nil(location); + return Expression::make_interface_value(lhs_type, nil, nil, location); } // This should have been checked already. go_assert(lhs_interface_type->implements_interface(rhs_type, NULL)); - tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo)); - if (lhs_type_tree == error_mark_node) - return error_mark_node; - // An interface is a tuple. If LHS_TYPE is an empty interface type, // then the first field is the type descriptor for RHS_TYPE. // Otherwise it is the interface method table for RHS_TYPE. - tree first_field_value; + Expression* first_field; if (lhs_is_empty) - { - Bexpression* rhs_bexpr = - rhs_type->type_descriptor_pointer(gogo, location); - first_field_value = expr_to_tree(rhs_bexpr); - } + first_field = Expression::make_type_descriptor(rhs_type, location); else { // Build the interface method table for this interface and this @@ -307,131 +253,72 @@ Expression::convert_type_to_interface(Translate_context* context, rhs_struct_type = rhs_type->deref()->struct_type(); is_pointer = true; } - tree method_table; if (rhs_named_type != NULL) - method_table = - rhs_named_type->interface_method_table(gogo, lhs_interface_type, - is_pointer); + first_field = + rhs_named_type->interface_method_table(lhs_interface_type, + is_pointer); else if (rhs_struct_type != NULL) - method_table = - rhs_struct_type->interface_method_table(gogo, lhs_interface_type, - is_pointer); + first_field = + rhs_struct_type->interface_method_table(lhs_interface_type, + is_pointer); else - method_table = null_pointer_node; - first_field_value = fold_convert_loc(location.gcc_location(), - const_ptr_type_node, method_table); + first_field = Expression::make_nil(location); } - if (first_field_value == error_mark_node) - return error_mark_node; - - // Start building a constructor for the value we will return. - - vec *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(lhs_type_tree); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - (lhs_is_empty ? "__type_descriptor" : "__methods")) == 0); - elt->index = field; - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - first_field_value); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0); - elt->index = field; + Expression* obj; if (rhs_type->points_to() != NULL) { - // We are assigning a pointer to the interface; the interface + // We are assigning a pointer to the interface; the interface // holds the pointer itself. - elt->value = rhs_tree; - return build_constructor(lhs_type_tree, init); + obj = rhs; + } + else + { + // We are assigning a non-pointer value to the interface; the + // interface gets a copy of the value in the heap. + obj = Expression::make_heap_expression(rhs, location); } - // We are assigning a non-pointer value to the interface; the - // interface gets a copy of the value in the heap. + return Expression::make_interface_value(lhs_type, first_field, obj, location); +} - tree object_size = TYPE_SIZE_UNIT(TREE_TYPE(rhs_tree)); +// Return an expression for the type descriptor of RHS. - tree space = gogo->allocate_memory(rhs_type, object_size, location); - space = fold_convert_loc(location.gcc_location(), - build_pointer_type(TREE_TYPE(rhs_tree)), space); - space = save_expr(space); +Expression* +Expression::get_interface_type_descriptor(Expression* rhs) +{ + go_assert(rhs->type()->interface_type() != NULL); + Location location = rhs->location(); - tree ref = build_fold_indirect_ref_loc(location.gcc_location(), space); - TREE_THIS_NOTRAP(ref) = 1; - tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, - void_type_node, ref, rhs_tree); + // The type descriptor is the first field of an empty interface. + if (rhs->type()->interface_type()->is_empty()) + return Expression::make_interface_info(rhs, INTERFACE_INFO_TYPE_DESCRIPTOR, + location); + + Expression* mtable = + Expression::make_interface_info(rhs, INTERFACE_INFO_METHODS, location); - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - space); + Expression* descriptor = + Expression::make_unary(OPERATOR_MULT, mtable, location); + descriptor = Expression::make_field_reference(descriptor, 0, location); + Expression* nil = Expression::make_nil(location); - return build2(COMPOUND_EXPR, lhs_type_tree, set, - build_constructor(lhs_type_tree, init)); + Expression* eq = + Expression::make_binary(OPERATOR_EQEQ, mtable, nil, location); + return Expression::make_conditional(eq, nil, descriptor, location); } -// Return a tree for the type descriptor of RHS_TREE, which has -// interface type RHS_TYPE. If RHS_TREE is nil the result will be -// NULL. - -tree -Expression::get_interface_type_descriptor(Translate_context*, - Type* rhs_type, tree rhs_tree, - Location location) -{ - tree rhs_type_tree = TREE_TYPE(rhs_tree); - go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE); - tree rhs_field = TYPE_FIELDS(rhs_type_tree); - tree v = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field, - NULL_TREE); - if (rhs_type->interface_type()->is_empty()) - { - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), - "__type_descriptor") == 0); - return v; - } - - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__methods") - == 0); - go_assert(POINTER_TYPE_P(TREE_TYPE(v))); - v = save_expr(v); - tree v1 = build_fold_indirect_ref_loc(location.gcc_location(), v); - go_assert(TREE_CODE(TREE_TYPE(v1)) == RECORD_TYPE); - tree f = TYPE_FIELDS(TREE_TYPE(v1)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(f)), "__type_descriptor") - == 0); - v1 = build3(COMPONENT_REF, TREE_TYPE(f), v1, f, NULL_TREE); - - tree eq = fold_build2_loc(location.gcc_location(), EQ_EXPR, boolean_type_node, - v, fold_convert_loc(location.gcc_location(), - TREE_TYPE(v), - null_pointer_node)); - tree n = fold_convert_loc(location.gcc_location(), TREE_TYPE(v1), - null_pointer_node); - return fold_build3_loc(location.gcc_location(), COND_EXPR, TREE_TYPE(v1), - eq, n, v1); -} - -// Return a tree for the conversion of an interface type to an +// Return an expression for the conversion of an interface type to an // interface type. -tree -Expression::convert_interface_to_interface(Translate_context* context, - Type *lhs_type, Type *rhs_type, - tree rhs_tree, bool for_type_guard, - Location location) +Expression* +Expression::convert_interface_to_interface(Type *lhs_type, Expression* rhs, + bool for_type_guard, + Location location) { - Gogo* gogo = context->gogo(); Interface_type* lhs_interface_type = lhs_type->interface_type(); bool lhs_is_empty = lhs_interface_type->is_empty(); - tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo)); - if (lhs_type_tree == error_mark_node) - return error_mark_node; - // In the general case this requires runtime examination of the type // method table to match it up with the interface methods. @@ -442,169 +329,75 @@ Expression::convert_interface_to_interface(Translate_context* context, // Get the type descriptor for the right hand side. This will be // NULL for a nil interface. + Expression* rhs_type_expr = Expression::get_interface_type_descriptor(rhs); + Expression* lhs_type_expr = + Expression::make_type_descriptor(lhs_type, location); - if (!DECL_P(rhs_tree)) - rhs_tree = save_expr(rhs_tree); - - tree rhs_type_descriptor = - Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree, - location); - - // The result is going to be a two element constructor. - - vec *init; - vec_alloc (init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(lhs_type_tree); - elt->index = field; - + Expression* first_field; if (for_type_guard) { // A type assertion fails when converting a nil interface. - Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo, - location); - tree lhs_type_descriptor = expr_to_tree(lhs_type_expr); - static tree assert_interface_decl; - tree call = Gogo::call_builtin(&assert_interface_decl, - location, - "__go_assert_interface", - 2, - ptr_type_node, - TREE_TYPE(lhs_type_descriptor), - lhs_type_descriptor, - TREE_TYPE(rhs_type_descriptor), - rhs_type_descriptor); - if (call == error_mark_node) - return error_mark_node; - // This will panic if the interface conversion fails. - TREE_NOTHROW(assert_interface_decl) = 0; - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - call); + first_field = + Runtime::make_call(Runtime::ASSERT_INTERFACE, location, 2, + lhs_type_expr, rhs_type_expr); } else if (lhs_is_empty) { - // A convertion to an empty interface always succeeds, and the + // A conversion to an empty interface always succeeds, and the // first field is just the type descriptor of the object. - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), - "__type_descriptor") == 0); - elt->value = fold_convert_loc(location.gcc_location(), - TREE_TYPE(field), rhs_type_descriptor); + first_field = rhs_type_expr; } else { // A conversion to a non-empty interface may fail, but unlike a // type assertion converting nil will always succeed. - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__methods") - == 0); - Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo, - location); - tree lhs_type_descriptor = expr_to_tree(lhs_type_expr); - - static tree convert_interface_decl; - tree call = Gogo::call_builtin(&convert_interface_decl, - location, - "__go_convert_interface", - 2, - ptr_type_node, - TREE_TYPE(lhs_type_descriptor), - lhs_type_descriptor, - TREE_TYPE(rhs_type_descriptor), - rhs_type_descriptor); - if (call == error_mark_node) - return error_mark_node; - // This will panic if the interface conversion fails. - TREE_NOTHROW(convert_interface_decl) = 0; - elt->value = fold_convert_loc(location.gcc_location(), TREE_TYPE(field), - call); + first_field = + Runtime::make_call(Runtime::CONVERT_INTERFACE, location, 2, + lhs_type_expr, rhs_type_expr); } // The second field is simply the object pointer. - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__object") == 0); - elt->index = field; - - tree rhs_type_tree = TREE_TYPE(rhs_tree); - go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE); - tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0); - elt->value = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field, - NULL_TREE); - - return build_constructor(lhs_type_tree, init); + Expression* obj = + Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT, location); + return Expression::make_interface_value(lhs_type, first_field, obj, location); } -// Return a tree for the conversion of an interface type to a +// Return an expression for the conversion of an interface type to a // non-interface type. -tree -Expression::convert_interface_to_type(Translate_context* context, - Type *lhs_type, Type* rhs_type, - tree rhs_tree, Location location) +Expression* +Expression::convert_interface_to_type(Type *lhs_type, Expression* rhs, + Location location) { - Gogo* gogo = context->gogo(); - tree rhs_type_tree = TREE_TYPE(rhs_tree); - - tree lhs_type_tree = type_to_tree(lhs_type->get_backend(gogo)); - if (lhs_type_tree == error_mark_node) - return error_mark_node; - // Call a function to check that the type is valid. The function // will panic with an appropriate runtime type error if the type is // not valid. - Bexpression* lhs_type_expr = lhs_type->type_descriptor_pointer(gogo, - location); - tree lhs_type_descriptor = expr_to_tree(lhs_type_expr); - - if (!DECL_P(rhs_tree)) - rhs_tree = save_expr(rhs_tree); - - tree rhs_type_descriptor = - Expression::get_interface_type_descriptor(context, rhs_type, rhs_tree, - location); - - Bexpression* rhs_inter_expr = rhs_type->type_descriptor_pointer(gogo, - location); - tree rhs_inter_descriptor = expr_to_tree(rhs_inter_expr); - - static tree check_interface_type_decl; - tree call = Gogo::call_builtin(&check_interface_type_decl, - location, - "__go_check_interface_type", - 3, - void_type_node, - TREE_TYPE(lhs_type_descriptor), - lhs_type_descriptor, - TREE_TYPE(rhs_type_descriptor), - rhs_type_descriptor, - TREE_TYPE(rhs_inter_descriptor), - rhs_inter_descriptor); - if (call == error_mark_node) - return error_mark_node; - // This call will panic if the conversion is invalid. - TREE_NOTHROW(check_interface_type_decl) = 0; + Expression* lhs_type_expr = Expression::make_type_descriptor(lhs_type, + location); + Expression* rhs_descriptor = + Expression::get_interface_type_descriptor(rhs); + + Type* rhs_type = rhs->type(); + Expression* rhs_inter_expr = Expression::make_type_descriptor(rhs_type, + location); + + Expression* check_iface = Runtime::make_call(Runtime::CHECK_INTERFACE_TYPE, + location, 3, lhs_type_expr, + rhs_descriptor, rhs_inter_expr); // If the call succeeds, pull out the value. - go_assert(TREE_CODE(rhs_type_tree) == RECORD_TYPE); - tree rhs_field = DECL_CHAIN(TYPE_FIELDS(rhs_type_tree)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(rhs_field)), "__object") == 0); - tree val = build3(COMPONENT_REF, TREE_TYPE(rhs_field), rhs_tree, rhs_field, - NULL_TREE); + Expression* obj = Expression::make_interface_info(rhs, INTERFACE_INFO_OBJECT, + location); // If the value is a pointer, then it is the value we want. // Otherwise it points to the value. if (lhs_type->points_to() == NULL) { - val = fold_convert_loc(location.gcc_location(), - build_pointer_type(lhs_type_tree), val); - val = build_fold_indirect_ref_loc(location.gcc_location(), val); + obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), obj, + location); + obj = Expression::make_unary(OPERATOR_MULT, obj, location); } - - return build2(COMPOUND_EXPR, lhs_type_tree, call, - fold_convert_loc(location.gcc_location(), lhs_type_tree, val)); + return Expression::make_compound(check_iface, obj, location); } // Convert an expression to a tree. This is implemented by the child @@ -674,54 +467,71 @@ Expression::backend_numeric_constant_expression(Translate_context* context, return ret; } -// Return a tree which evaluates to true if VAL, of arbitrary integer -// type, is negative or is more than the maximum value of BOUND_TYPE. -// If SOFAR is not NULL, it is or'red into the result. The return -// value may be NULL if SOFAR is NULL. +// Return an expression which evaluates to true if VAL, of arbitrary integer +// type, is negative or is more than the maximum value of the Go type "int". -tree -Expression::check_bounds(tree val, tree bound_type, tree sofar, - Location loc) +Expression* +Expression::check_bounds(Expression* val, Location loc) { - tree val_type = TREE_TYPE(val); - tree ret = NULL_TREE; + Type* val_type = val->type(); + Type* bound_type = Type::lookup_integer_type("int"); + + int val_type_size; + bool val_is_unsigned = false; + if (val_type->integer_type() != NULL) + { + val_type_size = val_type->integer_type()->bits(); + val_is_unsigned = val_type->integer_type()->is_unsigned(); + } + else + { + if (!val_type->is_numeric_type() + || !Type::are_convertible(bound_type, val_type, NULL)) + { + go_assert(saw_errors()); + return Expression::make_boolean(true, loc); + } - if (!TYPE_UNSIGNED(val_type)) + if (val_type->complex_type() != NULL) + val_type_size = val_type->complex_type()->bits(); + else + val_type_size = val_type->float_type()->bits(); + } + + Expression* negative_index = Expression::make_boolean(false, loc); + Expression* index_overflows = Expression::make_boolean(false, loc); + if (!val_is_unsigned) { - ret = fold_build2_loc(loc.gcc_location(), LT_EXPR, boolean_type_node, val, - build_int_cst(val_type, 0)); - if (ret == boolean_false_node) - ret = NULL_TREE; + mpz_t zval; + mpz_init_set_ui(zval, 0UL); + Expression* zero = Expression::make_integer(&zval, val_type, loc); + mpz_clear(zval); + + negative_index = Expression::make_binary(OPERATOR_LT, val, zero, loc); } - HOST_WIDE_INT val_type_size = int_size_in_bytes(val_type); - HOST_WIDE_INT bound_type_size = int_size_in_bytes(bound_type); - go_assert(val_type_size != -1 && bound_type_size != -1); + int bound_type_size = bound_type->integer_type()->bits(); if (val_type_size > bound_type_size || (val_type_size == bound_type_size - && TYPE_UNSIGNED(val_type) - && !TYPE_UNSIGNED(bound_type))) - { - tree max = TYPE_MAX_VALUE(bound_type); - tree big = fold_build2_loc(loc.gcc_location(), GT_EXPR, boolean_type_node, - val, fold_convert_loc(loc.gcc_location(), - val_type, max)); - if (big == boolean_false_node) - ; - else if (ret == NULL_TREE) - ret = big; - else - ret = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, ret, big); + && val_is_unsigned)) + { + mpz_t one; + mpz_init_set_ui(one, 1UL); + + // maxval = 2^(bound_type_size - 1) - 1 + mpz_t maxval; + mpz_init(maxval); + mpz_mul_2exp(maxval, one, bound_type_size - 1); + mpz_sub_ui(maxval, maxval, 1); + Expression* max = Expression::make_integer(&maxval, val_type, loc); + mpz_clear(one); + mpz_clear(maxval); + + index_overflows = Expression::make_binary(OPERATOR_GT, val, max, loc); } - if (ret == NULL_TREE) - return sofar; - else if (sofar == NULL_TREE) - return ret; - else - return fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, boolean_type_node, - sofar, ret); + return Expression::make_binary(OPERATOR_OROR, negative_index, index_overflows, + loc); } void @@ -1719,7 +1529,23 @@ String_expression::do_determine_type(const Type_context* context) tree String_expression::do_get_tree(Translate_context* context) { - return context->gogo()->go_string_constant_tree(this->val_); + Gogo* gogo = context->gogo(); + Btype* btype = Type::make_string_type()->get_backend(gogo); + + Location loc = this->location(); + std::vector init(2); + Bexpression* str_cst = + gogo->backend()->string_constant_expression(this->val_); + init[0] = gogo->backend()->address_expression(str_cst, loc); + + Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo); + mpz_t lenval; + mpz_init_set_ui(lenval, this->val_.length()); + init[1] = gogo->backend()->integer_constant_expression(int_btype, lenval); + mpz_clear(lenval); + + Bexpression* ret = gogo->backend()->constructor_expression(btype, init, loc); + return expr_to_tree(ret); } // Write string literal to string dump. @@ -1826,6 +1652,116 @@ Expression::make_string(const std::string& val, Location location) return new String_expression(val, location); } +// An expression that evaluates to some characteristic of a string. +// This is used when indexing, bound-checking, or nil checking a string. + +class String_info_expression : public Expression +{ + public: + String_info_expression(Expression* string, String_info string_info, + Location location) + : Expression(EXPRESSION_STRING_INFO, location), + string_(string), string_info_(string_info) + { } + + protected: + Type* + do_type(); + + void + do_determine_type(const Type_context*) + { go_unreachable(); } + + Expression* + do_copy() + { + return new String_info_expression(this->string_->copy(), this->string_info_, + this->location()); + } + + tree + do_get_tree(Translate_context* context); + + void + do_dump_expression(Ast_dump_context*) const; + + void + do_issue_nil_check() + { this->string_->issue_nil_check(); } + + private: + // The string for which we are getting information. + Expression* string_; + // What information we want. + String_info string_info_; +}; + +// Return the type of the string info. + +Type* +String_info_expression::do_type() +{ + switch (this->string_info_) + { + case STRING_INFO_DATA: + { + Type* byte_type = Type::lookup_integer_type("uint8"); + return Type::make_pointer_type(byte_type); + } + case STRING_INFO_LENGTH: + return Type::lookup_integer_type("int"); + default: + go_unreachable(); + } +} + +// Return string information in GENERIC. + +tree +String_info_expression::do_get_tree(Translate_context* context) +{ + Gogo* gogo = context->gogo(); + + Bexpression* bstring = tree_to_expr(this->string_->get_tree(context)); + Bexpression* ret; + switch (this->string_info_) + { + case STRING_INFO_DATA: + case STRING_INFO_LENGTH: + ret = gogo->backend()->struct_field_expression(bstring, this->string_info_, + this->location()); + break; + default: + go_unreachable(); + } + return expr_to_tree(ret); +} + +// Dump ast representation for a type info expression. + +void +String_info_expression::do_dump_expression( + Ast_dump_context* ast_dump_context) const +{ + ast_dump_context->ostream() << "stringinfo("; + this->string_->dump_expression(ast_dump_context); + ast_dump_context->ostream() << ","; + ast_dump_context->ostream() << + (this->string_info_ == STRING_INFO_DATA ? "data" + : this->string_info_ == STRING_INFO_LENGTH ? "length" + : "unknown"); + ast_dump_context->ostream() << ")"; +} + +// Make a string info expression. + +Expression* +Expression::make_string_info(Expression* string, String_info string_info, + Location location) +{ + return new String_info_expression(string, string_info, location); +} + // Make an integer expression. class Integer_expression : public Expression @@ -2826,16 +2762,8 @@ Const_expression::do_check_types(Gogo*) tree Const_expression::do_get_tree(Translate_context* context) { - Gogo* gogo = context->gogo(); - tree type_tree; - if (this->type_ == NULL) - type_tree = NULL_TREE; - else - { - type_tree = type_to_tree(this->type_->get_backend(gogo)); - if (type_tree == error_mark_node) - return error_mark_node; - } + if (this->type_ != NULL && this->type_->is_error()) + return error_mark_node; // If the type has been set for this expression, but the underlying // object is an abstract int or float, we try to get the abstract @@ -2855,24 +2783,15 @@ Const_expression::do_get_tree(Translate_context* context) } } - tree const_tree = this->constant_->get_tree(gogo, context->function()); - if (this->type_ == NULL - || const_tree == error_mark_node - || TREE_TYPE(const_tree) == error_mark_node) - return const_tree; - - tree ret; - if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(const_tree))) - ret = fold_convert(type_tree, const_tree); - else if (TREE_CODE(type_tree) == INTEGER_TYPE) - ret = fold(convert_to_integer(type_tree, const_tree)); - else if (TREE_CODE(type_tree) == REAL_TYPE) - ret = fold(convert_to_real(type_tree, const_tree)); - else if (TREE_CODE(type_tree) == COMPLEX_TYPE) - ret = fold(convert_to_complex(type_tree, const_tree)); - else - go_unreachable(); - return ret; + Gogo* gogo = context->gogo(); + Bexpression* ret = + tree_to_expr(this->constant_->get_tree(gogo, context->function())); + if (this->type_ != NULL) + { + Btype* btype = this->type_->get_backend(gogo); + ret = gogo->backend()->convert_expression(btype, ret, this->location()); + } + return expr_to_tree(ret); } // Dump ast representation for constant expression. @@ -3221,8 +3140,10 @@ Expression* Type_conversion_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) { - if (this->type()->is_string_type() - && this->expr_->type()->is_slice_type() + if (((this->type()->is_string_type() + && this->expr_->type()->is_slice_type()) + || (this->type()->interface_type() != NULL + && this->expr_->type()->interface_type() != NULL)) && !this->expr_->is_variable()) { Temporary_statement* temp = @@ -3325,73 +3246,50 @@ Type_conversion_expression::do_check_types(Gogo*) tree Type_conversion_expression::do_get_tree(Translate_context* context) { - Gogo* gogo = context->gogo(); - tree type_tree = type_to_tree(this->type_->get_backend(gogo)); - tree expr_tree = this->expr_->get_tree(context); - - if (type_tree == error_mark_node - || expr_tree == error_mark_node - || TREE_TYPE(expr_tree) == error_mark_node) - return error_mark_node; - - if (TYPE_MAIN_VARIANT(type_tree) == TYPE_MAIN_VARIANT(TREE_TYPE(expr_tree))) - return fold_convert(type_tree, expr_tree); - Type* type = this->type_; Type* expr_type = this->expr_->type(); - tree ret; - if (type->interface_type() != NULL || expr_type->interface_type() != NULL) - ret = Expression::convert_for_assignment(context, type, expr_type, - expr_tree, this->location()); - else if (type->integer_type() != NULL) - { - if (expr_type->integer_type() != NULL - || expr_type->float_type() != NULL - || expr_type->is_unsafe_pointer_type()) - ret = fold(convert_to_integer(type_tree, expr_tree)); - else - go_unreachable(); - } - else if (type->float_type() != NULL) + + Gogo* gogo = context->gogo(); + Btype* btype = type->get_backend(gogo); + Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context)); + Location loc = this->location(); + + if (Type::are_identical(type, expr_type, false, NULL)) { - if (expr_type->integer_type() != NULL - || expr_type->float_type() != NULL) - ret = fold(convert_to_real(type_tree, expr_tree)); - else - go_unreachable(); + Bexpression* bconvert = + gogo->backend()->convert_expression(btype, bexpr, loc); + return expr_to_tree(bconvert); } - else if (type->complex_type() != NULL) + else if (type->interface_type() != NULL + || expr_type->interface_type() != NULL) { - if (expr_type->complex_type() != NULL) - ret = fold(convert_to_complex(type_tree, expr_tree)); - else - go_unreachable(); + Expression* conversion = + Expression::convert_for_assignment(gogo, type, this->expr_, + this->location()); + return conversion->get_tree(context); } else if (type->is_string_type() && expr_type->integer_type() != NULL) { - Type* int_type = Type::lookup_integer_type("int"); - tree int_type_tree = type_to_tree(int_type->get_backend(gogo)); - - expr_tree = fold_convert(int_type_tree, expr_tree); - if (tree_fits_shwi_p (expr_tree)) + mpz_t intval; + Numeric_constant nc; + if (this->expr_->numeric_constant_value(&nc) + && nc.to_int(&intval) + && mpz_fits_ushort_p(intval)) { - HOST_WIDE_INT intval = tree_to_shwi (expr_tree); std::string s; - Lex::append_char(intval, true, &s, this->location()); - Expression* se = Expression::make_string(s, this->location()); + Lex::append_char(mpz_get_ui(intval), true, &s, loc); + mpz_clear(intval); + Expression* se = Expression::make_string(s, loc); return se->get_tree(context); } Expression* i2s_expr = - Runtime::make_call(Runtime::INT_TO_STRING, this->location(), 1, - this->expr_); - i2s_expr = Expression::make_cast(type, i2s_expr, this->location()); - ret = i2s_expr->get_tree(context); + Runtime::make_call(Runtime::INT_TO_STRING, loc, 1, this->expr_); + return Expression::make_cast(type, i2s_expr, loc)->get_tree(context); } else if (type->is_string_type() && expr_type->is_slice_type()) { - Location location = this->location(); Array_type* a = expr_type->array_type(); Type* e = a->element_type()->forwarded(); go_assert(e->integer_type() != NULL); @@ -3407,46 +3305,50 @@ Type_conversion_expression::do_get_tree(Translate_context* context) } Expression* valptr = a->get_value_pointer(gogo, this->expr_); Expression* len = a->get_length(gogo, this->expr_); - Expression* a2s_expr = Runtime::make_call(code, location, 2, valptr, len); - ret = a2s_expr->get_tree(context); + return Runtime::make_call(code, loc, 2, valptr, len)->get_tree(context); } else if (type->is_slice_type() && expr_type->is_string_type()) { Type* e = type->array_type()->element_type()->forwarded(); go_assert(e->integer_type() != NULL); - Expression* s2a_expr; + Runtime::Function code; if (e->integer_type()->is_byte()) - s2a_expr = Runtime::make_call(Runtime::STRING_TO_BYTE_ARRAY, - this->location(), 1, this->expr_); + code = Runtime::STRING_TO_BYTE_ARRAY; else { go_assert(e->integer_type()->is_rune()); - s2a_expr = Runtime::make_call(Runtime::STRING_TO_INT_ARRAY, - this->location(), 1, this->expr_); + code = Runtime::STRING_TO_INT_ARRAY; } - s2a_expr = Expression::make_unsafe_cast(type, s2a_expr, - this->location()); - ret = s2a_expr->get_tree(context); + Expression* s2a = Runtime::make_call(code, loc, 1, this->expr_); + return Expression::make_unsafe_cast(type, s2a, loc)->get_tree(context); + } + else if (type->is_numeric_type()) + { + go_assert(Type::are_convertible(type, expr_type, NULL)); + Bexpression* bconvert = + gogo->backend()->convert_expression(btype, bexpr, loc); + return expr_to_tree(bconvert); } else if ((type->is_unsafe_pointer_type() - && expr_type->points_to() != NULL) - || (expr_type->is_unsafe_pointer_type() - && type->points_to() != NULL)) - ret = fold_convert(type_tree, expr_tree); - else if (type->is_unsafe_pointer_type() - && expr_type->integer_type() != NULL) - ret = convert_to_pointer(type_tree, expr_tree); - else if (this->may_convert_function_types_ - && type->function_type() != NULL - && expr_type->function_type() != NULL) - ret = fold_convert_loc(this->location().gcc_location(), type_tree, - expr_tree); + && (expr_type->points_to() != NULL + || expr_type->integer_type())) + || (expr_type->is_unsafe_pointer_type() + && type->points_to() != NULL) + || (this->may_convert_function_types_ + && type->function_type() != NULL + && expr_type->function_type() != NULL)) + { + Bexpression* bconvert = + gogo->backend()->convert_expression(btype, bexpr, loc); + return expr_to_tree(bconvert); + } else - ret = Expression::convert_for_assignment(context, type, expr_type, - expr_tree, this->location()); - - return ret; + { + Expression* conversion = + Expression::convert_for_assignment(gogo, type, this->expr_, loc); + return conversion->get_tree(context); + } } // Output a type conversion in a constant expression. @@ -3560,58 +3462,57 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context) Type* t = this->type_; Type* et = this->expr_->type(); - - tree type_tree = type_to_tree(this->type_->get_backend(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; - - Location loc = this->location(); - - bool use_view_convert = false; - if (t->is_slice_type()) + if (t->array_type() != NULL) + go_assert(et->array_type() != NULL + && t->is_slice_type() == et->is_slice_type()); + else if (t->struct_type() != NULL) { - go_assert(et->is_slice_type()); - use_view_convert = true; + if (t->named_type() != NULL + && et->named_type() != NULL + && !Type::are_convertible(t, et, NULL)) + { + go_assert(saw_errors()); + return error_mark_node; + } + + go_assert(et->struct_type() != NULL + && Type::are_convertible(t, et, NULL)); } else if (t->map_type() != NULL) go_assert(et->map_type() != NULL); else if (t->channel_type() != NULL) go_assert(et->channel_type() != NULL); else if (t->points_to() != NULL) - go_assert(et->points_to() != NULL || et->is_nil_type()); + go_assert(et->points_to() != NULL + || et->channel_type() != NULL + || et->map_type() != NULL + || et->function_type() != NULL + || et->is_nil_type()); else if (et->is_unsafe_pointer_type()) go_assert(t->points_to() != NULL); - else if (t->interface_type() != NULL && !t->interface_type()->is_empty()) - { - go_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()) + else if (t->interface_type() != NULL) { + bool empty_iface = t->interface_type()->is_empty(); go_assert(et->interface_type() != NULL - && et->interface_type()->is_empty()); - use_view_convert = true; + && et->interface_type()->is_empty() == empty_iface); } else if (t->integer_type() != NULL) - { - go_assert(et->is_boolean_type() - || et->integer_type() != NULL - || et->function_type() != NULL - || et->points_to() != NULL - || et->map_type() != NULL - || et->channel_type() != NULL); - return convert_to_integer(type_tree, expr_tree); - } + go_assert(et->is_boolean_type() + || et->integer_type() != NULL + || et->function_type() != NULL + || et->points_to() != NULL + || et->map_type() != NULL + || et->channel_type() != NULL); else go_unreachable(); - if (use_view_convert) - return fold_build1_loc(loc.gcc_location(), VIEW_CONVERT_EXPR, type_tree, - expr_tree); - else - return fold_convert_loc(loc.gcc_location(), type_tree, expr_tree); + Gogo* gogo = context->gogo(); + Btype* btype = t->get_backend(gogo); + Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context)); + Location loc = this->location(); + Bexpression* ret = + gogo->backend()->convert_expression(btype, bexpr, loc); + return expr_to_tree(ret); } // Dump ast representation for an unsafe type conversion expression. @@ -3757,7 +3658,7 @@ class Unary_expression : public Expression }; // If we are taking the address of a composite literal, and the -// contents are not constant, then we want to make a heap composite +// contents are not constant, then we want to make a heap expression // instead. Expression* @@ -4758,9 +4659,19 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, { case OPERATOR_PLUS: mpz_add(val, left_val, right_val); + if (mpz_sizeinbase(val, 2) > 0x100000) + { + error_at(location, "constant addition overflow"); + mpz_set_ui(val, 1); + } break; case OPERATOR_MINUS: mpz_sub(val, left_val, right_val); + if (mpz_sizeinbase(val, 2) > 0x100000) + { + error_at(location, "constant subtraction overflow"); + mpz_set_ui(val, 1); + } break; case OPERATOR_OR: mpz_ior(val, left_val, right_val); @@ -4770,6 +4681,11 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, break; case OPERATOR_MULT: mpz_mul(val, left_val, right_val); + if (mpz_sizeinbase(val, 2) > 0x100000) + { + error_at(location, "constant multiplication overflow"); + mpz_set_ui(val, 1); + } break; case OPERATOR_DIV: if (mpz_sgn(right_val) != 0) @@ -4797,7 +4713,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, else { error_at(location, "shift count overflow"); - mpz_set_ui(val, 0); + mpz_set_ui(val, 1); } break; } @@ -4808,7 +4724,7 @@ Binary_expression::eval_integer(Operator op, const Numeric_constant* left_nc, if (mpz_cmp_ui(right_val, shift) != 0) { error_at(location, "shift count overflow"); - mpz_set_ui(val, 0); + mpz_set_ui(val, 1); } else { @@ -6888,7 +6804,7 @@ Bound_method_expression::do_get_tree(Translate_context* context) vals->push_back(val); Expression* ret = Expression::make_struct_composite_literal(st, vals, loc); - ret = Expression::make_heap_composite(ret, loc); + ret = Expression::make_heap_expression(ret, loc); tree ret_tree = ret->get_tree(context); @@ -7776,27 +7692,33 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const return false; if (arg_type->is_abstract()) return false; + if (this->seen_) + return false; unsigned int ret; if (this->code_ == BUILTIN_SIZEOF) { - if (!arg_type->backend_type_size(this->gogo_, &ret)) + this->seen_ = true; + bool ok = arg_type->backend_type_size(this->gogo_, &ret); + this->seen_ = false; + if (!ok) return false; } else if (this->code_ == BUILTIN_ALIGNOF) { + bool ok; + this->seen_ = true; if (arg->field_reference_expression() == NULL) - { - if (!arg_type->backend_type_align(this->gogo_, &ret)) - return false; - } + ok = arg_type->backend_type_align(this->gogo_, &ret); else { // Calling unsafe.Alignof(s.f) returns the alignment of // the type of f when it is used as a field in a struct. - if (!arg_type->backend_type_field_align(this->gogo_, &ret)) - return false; + ok = arg_type->backend_type_field_align(this->gogo_, &ret); } + this->seen_ = false; + if (!ok) + return false; } else go_unreachable(); @@ -7813,6 +7735,9 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const Field_reference_expression* farg = arg->field_reference_expression(); if (farg == NULL) return false; + if (this->seen_) + return false; + unsigned int total_offset = 0; while (true) { @@ -7823,10 +7748,13 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const if (st->named_type() != NULL) st->named_type()->convert(this->gogo_); unsigned int offset; - if (!st->struct_type()->backend_field_offset(this->gogo_, - farg->field_index(), - &offset)) - return false; + this->seen_ = true; + bool ok = st->struct_type()->backend_field_offset(this->gogo_, + farg->field_index(), + &offset); + this->seen_ = false; + if (!ok) + return false; total_offset += offset; if (farg->implicit() && struct_expr->field_reference_expression() != NULL) { @@ -8439,7 +8367,7 @@ Builtin_call_expression::do_get_tree(Translate_context* context) { const Expression_list* args = this->args(); go_assert(args != NULL && args->size() == 1); - Expression* arg = *args->begin(); + Expression* arg = args->front(); Type* arg_type = arg->type(); if (this->seen_) @@ -8448,31 +8376,22 @@ Builtin_call_expression::do_get_tree(Translate_context* context) return error_mark_node; } this->seen_ = true; - - tree arg_tree = arg->get_tree(context); - this->seen_ = false; - - if (arg_tree == error_mark_node) - return error_mark_node; - if (arg_type->points_to() != NULL) { arg_type = arg_type->points_to(); go_assert(arg_type->array_type() != NULL && !arg_type->is_slice_type()); - go_assert(POINTER_TYPE_P(TREE_TYPE(arg_tree))); - arg_tree = build_fold_indirect_ref(arg_tree); + arg = Expression::make_unary(OPERATOR_MULT, arg, location); } Type* int_type = Type::lookup_integer_type("int"); - tree int_type_tree = type_to_tree(int_type->get_backend(gogo)); - - tree val_tree; + Expression* val; if (this->code_ == BUILTIN_LEN) { if (arg_type->is_string_type()) - val_tree = String_type::length_tree(gogo, arg_tree); + val = Expression::make_string_info(arg, STRING_INFO_LENGTH, + location); else if (arg_type->array_type() != NULL) { if (this->seen_) @@ -8481,34 +8400,13 @@ Builtin_call_expression::do_get_tree(Translate_context* context) return error_mark_node; } this->seen_ = true; - Expression* len = arg_type->array_type()->get_length(gogo, arg); - val_tree = len->get_tree(context); + val = arg_type->array_type()->get_length(gogo, arg); this->seen_ = false; } else if (arg_type->map_type() != NULL) - { - tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo)); - static tree map_len_fndecl; - val_tree = Gogo::call_builtin(&map_len_fndecl, - location, - "__go_map_len", - 1, - int_type_tree, - arg_type_tree, - arg_tree); - } + val = Runtime::make_call(Runtime::MAP_LEN, location, 1, arg); else if (arg_type->channel_type() != NULL) - { - tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo)); - static tree chan_len_fndecl; - val_tree = Gogo::call_builtin(&chan_len_fndecl, - location, - "__go_chan_len", - 1, - int_type_tree, - arg_type_tree, - arg_tree); - } + val = Runtime::make_call(Runtime::CHAN_LEN, location, 1, arg); else go_unreachable(); } @@ -8522,36 +8420,24 @@ Builtin_call_expression::do_get_tree(Translate_context* context) return error_mark_node; } this->seen_ = true; - Expression* cap = - arg_type->array_type()->get_capacity(gogo, arg); - val_tree = cap->get_tree(context); + val = arg_type->array_type()->get_capacity(gogo, arg); this->seen_ = false; } else if (arg_type->channel_type() != NULL) - { - tree arg_type_tree = type_to_tree(arg_type->get_backend(gogo)); - static tree chan_cap_fndecl; - val_tree = Gogo::call_builtin(&chan_cap_fndecl, - location, - "__go_chan_cap", - 1, - int_type_tree, - arg_type_tree, - arg_tree); - } + val = Runtime::make_call(Runtime::CHAN_CAP, location, 1, arg); else go_unreachable(); } - return fold_convert_loc(location.gcc_location(), int_type_tree, - val_tree); + return Expression::make_cast(int_type, val, + location)->get_tree(context); } case BUILTIN_PRINT: case BUILTIN_PRINTLN: { const bool is_ln = this->code_ == BUILTIN_PRINTLN; - tree stmt_list = NULL_TREE; + Expression* print_stmts = NULL; const Expression_list* call_args = this->args(); if (call_args != NULL) @@ -8562,139 +8448,91 @@ Builtin_call_expression::do_get_tree(Translate_context* context) { if (is_ln && p != call_args->begin()) { - static tree print_space_fndecl; - tree call = Gogo::call_builtin(&print_space_fndecl, - location, - "__go_print_space", - 0, - void_type_node); - if (call == error_mark_node) - return error_mark_node; - append_to_statement_list(call, &stmt_list); - } - - Type* type = (*p)->type(); + Expression* print_space = + Runtime::make_call(Runtime::PRINT_SPACE, + this->location(), 0); - tree arg = (*p)->get_tree(context); - if (arg == error_mark_node) - return error_mark_node; + print_stmts = + Expression::make_compound(print_stmts, print_space, + location); + } - tree* pfndecl; - const char* fnname; + Expression* arg = *p; + Type* type = arg->type(); + Runtime::Function code; if (type->is_string_type()) - { - static tree print_string_fndecl; - pfndecl = &print_string_fndecl; - fnname = "__go_print_string"; - } + code = Runtime::PRINT_STRING; else if (type->integer_type() != NULL && type->integer_type()->is_unsigned()) { - static tree print_uint64_fndecl; - pfndecl = &print_uint64_fndecl; - fnname = "__go_print_uint64"; Type* itype = Type::lookup_integer_type("uint64"); - Btype* bitype = itype->get_backend(gogo); - arg = fold_convert_loc(location.gcc_location(), - type_to_tree(bitype), arg); + arg = Expression::make_cast(itype, arg, location); + code = Runtime::PRINT_UINT64; } else if (type->integer_type() != NULL) { - static tree print_int64_fndecl; - pfndecl = &print_int64_fndecl; - fnname = "__go_print_int64"; Type* itype = Type::lookup_integer_type("int64"); - Btype* bitype = itype->get_backend(gogo); - arg = fold_convert_loc(location.gcc_location(), - type_to_tree(bitype), arg); + arg = Expression::make_cast(itype, arg, location); + code = Runtime::PRINT_INT64; } else if (type->float_type() != NULL) { - static tree print_double_fndecl; - pfndecl = &print_double_fndecl; - fnname = "__go_print_double"; - arg = fold_convert_loc(location.gcc_location(), - double_type_node, arg); + Type* dtype = Type::lookup_float_type("float64"); + arg = Expression::make_cast(dtype, arg, location); + code = Runtime::PRINT_DOUBLE; } else if (type->complex_type() != NULL) { - static tree print_complex_fndecl; - pfndecl = &print_complex_fndecl; - fnname = "__go_print_complex"; - arg = fold_convert_loc(location.gcc_location(), - complex_double_type_node, arg); + Type* ctype = Type::lookup_complex_type("complex128"); + arg = Expression::make_cast(ctype, arg, location); + code = Runtime::PRINT_COMPLEX; } else if (type->is_boolean_type()) - { - static tree print_bool_fndecl; - pfndecl = &print_bool_fndecl; - fnname = "__go_print_bool"; - } + code = Runtime::PRINT_BOOL; else if (type->points_to() != NULL || type->channel_type() != NULL || type->map_type() != NULL || type->function_type() != NULL) { - static tree print_pointer_fndecl; - pfndecl = &print_pointer_fndecl; - fnname = "__go_print_pointer"; - arg = fold_convert_loc(location.gcc_location(), - ptr_type_node, arg); + arg = Expression::make_cast(type, arg, location); + code = Runtime::PRINT_POINTER; } else if (type->interface_type() != NULL) { if (type->interface_type()->is_empty()) - { - static tree print_empty_interface_fndecl; - pfndecl = &print_empty_interface_fndecl; - fnname = "__go_print_empty_interface"; - } + code = Runtime::PRINT_EMPTY_INTERFACE; else - { - static tree print_interface_fndecl; - pfndecl = &print_interface_fndecl; - fnname = "__go_print_interface"; - } + code = Runtime::PRINT_INTERFACE; } else if (type->is_slice_type()) - { - static tree print_slice_fndecl; - pfndecl = &print_slice_fndecl; - fnname = "__go_print_slice"; - } + code = Runtime::PRINT_SLICE; else { go_assert(saw_errors()); return error_mark_node; } - tree call = Gogo::call_builtin(pfndecl, - location, - fnname, - 1, - void_type_node, - TREE_TYPE(arg), - arg); - if (call == error_mark_node) - return error_mark_node; - append_to_statement_list(call, &stmt_list); + Expression* call = Runtime::make_call(code, location, 1, arg); + if (print_stmts == NULL) + print_stmts = call; + else + print_stmts = Expression::make_compound(print_stmts, call, + location); } } if (is_ln) { - static tree print_nl_fndecl; - tree call = Gogo::call_builtin(&print_nl_fndecl, - location, - "__go_print_nl", - 0, - void_type_node); - if (call == error_mark_node) - return error_mark_node; - append_to_statement_list(call, &stmt_list); + Expression* print_nl = + Runtime::make_call(Runtime::PRINT_NL, location, 0); + if (print_stmts == NULL) + print_stmts = print_nl; + else + print_stmts = Expression::make_compound(print_stmts, print_nl, + location); } - return stmt_list; + return print_stmts->get_tree(context); } case BUILTIN_PANIC: @@ -8702,29 +8540,13 @@ Builtin_call_expression::do_get_tree(Translate_context* context) const Expression_list* args = this->args(); go_assert(args != NULL && args->size() == 1); Expression* arg = args->front(); - tree arg_tree = arg->get_tree(context); - if (arg_tree == error_mark_node) - return error_mark_node; Type *empty = Type::make_empty_interface_type(Linemap::predeclared_location()); - arg_tree = Expression::convert_for_assignment(context, empty, - arg->type(), - arg_tree, location); - static tree panic_fndecl; - tree call = Gogo::call_builtin(&panic_fndecl, - location, - "__go_panic", - 1, - void_type_node, - TREE_TYPE(arg_tree), - arg_tree); - if (call == error_mark_node) - return error_mark_node; - // This function will throw an exception. - TREE_NOTHROW(panic_fndecl) = 0; - // This function will not return. - TREE_THIS_VOLATILE(panic_fndecl) = 1; - return call; + arg = Expression::convert_for_assignment(gogo, empty, arg, location); + + Expression* panic = + Runtime::make_call(Runtime::PANIC, location, 1, arg); + return panic->get_tree(context); } case BUILTIN_RECOVER: @@ -8734,49 +8556,22 @@ Builtin_call_expression::do_get_tree(Translate_context* context) const Expression_list* args = this->args(); go_assert(args != NULL && args->size() == 1); Expression* arg = args->front(); - tree arg_tree = arg->get_tree(context); - if (arg_tree == error_mark_node) - return error_mark_node; - Type *empty = Type::make_empty_interface_type(Linemap::predeclared_location()); - tree empty_tree = type_to_tree(empty->get_backend(context->gogo())); - Type* nil_type = Type::make_nil_type(); Expression* nil = Expression::make_nil(location); - tree nil_tree = nil->get_tree(context); - tree empty_nil_tree = Expression::convert_for_assignment(context, - empty, - nil_type, - nil_tree, - location); + nil = Expression::convert_for_assignment(gogo, empty, nil, location); // We need to handle a deferred call to recover specially, // because it changes whether it can recover a panic or not. // See test7 in test/recover1.go. - tree call; - if (this->is_deferred()) - { - static tree deferred_recover_fndecl; - call = Gogo::call_builtin(&deferred_recover_fndecl, - location, - "__go_deferred_recover", - 0, - empty_tree); - } - else - { - static tree recover_fndecl; - call = Gogo::call_builtin(&recover_fndecl, - location, - "__go_recover", - 0, - empty_tree); - } - if (call == error_mark_node) - return error_mark_node; - return fold_build3_loc(location.gcc_location(), COND_EXPR, empty_tree, - arg_tree, call, empty_nil_tree); + Expression* recover = Runtime::make_call((this->is_deferred() + ? Runtime::DEFERRED_RECOVER + : Runtime::RECOVER), + location, 0); + Expression* cond = + Expression::make_conditional(arg, recover, nil, location); + return cond->get_tree(context); } case BUILTIN_CLOSE: @@ -8784,17 +8579,9 @@ Builtin_call_expression::do_get_tree(Translate_context* context) const Expression_list* args = this->args(); go_assert(args != NULL && args->size() == 1); Expression* arg = args->front(); - tree arg_tree = arg->get_tree(context); - if (arg_tree == error_mark_node) - return error_mark_node; - static tree close_fndecl; - return Gogo::call_builtin(&close_fndecl, - location, - "__go_builtin_close", - 1, - void_type_node, - TREE_TYPE(arg_tree), - arg_tree); + Expression* close = Runtime::make_call(Runtime::CLOSE, location, + 1, arg); + return close->get_tree(context); } case BUILTIN_SIZEOF: @@ -8810,8 +8597,12 @@ Builtin_call_expression::do_get_tree(Translate_context* context) return error_mark_node; } Type* uintptr_type = Type::lookup_integer_type("uintptr"); - tree type = type_to_tree(uintptr_type->get_backend(gogo)); - return build_int_cst(type, val); + mpz_t ival; + nc.get_int(&ival); + Expression* int_cst = + Expression::make_integer(&ival, uintptr_type, location); + mpz_clear(ival); + return int_cst->get_tree(context); } case BUILTIN_COPY: @@ -8821,88 +8612,51 @@ Builtin_call_expression::do_get_tree(Translate_context* context) Expression* arg1 = args->front(); Expression* arg2 = args->back(); - tree arg1_tree = arg1->get_tree(context); - tree arg2_tree = arg2->get_tree(context); - if (arg1_tree == error_mark_node || arg2_tree == error_mark_node) - return error_mark_node; - Type* arg1_type = arg1->type(); Array_type* at = arg1_type->array_type(); go_assert(arg1->is_variable()); - Expression* arg1_valptr = at->get_value_pointer(gogo, arg1); - Expression* arg1_len_expr = at->get_length(gogo, arg1); - tree arg1_val = arg1_valptr->get_tree(context); - tree arg1_len = arg1_len_expr->get_tree(context); - if (arg1_val == error_mark_node || arg1_len == error_mark_node) - return error_mark_node; + Expression* arg1_val = at->get_value_pointer(gogo, arg1); + Expression* arg1_len = at->get_length(gogo, arg1); Type* arg2_type = arg2->type(); - tree arg2_val; - tree arg2_len; + go_assert(arg2->is_variable()); + Expression* arg2_val; + Expression* arg2_len; if (arg2_type->is_slice_type()) { at = arg2_type->array_type(); - go_assert(arg2->is_variable()); - Expression* arg2_valptr = at->get_value_pointer(gogo, arg2); - Expression* arg2_len_expr = at->get_length(gogo, arg2); - arg2_val = arg2_valptr->get_tree(context); - arg2_len = arg2_len_expr->get_tree(context); + arg2_val = at->get_value_pointer(gogo, arg2); + arg2_len = at->get_length(gogo, arg2); } else { - arg2_tree = save_expr(arg2_tree); - arg2_val = String_type::bytes_tree(gogo, arg2_tree); - arg2_len = String_type::length_tree(gogo, arg2_tree); + go_assert(arg2->is_variable()); + arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA, + location); + arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH, + location); } - if (arg2_val == error_mark_node || arg2_len == error_mark_node) - return error_mark_node; - - arg1_len = save_expr(arg1_len); - arg2_len = save_expr(arg2_len); - tree len = fold_build3_loc(location.gcc_location(), COND_EXPR, - TREE_TYPE(arg1_len), - fold_build2_loc(location.gcc_location(), - LT_EXPR, boolean_type_node, - arg1_len, arg2_len), - arg1_len, arg2_len); - len = save_expr(len); + Expression* cond = + Expression::make_binary(OPERATOR_LT, arg1_len, arg2_len, location); + Expression* length = + Expression::make_conditional(cond, arg1_len, arg2_len, location); Type* element_type = at->element_type(); Btype* element_btype = element_type->get_backend(gogo); - tree element_type_tree = type_to_tree(element_btype); - if (element_type_tree == error_mark_node) - return error_mark_node; - tree element_size = TYPE_SIZE_UNIT(element_type_tree); - tree bytecount = fold_convert_loc(location.gcc_location(), - TREE_TYPE(element_size), len); - bytecount = fold_build2_loc(location.gcc_location(), MULT_EXPR, - TREE_TYPE(element_size), - bytecount, element_size); - bytecount = fold_convert_loc(location.gcc_location(), size_type_node, - bytecount); - - arg1_val = fold_convert_loc(location.gcc_location(), ptr_type_node, - arg1_val); - arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node, - arg2_val); - - static tree copy_fndecl; - tree call = Gogo::call_builtin(©_fndecl, - location, - "__go_copy", - 3, - void_type_node, - ptr_type_node, - arg1_val, - ptr_type_node, - arg2_val, - size_type_node, - bytecount); - if (call == error_mark_node) - return error_mark_node; - return fold_build2_loc(location.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(len), call, len); + mpz_t size; + size_t element_size = gogo->backend()->type_size(element_btype); + mpz_init_set_ui(size, element_size); + Expression* size_expr = Expression::make_integer(&size, length->type(), location); + mpz_clear(size); + + Expression* bytecount = + Expression::make_binary(OPERATOR_MULT, size_expr, length, location); + Expression* copy = Runtime::make_call(Runtime::COPY, location, 3, + arg1_val, arg2_val, bytecount); + + Expression* compound = Expression::make_compound(copy, length, location); + return compound->get_tree(context); } case BUILTIN_APPEND: @@ -8912,67 +8666,40 @@ Builtin_call_expression::do_get_tree(Translate_context* context) Expression* arg1 = args->front(); Expression* arg2 = args->back(); - tree arg1_tree = arg1->get_tree(context); - tree arg2_tree = arg2->get_tree(context); - if (arg1_tree == error_mark_node || arg2_tree == error_mark_node) - return error_mark_node; - Array_type* at = arg1->type()->array_type(); Type* element_type = at->element_type()->forwarded(); - tree arg2_val; - tree arg2_len; - tree element_size; + go_assert(arg2->is_variable()); + Expression* arg2_val; + Expression* arg2_len; + mpz_t size; if (arg2->type()->is_string_type() && element_type->integer_type() != NULL && element_type->integer_type()->is_byte()) { - arg2_tree = save_expr(arg2_tree); - arg2_val = String_type::bytes_tree(gogo, arg2_tree); - arg2_len = String_type::length_tree(gogo, arg2_tree); - element_size = size_int(1); + arg2_val = Expression::make_string_info(arg2, STRING_INFO_DATA, + location); + arg2_len = Expression::make_string_info(arg2, STRING_INFO_LENGTH, + location); + mpz_init_set_ui(size, 1UL); } else { - go_assert(arg2->is_variable()); - arg2_val = - at->get_value_pointer(gogo, arg2)->get_tree(context); - arg2_len = at->get_length(gogo, arg2)->get_tree(context); + arg2_val = at->get_value_pointer(gogo, arg2); + arg2_len = at->get_length(gogo, arg2); Btype* element_btype = element_type->get_backend(gogo); - tree element_type_tree = type_to_tree(element_btype); - if (element_type_tree == error_mark_node) - return error_mark_node; - element_size = TYPE_SIZE_UNIT(element_type_tree); + size_t element_size = gogo->backend()->type_size(element_btype); + mpz_init_set_ui(size, element_size); } - - arg2_val = fold_convert_loc(location.gcc_location(), ptr_type_node, - arg2_val); - arg2_len = fold_convert_loc(location.gcc_location(), size_type_node, - arg2_len); - element_size = fold_convert_loc(location.gcc_location(), size_type_node, - element_size); - - if (arg2_val == error_mark_node - || arg2_len == error_mark_node - || element_size == error_mark_node) - return error_mark_node; - - // We rebuild the decl each time since the slice types may - // change. - tree append_fndecl = NULL_TREE; - return Gogo::call_builtin(&append_fndecl, - location, - "__go_append", - 4, - TREE_TYPE(arg1_tree), - TREE_TYPE(arg1_tree), - arg1_tree, - ptr_type_node, - arg2_val, - size_type_node, - arg2_len, - size_type_node, - element_size); + Expression* element_size = + Expression::make_integer(&size, NULL, location); + mpz_clear(size); + + Expression* append = Runtime::make_call(Runtime::APPEND, location, 4, + arg1, arg2_val, arg2_len, + element_size); + append = Expression::make_unsafe_cast(arg1->type(), append, location); + return append->get_tree(context); } case BUILTIN_REAL: @@ -8981,34 +8708,25 @@ Builtin_call_expression::do_get_tree(Translate_context* context) const Expression_list* args = this->args(); go_assert(args != NULL && args->size() == 1); Expression* arg = args->front(); - tree arg_tree = arg->get_tree(context); - if (arg_tree == error_mark_node) - return error_mark_node; - go_assert(COMPLEX_FLOAT_TYPE_P(TREE_TYPE(arg_tree))); - if (this->code_ == BUILTIN_REAL) - return fold_build1_loc(location.gcc_location(), REALPART_EXPR, - TREE_TYPE(TREE_TYPE(arg_tree)), - arg_tree); - else - return fold_build1_loc(location.gcc_location(), IMAGPART_EXPR, - TREE_TYPE(TREE_TYPE(arg_tree)), - arg_tree); + + Bexpression* ret; + Bexpression* bcomplex = tree_to_expr(arg->get_tree(context)); + if (this->code_ == BUILTIN_REAL) + ret = gogo->backend()->real_part_expression(bcomplex, location); + else + ret = gogo->backend()->imag_part_expression(bcomplex, location); + return expr_to_tree(ret); } case BUILTIN_COMPLEX: { const Expression_list* args = this->args(); go_assert(args != NULL && args->size() == 2); - tree r = args->front()->get_tree(context); - tree i = args->back()->get_tree(context); - if (r == error_mark_node || i == error_mark_node) - return error_mark_node; - go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(r)) - == TYPE_MAIN_VARIANT(TREE_TYPE(i))); - go_assert(SCALAR_FLOAT_TYPE_P(TREE_TYPE(r))); - return fold_build2_loc(location.gcc_location(), COMPLEX_EXPR, - build_complex_type(TREE_TYPE(r)), - r, i); + Bexpression* breal = tree_to_expr(args->front()->get_tree(context)); + Bexpression* bimag = tree_to_expr(args->back()->get_tree(context)); + Bexpression* ret = + gogo->backend()->complex_expression(breal, bimag, location); + return expr_to_tree(ret); } default: @@ -9382,6 +9100,37 @@ Call_expression::lower_varargs(Gogo* gogo, Named_object* function, this->varargs_are_lowered_ = true; } +// Flatten a call with multiple results into a temporary. + +Expression* +Call_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) +{ + size_t rc = this->result_count(); + if (rc > 1 && this->call_temp_ == NULL) + { + Struct_field_list* sfl = new Struct_field_list(); + Function_type* fntype = this->get_function_type(); + const Typed_identifier_list* results = fntype->results(); + Location loc = this->location(); + + int i = 0; + char buf[10]; + for (Typed_identifier_list::const_iterator p = results->begin(); + p != results->end(); + ++p, ++i) + { + snprintf(buf, sizeof buf, "res%d", i); + sfl->push_back(Struct_field(Typed_identifier(buf, p->type(), loc))); + } + + Struct_type* st = Type::make_struct_type(sfl, loc); + this->call_temp_ = Statement::make_temporary(st, NULL, loc); + inserter->insert(this->call_temp_); + } + + return this; +} + // Get the function type. This can return NULL in error cases. Function_type* @@ -9703,8 +9452,8 @@ Call_expression::interface_method_function( tree Call_expression::do_get_tree(Translate_context* context) { - if (this->tree_ != NULL_TREE) - return this->tree_; + if (this->call_ != NULL) + return expr_to_tree(this->call_); Function_type* fntype = this->get_function_type(); if (fntype == NULL) @@ -9733,11 +9482,12 @@ Call_expression::do_get_tree(Translate_context* context) has_closure_arg = true; int nargs; - tree* args; + std::vector fn_args; if (this->args_ == NULL || this->args_->empty()) { nargs = is_interface_method ? 1 : 0; - args = nargs == 0 ? NULL : new tree[nargs]; + if (nargs > 0) + fn_args.resize(1); } else if (fntype->parameters() == NULL || fntype->parameters()->empty()) { @@ -9746,8 +9496,8 @@ Call_expression::do_get_tree(Translate_context* context) && fntype->is_method() && this->args_->size() == 1); nargs = 1; - args = new tree[nargs]; - args[0] = this->args_->front()->get_tree(context); + fn_args.resize(1); + fn_args[0] = tree_to_expr(this->args_->front()->get_tree(context)); } else { @@ -9756,239 +9506,138 @@ Call_expression::do_get_tree(Translate_context* context) nargs = this->args_->size(); int i = is_interface_method ? 1 : 0; nargs += i; - args = new tree[nargs]; + fn_args.resize(nargs); Typed_identifier_list::const_iterator pp = params->begin(); Expression_list::const_iterator pe = this->args_->begin(); if (!is_interface_method && fntype->is_method()) { - args[i] = (*pe)->get_tree(context); + fn_args[i] = tree_to_expr((*pe)->get_tree(context)); ++pe; ++i; } for (; pe != this->args_->end(); ++pe, ++pp, ++i) { go_assert(pp != params->end()); - tree arg_val = (*pe)->get_tree(context); - args[i] = Expression::convert_for_assignment(context, - pp->type(), - (*pe)->type(), - arg_val, - location); - if (args[i] == error_mark_node) - return error_mark_node; + Expression* arg = + Expression::convert_for_assignment(gogo, pp->type(), *pe, + location); + fn_args[i] = tree_to_expr(arg->get_tree(context)); } go_assert(pp == params->end()); go_assert(i == nargs); } - tree fntype_tree = type_to_tree(fntype->get_backend(gogo)); - tree fnfield_type = type_to_tree(fntype->get_backend_fntype(gogo)); - if (fntype_tree == error_mark_node || fnfield_type == error_mark_node) - return error_mark_node; - go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type)); - tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type)); - if (rettype == error_mark_node) - return error_mark_node; - - tree fn; - tree closure_tree; + Expression* fn; + Expression* closure = NULL; if (func != NULL) { Named_object* no = func->named_object(); - fn = expr_to_tree(Func_expression::get_code_pointer(gogo, no, location)); - if (!has_closure) - closure_tree = NULL_TREE; - else - { - closure_tree = func->closure()->get_tree(context); - if (closure_tree == error_mark_node) - return error_mark_node; - } + fn = Expression::make_func_code_reference(no, location); + if (has_closure) + closure = func->closure(); } else if (!is_interface_method) { - closure_tree = this->fn_->get_tree(context); - if (closure_tree == error_mark_node) - return error_mark_node; - tree fnc = fold_convert_loc(location.gcc_location(), fntype_tree, - closure_tree); - go_assert(POINTER_TYPE_P(TREE_TYPE(fnc)) - && (TREE_CODE(TREE_TYPE(TREE_TYPE(fnc))) - == RECORD_TYPE)); - tree field = TYPE_FIELDS(TREE_TYPE(TREE_TYPE(fnc))); - fn = fold_build3_loc(location.gcc_location(), COMPONENT_REF, - TREE_TYPE(field), - build_fold_indirect_ref_loc(location.gcc_location(), - fnc), - field, NULL_TREE); - } + closure = this->fn_; + + // The backend representation of this function type is a pointer + // to a struct whose first field is the actual function to call. + Type* pfntype = + Type::make_pointer_type( + Type::make_pointer_type(Type::make_void_type())); + fn = Expression::make_unsafe_cast(pfntype, this->fn_, location); + fn = Expression::make_unary(OPERATOR_MULT, fn, location); + } else { Expression* first_arg; - Expression* fn_expr = - this->interface_method_function(interface_method, &first_arg); - args[0] = first_arg->get_tree(context); - fn = fn_expr->get_tree(context); - - if (fn == error_mark_node) - return error_mark_node; - closure_tree = NULL_TREE; - } - - if (fn == error_mark_node || TREE_TYPE(fn) == error_mark_node) - return error_mark_node; - - tree fndecl = fn; - if (TREE_CODE(fndecl) == ADDR_EXPR) - fndecl = TREE_OPERAND(fndecl, 0); - - // Add a type cast in case the type of the function is a recursive - // type which refers to itself. We don't do this for an interface - // method because 1) an interface method never refers to itself, so - // we always have a function type here; 2) we pass an extra first - // argument to an interface method, so fnfield_type is not correct. - if ((!DECL_P(fndecl) || !DECL_IS_BUILTIN(fndecl)) && !is_interface_method) - fn = fold_convert_loc(location.gcc_location(), fnfield_type, fn); - - // This is to support builtin math functions when using 80387 math. - tree excess_type = NULL_TREE; - if (optimize - && TREE_CODE(fndecl) == FUNCTION_DECL - && DECL_IS_BUILTIN(fndecl) - && DECL_BUILT_IN_CLASS(fndecl) == BUILT_IN_NORMAL - && nargs > 0 - && ((SCALAR_FLOAT_TYPE_P(rettype) - && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0]))) - || (COMPLEX_FLOAT_TYPE_P(rettype) - && COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[0]))))) - { - excess_type = excess_precision_type(TREE_TYPE(args[0])); - if (excess_type != NULL_TREE) - { - tree excess_fndecl = mathfn_built_in(excess_type, - DECL_FUNCTION_CODE(fndecl)); - if (excess_fndecl == NULL_TREE) - excess_type = NULL_TREE; - else - { - fn = build_fold_addr_expr_loc(location.gcc_location(), - excess_fndecl); - for (int i = 0; i < nargs; ++i) - { - if (SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[i])) - || COMPLEX_FLOAT_TYPE_P(TREE_TYPE(args[i]))) - args[i] = ::convert(excess_type, args[i]); - } - } - } + fn = this->interface_method_function(interface_method, &first_arg); + fn_args[0] = tree_to_expr(first_arg->get_tree(context)); } - if (func == NULL) - fn = save_expr(fn); - if (!has_closure_arg) - go_assert(closure_tree == NULL_TREE); + go_assert(closure == NULL); else { // Pass the closure argument by calling the function function // __go_set_closure. In the order_evaluations pass we have // ensured that if any parameters contain call expressions, they // will have been moved out to temporary variables. - - go_assert(closure_tree != NULL_TREE); - closure_tree = fold_convert_loc(location.gcc_location(), ptr_type_node, - closure_tree); - static tree set_closure_fndecl; - tree set_closure = Gogo::call_builtin(&set_closure_fndecl, - location, - "__go_set_closure", - 1, - void_type_node, - ptr_type_node, - closure_tree); - if (set_closure == error_mark_node) - return error_mark_node; - fn = build2_loc(location.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(fn), set_closure, fn); + go_assert(closure != NULL); + Expression* set_closure = + Runtime::make_call(Runtime::SET_CLOSURE, location, 1, closure); + fn = Expression::make_compound(set_closure, fn, location); } - tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype, - fn, nargs, args); - delete[] args; - - SET_EXPR_LOCATION(ret, location.gcc_location()); - - // If this is a recursive function type which returns itself, as in - // type F func() F - // we have used ptr_type_node for the return type. Add a cast here - // to the correct type. - if (TREE_TYPE(ret) == ptr_type_node) - { - tree t = type_to_tree(this->type()->base()->get_backend(gogo)); - ret = fold_convert_loc(location.gcc_location(), t, ret); - } + Btype* bft = fntype->get_backend_fntype(gogo); + Bexpression* bfn = tree_to_expr(fn->get_tree(context)); + bfn = gogo->backend()->convert_expression(bft, bfn, location); + Bexpression* call = gogo->backend()->call_expression(bfn, fn_args, location); - if (excess_type != NULL_TREE) + if (this->results_ != NULL) { - // Calling convert here can undo our excess precision change. - // That may or may not be a bug in convert_to_real. - ret = build1(NOP_EXPR, rettype, ret); - } + go_assert(this->call_temp_ != NULL); + Expression* call_ref = + Expression::make_temporary_reference(this->call_temp_, location); + Bexpression* bcall_ref = tree_to_expr(call_ref->get_tree(context)); + Bstatement* assn_stmt = + gogo->backend()->assignment_statement(bcall_ref, call, location); - if (this->results_ != NULL) - ret = this->set_results(context, ret); + this->call_ = this->set_results(context, bcall_ref); - this->tree_ = ret; + Bexpression* set_and_call = + gogo->backend()->compound_expression(assn_stmt, this->call_, + location); + return expr_to_tree(set_and_call); + } - return ret; + this->call_ = call; + return expr_to_tree(this->call_); } // Set the result variables if this call returns multiple results. -tree -Call_expression::set_results(Translate_context* context, tree call_tree) +Bexpression* +Call_expression::set_results(Translate_context* context, Bexpression* call) { - tree stmt_list = NULL_TREE; - - call_tree = save_expr(call_tree); - - if (TREE_CODE(TREE_TYPE(call_tree)) != RECORD_TYPE) - { - go_assert(saw_errors()); - return call_tree; - } + Gogo* gogo = context->gogo(); + Bexpression* results = NULL; Location loc = this->location(); - tree field = TYPE_FIELDS(TREE_TYPE(call_tree)); + size_t rc = this->result_count(); - for (size_t i = 0; i < rc; ++i, field = DECL_CHAIN(field)) + for (size_t i = 0; i < rc; ++i) { - go_assert(field != NULL_TREE); - Temporary_statement* temp = this->result(i); if (temp == NULL) { go_assert(saw_errors()); - return error_mark_node; + return gogo->backend()->error_expression(); } Temporary_reference_expression* ref = Expression::make_temporary_reference(temp, loc); ref->set_is_lvalue(); - tree temp_tree = ref->get_tree(context); - if (temp_tree == error_mark_node) - return error_mark_node; - tree val_tree = build3_loc(loc.gcc_location(), COMPONENT_REF, - TREE_TYPE(field), call_tree, field, NULL_TREE); - tree set_tree = build2_loc(loc.gcc_location(), MODIFY_EXPR, - void_type_node, temp_tree, val_tree); + Bexpression* result_ref = tree_to_expr(ref->get_tree(context)); + Bexpression* call_result = + gogo->backend()->struct_field_expression(call, i, loc); + Bstatement* assn_stmt = + gogo->backend()->assignment_statement(result_ref, call_result, loc); - append_to_statement_list(set_tree, &stmt_list); - } - go_assert(field == NULL_TREE); + Bexpression* result = + gogo->backend()->compound_expression(assn_stmt, call_result, loc); - return save_expr(stmt_list); + if (results == NULL) + results = result; + else + { + Bstatement* expr_stmt = gogo->backend()->expression_statement(result); + results = + gogo->backend()->compound_expression(expr_stmt, results, loc); + } + } + return results; } // Dump ast representation for a call expressin. @@ -10333,6 +9982,9 @@ class Array_index_expression : public Expression int do_traverse(Traverse*); + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + Type* do_type(); @@ -10343,9 +9995,6 @@ class Array_index_expression : public Expression do_check_types(Gogo*); Expression* - do_flatten(Gogo*, Named_object*, Statement_inserter*); - - Expression* do_copy() { return Expression::make_array_index(this->array_->copy(), @@ -10586,19 +10235,41 @@ Array_index_expression::do_check_types(Gogo*) } } -// Flatten array indexing by using a temporary variable for slices. +// Flatten array indexing by using temporary variables for slices and indexes. Expression* Array_index_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) { Location loc = this->location(); + Temporary_statement* temp; if (this->array_->type()->is_slice_type() && !this->array_->is_variable()) { - Temporary_statement* temp = Statement::make_temporary(NULL, this->array_, loc); + temp = Statement::make_temporary(NULL, this->array_, loc); inserter->insert(temp); this->array_ = Expression::make_temporary_reference(temp, loc); } + if (!this->start_->is_variable()) + { + temp = Statement::make_temporary(NULL, this->start_, loc); + inserter->insert(temp); + this->start_ = Expression::make_temporary_reference(temp, loc); + } + if (this->end_ != NULL + && !this->end_->is_nil_expression() + && !this->end_->is_variable()) + { + temp = Statement::make_temporary(NULL, this->end_, loc); + inserter->insert(temp); + this->end_ = Expression::make_temporary_reference(temp, loc); + } + if (this->cap_ != NULL && !this->cap_->is_variable()) + { + temp = Statement::make_temporary(NULL, this->cap_, loc); + inserter->insert(temp); + this->cap_ = Expression::make_temporary_reference(temp, loc); + } + return this; } @@ -10625,9 +10296,6 @@ Array_index_expression::do_is_addressable() const tree Array_index_expression::do_get_tree(Translate_context* context) { - Gogo* gogo = context->gogo(); - Location loc = this->location(); - Array_type* array_type = this->array_->type()->array_type(); if (array_type == NULL) { @@ -10636,66 +10304,40 @@ Array_index_expression::do_get_tree(Translate_context* context) } go_assert(!array_type->is_slice_type() || this->array_->is_variable()); - tree type_tree = type_to_tree(array_type->get_backend(gogo)); - if (type_tree == error_mark_node) - return error_mark_node; + Location loc = this->location(); + Gogo* gogo = context->gogo(); + + Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo); - tree length_tree = NULL_TREE; + // We need to convert the length and capacity to the Go "int" type here + // because the length of a fixed-length array could be of type "uintptr" + // and gimple disallows binary operations between "uintptr" and other + // integer types. FIXME. + Bexpression* length = NULL; if (this->end_ == NULL || this->end_->is_nil_expression()) { Expression* len = array_type->get_length(gogo, this->array_); - length_tree = len->get_tree(context); - if (length_tree == error_mark_node) - return error_mark_node; - length_tree = save_expr(length_tree); + length = tree_to_expr(len->get_tree(context)); + length = gogo->backend()->convert_expression(int_btype, length, loc); } - tree capacity_tree = NULL_TREE; + Bexpression* capacity = NULL; if (this->end_ != NULL) { Expression* cap = array_type->get_capacity(gogo, this->array_); - capacity_tree = cap->get_tree(context); - if (capacity_tree == error_mark_node) - return error_mark_node; - capacity_tree = save_expr(capacity_tree); + capacity = tree_to_expr(cap->get_tree(context)); + capacity = gogo->backend()->convert_expression(int_btype, capacity, loc); } - tree cap_arg = capacity_tree; + Bexpression* cap_arg = capacity; if (this->cap_ != NULL) { - cap_arg = this->cap_->get_tree(context); - if (cap_arg == error_mark_node) - return error_mark_node; + cap_arg = tree_to_expr(this->cap_->get_tree(context)); + cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc); } - tree length_type = (length_tree != NULL_TREE - ? TREE_TYPE(length_tree) - : TREE_TYPE(cap_arg)); - - tree bad_index = boolean_false_node; - - tree start_tree = this->start_->get_tree(context); - if (start_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(start_tree)) - start_tree = save_expr(start_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree))) - start_tree = convert_to_integer(length_type, start_tree); - - bad_index = Expression::check_bounds(start_tree, length_type, bad_index, - loc); - - start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree); - bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, bad_index, - fold_build2_loc(loc.gcc_location(), - (this->end_ == NULL - ? GE_EXPR - : GT_EXPR), - boolean_type_node, start_tree, - (this->end_ == NULL - ? length_tree - : capacity_tree))); + if (length == NULL) + length = cap_arg; int code = (array_type->length() != NULL ? (this->end_ == NULL @@ -10704,168 +10346,124 @@ Array_index_expression::do_get_tree(Translate_context* context) : (this->end_ == NULL ? RUNTIME_ERROR_SLICE_INDEX_OUT_OF_BOUNDS : RUNTIME_ERROR_SLICE_SLICE_OUT_OF_BOUNDS)); - tree crash = gogo->runtime_error(code, loc)->get_tree(context); + Bexpression* crash = + tree_to_expr(gogo->runtime_error(code, loc)->get_tree(context)); + + Expression* bounds_check = Expression::check_bounds(this->start_, loc); + Bexpression* bad_index = tree_to_expr(bounds_check->get_tree(context)); + + Bexpression* start = tree_to_expr(this->start_->get_tree(context)); + start = gogo->backend()->convert_expression(int_btype, start, loc); + Bexpression* start_too_large = + gogo->backend()->binary_expression((this->end_ == NULL + ? OPERATOR_GE + : OPERATOR_GT), + start, + (this->end_ == NULL + ? length + : capacity), + loc); + bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, start_too_large, + bad_index, loc); if (this->end_ == NULL) { // Simple array indexing. This has to return an l-value, so - // wrap the index check into START_TREE. - start_tree = build2(COMPOUND_EXPR, TREE_TYPE(start_tree), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - start_tree); - start_tree = fold_convert_loc(loc.gcc_location(), sizetype, start_tree); + // wrap the index check into START. + start = + gogo->backend()->conditional_expression(int_btype, bad_index, + crash, start, loc); + Bexpression* ret; if (array_type->length() != NULL) { - // Fixed array. - tree array_tree = this->array_->get_tree(context); - if (array_tree == error_mark_node) - return error_mark_node; - return build4(ARRAY_REF, TREE_TYPE(type_tree), array_tree, - start_tree, NULL_TREE, NULL_TREE); + Bexpression* array = tree_to_expr(this->array_->get_tree(context)); + ret = gogo->backend()->array_index_expression(array, start, loc); } else { - // Open array. - Expression* valptr = + // Slice. + Expression* valptr = array_type->get_value_pointer(gogo, this->array_); - tree values = valptr->get_tree(context); - Type* element_type = array_type->element_type(); - Btype* belement_type = element_type->get_backend(gogo); - tree element_type_tree = type_to_tree(belement_type); - if (element_type_tree == error_mark_node) - return error_mark_node; - tree element_size = TYPE_SIZE_UNIT(element_type_tree); - tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype, - start_tree, element_size); - tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR, - TREE_TYPE(values), values, offset); - return build_fold_indirect_ref(ptr); + Bexpression* ptr = tree_to_expr(valptr->get_tree(context)); + ptr = gogo->backend()->pointer_offset_expression(ptr, start, loc); + ret = gogo->backend()->indirect_expression(ptr, true, loc); } + return expr_to_tree(ret); } // Array slice. if (this->cap_ != NULL) { - if (!DECL_P(cap_arg)) - cap_arg = save_expr(cap_arg); - if (!INTEGRAL_TYPE_P(TREE_TYPE(cap_arg))) - cap_arg = convert_to_integer(length_type, cap_arg); - - bad_index = Expression::check_bounds(cap_arg, length_type, bad_index, - loc); - cap_arg = fold_convert_loc(loc.gcc_location(), length_type, cap_arg); - - tree bad_cap = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, - fold_build2_loc(loc.gcc_location(), - LT_EXPR, boolean_type_node, - cap_arg, start_tree), - fold_build2_loc(loc.gcc_location(), - GT_EXPR, boolean_type_node, - cap_arg, capacity_tree)); - bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, bad_index, bad_cap); - } - - tree end_tree; + bounds_check = Expression::check_bounds(this->cap_, loc); + Bexpression* bounds_bcheck = + tree_to_expr(bounds_check->get_tree(context)); + bad_index = + gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck, + bad_index, loc); + cap_arg = gogo->backend()->convert_expression(int_btype, cap_arg, loc); + + Bexpression* cap_too_small = + gogo->backend()->binary_expression(OPERATOR_LT, cap_arg, start, loc); + Bexpression* cap_too_large = + gogo->backend()->binary_expression(OPERATOR_GT, cap_arg, capacity, loc); + Bexpression* bad_cap = + gogo->backend()->binary_expression(OPERATOR_OROR, cap_too_small, + cap_too_large, loc); + bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_cap, + bad_index, loc); + } + + Bexpression* end; if (this->end_->is_nil_expression()) - end_tree = length_tree; + end = length; else { - end_tree = this->end_->get_tree(context); - if (end_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(end_tree)) - end_tree = save_expr(end_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree))) - end_tree = convert_to_integer(length_type, end_tree); + bounds_check = Expression::check_bounds(this->end_, loc); + Bexpression* bounds_bcheck = + tree_to_expr(bounds_check->get_tree(context)); - bad_index = Expression::check_bounds(end_tree, length_type, bad_index, - loc); + bad_index = + gogo->backend()->binary_expression(OPERATOR_OROR, bounds_bcheck, + bad_index, loc); - end_tree = fold_convert_loc(loc.gcc_location(), length_type, end_tree); - - tree bad_end = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, - fold_build2_loc(loc.gcc_location(), - LT_EXPR, boolean_type_node, - end_tree, start_tree), - fold_build2_loc(loc.gcc_location(), - GT_EXPR, boolean_type_node, - end_tree, cap_arg)); - bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, bad_index, bad_end); + end = tree_to_expr(this->end_->get_tree(context)); + end = gogo->backend()->convert_expression(int_btype, end, loc); + Bexpression* end_too_small = + gogo->backend()->binary_expression(OPERATOR_LT, end, start, loc); + Bexpression* end_too_large = + gogo->backend()->binary_expression(OPERATOR_GT, end, cap_arg, loc); + Bexpression* bad_end = + gogo->backend()->binary_expression(OPERATOR_OROR, end_too_small, + end_too_large, loc); + bad_index = gogo->backend()->binary_expression(OPERATOR_OROR, bad_end, + bad_index, loc); } - - Type* element_type = array_type->element_type(); - tree element_type_tree = type_to_tree(element_type->get_backend(gogo)); - if (element_type_tree == error_mark_node) - return error_mark_node; - tree element_size = TYPE_SIZE_UNIT(element_type_tree); - - tree offset = fold_build2_loc(loc.gcc_location(), MULT_EXPR, sizetype, - fold_convert_loc(loc.gcc_location(), sizetype, - start_tree), - element_size); - Expression* valptr = array_type->get_value_pointer(gogo, this->array_); - tree value_pointer = valptr->get_tree(context); - if (value_pointer == error_mark_node) - return error_mark_node; - - value_pointer = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR, - TREE_TYPE(value_pointer), - value_pointer, offset); - - tree result_length_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR, - length_type, end_tree, start_tree); - - tree result_capacity_tree = fold_build2_loc(loc.gcc_location(), MINUS_EXPR, - length_type, cap_arg, start_tree); - - tree struct_tree = type_to_tree(this->type()->get_backend(gogo)); - go_assert(TREE_CODE(struct_tree) == RECORD_TYPE); - - vec *init; - vec_alloc (init, 3); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(struct_tree); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0); - elt->index = field; - elt->value = value_pointer; + Bexpression* val = tree_to_expr(valptr->get_tree(context)); + val = gogo->backend()->pointer_offset_expression(val, start, loc); - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); - elt->index = field; - elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field), - result_length_tree); + Bexpression* result_length = + gogo->backend()->binary_expression(OPERATOR_MINUS, end, start, loc); - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0); - elt->index = field; - elt->value = fold_convert_loc(loc.gcc_location(), TREE_TYPE(field), - result_capacity_tree); + Bexpression* result_capacity = + gogo->backend()->binary_expression(OPERATOR_MINUS, cap_arg, start, loc); - tree constructor = build_constructor(struct_tree, init); + Btype* struct_btype = this->type()->get_backend(gogo); + std::vector init; + init.push_back(val); + init.push_back(result_length); + init.push_back(result_capacity); - if (TREE_CONSTANT(value_pointer) - && TREE_CONSTANT(result_length_tree) - && TREE_CONSTANT(result_capacity_tree)) - TREE_CONSTANT(constructor) = 1; + Bexpression* ctor = + gogo->backend()->constructor_expression(struct_btype, init, loc); + Bexpression* ret = + gogo->backend()->conditional_expression(struct_btype, bad_index, + crash, ctor, loc); - return fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(constructor), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - constructor); + return expr_to_tree(ret); } // Dump ast representation for an array index expression. @@ -10903,6 +10501,9 @@ class String_index_expression : public Expression int do_traverse(Traverse*); + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + Type* do_type(); @@ -10963,6 +10564,36 @@ String_index_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +Expression* +String_index_expression::do_flatten(Gogo*, Named_object*, + Statement_inserter* inserter) +{ + Temporary_statement* temp; + Location loc = this->location(); + if (!this->string_->is_variable()) + { + temp = Statement::make_temporary(NULL, this->string_, loc); + inserter->insert(temp); + this->string_ = Expression::make_temporary_reference(temp, loc); + } + if (!this->start_->is_variable()) + { + temp = Statement::make_temporary(NULL, this->start_, loc); + inserter->insert(temp); + this->start_ = Expression::make_temporary_reference(temp, loc); + } + if (this->end_ != NULL + && !this->end_->is_nil_expression() + && !this->end_->is_variable()) + { + temp = Statement::make_temporary(NULL, this->end_, loc); + inserter->insert(temp); + this->end_ = Expression::make_temporary_reference(temp, loc); + } + + return this; +} + // Return the type of a string index. Type* @@ -11049,112 +10680,87 @@ tree String_index_expression::do_get_tree(Translate_context* context) { Location loc = this->location(); + Expression* string_arg = this->string_; + if (this->string_->type()->points_to() != NULL) + string_arg = Expression::make_unary(OPERATOR_MULT, this->string_, loc); - tree string_tree = this->string_->get_tree(context); - if (string_tree == error_mark_node) - return error_mark_node; + Expression* bad_index = Expression::check_bounds(this->start_, loc); - if (this->string_->type()->points_to() != NULL) - string_tree = build_fold_indirect_ref(string_tree); - if (!DECL_P(string_tree)) - string_tree = save_expr(string_tree); - tree string_type = TREE_TYPE(string_tree); + int code = (this->end_ == NULL + ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS + : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS); - tree length_tree = String_type::length_tree(context->gogo(), string_tree); - length_tree = save_expr(length_tree); + Gogo* gogo = context->gogo(); + Bexpression* crash = + tree_to_expr(gogo->runtime_error(code, loc)->get_tree(context)); Type* int_type = Type::lookup_integer_type("int"); - tree length_type = type_to_tree(int_type->get_backend(context->gogo())); - tree bad_index = boolean_false_node; + // It is possible that an error occurred earlier because the start index + // cannot be represented as an integer type. In this case, we shouldn't + // try casting the starting index into an integer since + // Type_conversion_expression will fail to get the backend representation. + // FIXME. + if (this->start_->type()->integer_type() == NULL + && !Type::are_convertible(int_type, this->start_->type(), NULL)) + { + go_assert(saw_errors()); + return error_mark_node; + } - tree start_tree = this->start_->get_tree(context); - if (start_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(start_tree)) - start_tree = save_expr(start_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(start_tree))) - start_tree = convert_to_integer(length_type, start_tree); + Expression* start = Expression::make_cast(int_type, this->start_, loc); - bad_index = Expression::check_bounds(start_tree, length_type, bad_index, - loc); + if (this->end_ == NULL) + { + Expression* length = + Expression::make_string_info(this->string_, STRING_INFO_LENGTH, loc); - start_tree = fold_convert_loc(loc.gcc_location(), length_type, start_tree); + Expression* start_too_large = + Expression::make_binary(OPERATOR_GE, start, length, loc); + bad_index = Expression::make_binary(OPERATOR_OROR, start_too_large, + bad_index, loc); + Expression* bytes = + Expression::make_string_info(this->string_, STRING_INFO_DATA, loc); - int code = (this->end_ == NULL - ? RUNTIME_ERROR_STRING_INDEX_OUT_OF_BOUNDS - : RUNTIME_ERROR_STRING_SLICE_OUT_OF_BOUNDS); - tree crash = context->gogo()->runtime_error(code, loc)->get_tree(context); + Bexpression* bstart = tree_to_expr(start->get_tree(context)); + Bexpression* ptr = tree_to_expr(bytes->get_tree(context)); + ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc); + Bexpression* index = gogo->backend()->indirect_expression(ptr, true, loc); - if (this->end_ == NULL) + Btype* byte_btype = bytes->type()->points_to()->get_backend(gogo); + Bexpression* index_error = tree_to_expr(bad_index->get_tree(context)); + Bexpression* ret = + gogo->backend()->conditional_expression(byte_btype, index_error, + crash, index, loc); + return expr_to_tree(ret); + } + + Expression* end = NULL; + if (this->end_->is_nil_expression()) { - bad_index = fold_build2_loc(loc.gcc_location(), TRUTH_OR_EXPR, - boolean_type_node, bad_index, - fold_build2_loc(loc.gcc_location(), GE_EXPR, - boolean_type_node, - start_tree, length_tree)); - - tree bytes_tree = String_type::bytes_tree(context->gogo(), string_tree); - tree ptr = fold_build2_loc(loc.gcc_location(), POINTER_PLUS_EXPR, - TREE_TYPE(bytes_tree), - bytes_tree, - fold_convert_loc(loc.gcc_location(), sizetype, - start_tree)); - tree index = build_fold_indirect_ref_loc(loc.gcc_location(), ptr); - - return build2(COMPOUND_EXPR, TREE_TYPE(index), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - index); + mpz_t neg_one; + mpz_init_set_si(neg_one, -1); + end = Expression::make_integer(&neg_one, int_type, loc); + mpz_clear(neg_one); } else { - tree end_tree; - if (this->end_->is_nil_expression()) - end_tree = build_int_cst(length_type, -1); - else - { - end_tree = this->end_->get_tree(context); - if (end_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(end_tree)) - end_tree = save_expr(end_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(end_tree))) - end_tree = convert_to_integer(length_type, end_tree); - - bad_index = Expression::check_bounds(end_tree, length_type, - bad_index, loc); - - end_tree = fold_convert_loc(loc.gcc_location(), length_type, - end_tree); - } - - static tree strslice_fndecl; - tree ret = Gogo::call_builtin(&strslice_fndecl, - loc, - "__go_string_slice", - 3, - string_type, - string_type, - string_tree, - length_type, - start_tree, - length_type, - end_tree); - if (ret == error_mark_node) - return error_mark_node; - // This will panic if the bounds are out of range for the - // string. - TREE_NOTHROW(strslice_fndecl) = 0; - - if (bad_index == boolean_false_node) - return ret; - else - return build2(COMPOUND_EXPR, TREE_TYPE(ret), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - ret); + Expression* bounds_check = Expression::check_bounds(this->end_, loc); + bad_index = + Expression::make_binary(OPERATOR_OROR, bounds_check, bad_index, loc); + end = Expression::make_cast(int_type, this->end_, loc); } + + Expression* strslice = Runtime::make_call(Runtime::STRING_SLICE, loc, 3, + string_arg, start, end); + Bexpression* bstrslice = tree_to_expr(strslice->get_tree(context)); + + Btype* str_btype = strslice->type()->get_backend(gogo); + Bexpression* index_error = tree_to_expr(bad_index->get_tree(context)); + Bexpression* ret = + gogo->backend()->conditional_expression(str_btype, index_error, + crash, bstrslice, loc); + return expr_to_tree(ret); } // Dump ast representation for a string index expression. @@ -11199,6 +10805,44 @@ Map_index_expression::do_traverse(Traverse* traverse) return Expression::traverse(&this->index_, traverse); } +// We need to pass in a pointer to the key, so flatten the index into a +// temporary variable if it isn't already. The value pointer will be +// dereferenced and checked for nil, so flatten into a temporary to avoid +// recomputation. + +Expression* +Map_index_expression::do_flatten(Gogo*, Named_object*, + Statement_inserter* inserter) +{ + Map_type* mt = this->get_map_type(); + if (this->index_->type() != mt->key_type()) + this->index_ = Expression::make_cast(mt->key_type(), this->index_, + this->location()); + + if (!this->index_->is_variable()) + { + Temporary_statement* temp = Statement::make_temporary(NULL, this->index_, + this->location()); + inserter->insert(temp); + this->index_ = Expression::make_temporary_reference(temp, + this->location()); + } + + if (this->value_pointer_ == NULL) + this->get_value_pointer(this->is_lvalue_); + if (!this->value_pointer_->is_variable()) + { + Temporary_statement* temp = + Statement::make_temporary(NULL, this->value_pointer_, + this->location()); + inserter->insert(temp); + this->value_pointer_ = + Expression::make_temporary_reference(temp, this->location()); + } + + return this; +} + // Return the type of a map index. Type* @@ -11258,131 +10902,84 @@ Map_index_expression::do_get_tree(Translate_context* context) { Map_type* type = this->get_map_type(); if (type == NULL) - return error_mark_node; - - tree valptr = this->get_value_pointer(context, this->is_lvalue_); - if (valptr == error_mark_node) - return error_mark_node; - valptr = save_expr(valptr); + { + go_assert(saw_errors()); + return error_mark_node; + } - tree val_type_tree = TREE_TYPE(TREE_TYPE(valptr)); + go_assert(this->value_pointer_ != NULL + && this->value_pointer_->is_variable()); + Bexpression* ret; if (this->is_lvalue_) - return build_fold_indirect_ref(valptr); + { + Expression* val = + Expression::make_unary(OPERATOR_MULT, this->value_pointer_, + this->location()); + ret = tree_to_expr(val->get_tree(context)); + } else if (this->is_in_tuple_assignment_) { // Tuple_map_assignment_statement is responsible for using this // appropriately. - return valptr; + ret = tree_to_expr(this->value_pointer_->get_tree(context)); } else { + Location loc = this->location(); + + Expression* nil_check = + Expression::make_binary(OPERATOR_EQEQ, this->value_pointer_, + Expression::make_nil(loc), loc); + Bexpression* bnil_check = tree_to_expr(nil_check->get_tree(context)); + Expression* val = + Expression::make_unary(OPERATOR_MULT, this->value_pointer_, loc); + Bexpression* bval = tree_to_expr(val->get_tree(context)); + Gogo* gogo = context->gogo(); Btype* val_btype = type->val_type()->get_backend(gogo); Bexpression* val_zero = gogo->backend()->zero_expression(val_btype); - return fold_build3(COND_EXPR, val_type_tree, - fold_build2(EQ_EXPR, boolean_type_node, valptr, - fold_convert(TREE_TYPE(valptr), - null_pointer_node)), - expr_to_tree(val_zero), - build_fold_indirect_ref(valptr)); + ret = gogo->backend()->conditional_expression(val_btype, bnil_check, + val_zero, bval, loc); } + + return expr_to_tree(ret); } -// Get a tree for the map index. This returns a tree which evaluates -// to a pointer to a value. The pointer will be NULL if the key is +// Get an expression for the map index. This returns an expression which +// evaluates to a pointer to a value. The pointer will be NULL if the key is // not in the map. -tree -Map_index_expression::get_value_pointer(Translate_context* context, - bool insert) +Expression* +Map_index_expression::get_value_pointer(bool insert) { - Map_type* type = this->get_map_type(); - if (type == NULL) - return error_mark_node; - - tree map_tree = this->map_->get_tree(context); - tree index_tree = this->index_->get_tree(context); - index_tree = Expression::convert_for_assignment(context, type->key_type(), - this->index_->type(), - index_tree, - this->location()); - if (map_tree == error_mark_node || index_tree == error_mark_node) - return error_mark_node; - - if (this->map_->type()->points_to() != NULL) - map_tree = build_fold_indirect_ref(map_tree); - - // We need to pass in a pointer to the key, so stuff it into a - // variable. - tree tmp; - tree make_tmp; - if (current_function_decl != NULL) + if (this->value_pointer_ == NULL) { - tmp = create_tmp_var(TREE_TYPE(index_tree), get_name(index_tree)); - DECL_IGNORED_P(tmp) = 0; - DECL_INITIAL(tmp) = index_tree; - make_tmp = build1(DECL_EXPR, void_type_node, tmp); - TREE_ADDRESSABLE(tmp) = 1; - } - else - { - tmp = build_decl(this->location().gcc_location(), VAR_DECL, - create_tmp_var_name("M"), - TREE_TYPE(index_tree)); - DECL_EXTERNAL(tmp) = 0; - TREE_PUBLIC(tmp) = 0; - TREE_STATIC(tmp) = 1; - DECL_ARTIFICIAL(tmp) = 1; - if (!TREE_CONSTANT(index_tree)) - make_tmp = fold_build2_loc(this->location().gcc_location(), - INIT_EXPR, void_type_node, - tmp, index_tree); - else + Map_type* type = this->get_map_type(); + if (type == NULL) { - TREE_READONLY(tmp) = 1; - TREE_CONSTANT(tmp) = 1; - DECL_INITIAL(tmp) = index_tree; - make_tmp = NULL_TREE; + go_assert(saw_errors()); + return Expression::make_error(this->location()); } - rest_of_decl_compilation(tmp, 1, 0); - } - tree tmpref = - fold_convert_loc(this->location().gcc_location(), const_ptr_type_node, - build_fold_addr_expr_loc(this->location().gcc_location(), - tmp)); - - static tree map_index_fndecl; - tree call = Gogo::call_builtin(&map_index_fndecl, - this->location(), - "__go_map_index", - 3, - const_ptr_type_node, - TREE_TYPE(map_tree), - map_tree, - const_ptr_type_node, - tmpref, - boolean_type_node, - (insert - ? boolean_true_node - : boolean_false_node)); - if (call == error_mark_node) - return error_mark_node; - // This can panic on a map of interface type if the interface holds - // an uncomparable or unhashable type. - TREE_NOTHROW(map_index_fndecl) = 0; - Type* val_type = type->val_type(); - tree val_type_tree = type_to_tree(val_type->get_backend(context->gogo())); - if (val_type_tree == error_mark_node) - return error_mark_node; - tree ptr_val_type_tree = build_pointer_type(val_type_tree); + Location loc = this->location(); + Expression* map_ref = this->map_; + if (this->map_->type()->points_to() != NULL) + map_ref = Expression::make_unary(OPERATOR_MULT, map_ref, loc); - tree ret = fold_convert_loc(this->location().gcc_location(), - ptr_val_type_tree, call); - if (make_tmp != NULL_TREE) - ret = build2(COMPOUND_EXPR, ptr_val_type_tree, make_tmp, ret); - return ret; + Expression* index_ptr = Expression::make_unary(OPERATOR_AND, this->index_, + loc); + Expression* map_index = + Runtime::make_call(Runtime::MAP_INDEX, loc, 3, + map_ref, index_ptr, + Expression::make_boolean(insert, loc)); + + Type* val_type = type->val_type(); + this->value_pointer_ = + Expression::make_unsafe_cast(Type::make_pointer_type(val_type), + map_index, this->location()); + } + return this->value_pointer_; } // Dump ast representation for a map index expression @@ -11841,7 +11438,7 @@ Interface_field_reference_expression::do_get_tree(Translate_context* context) vals->push_back(this->expr_); Expression* expr = Expression::make_struct_composite_literal(st, vals, loc); - expr = Expression::make_heap_composite(expr, loc); + expr = Expression::make_heap_expression(expr, loc); Bexpression* bclosure = tree_to_expr(expr->get_tree(context)); Expression* nil_check = @@ -12193,15 +11790,13 @@ class Allocation_expression : public Expression tree Allocation_expression::do_get_tree(Translate_context* context) { - tree type_tree = type_to_tree(this->type_->get_backend(context->gogo())); - if (type_tree == error_mark_node) - return error_mark_node; - tree size_tree = TYPE_SIZE_UNIT(type_tree); - tree space = context->gogo()->allocate_memory(this->type_, size_tree, - this->location()); - if (space == error_mark_node) - return error_mark_node; - return fold_convert(build_pointer_type(type_tree), space); + Gogo* gogo = context->gogo(); + Location loc = this->location(); + Expression* space = gogo->allocate_memory(this->type_, loc); + Bexpression* bspace = tree_to_expr(space->get_tree(context)); + Btype* pbtype = gogo->backend()->pointer_type(this->type_->get_backend(gogo)); + Bexpression* ret = gogo->backend()->convert_expression(pbtype, bspace, loc); + return expr_to_tree(ret); } // Dump ast representation for an allocation expression. @@ -12453,64 +12048,38 @@ Struct_construction_expression::do_get_tree(Translate_context* context) { Gogo* gogo = context->gogo(); + Btype* btype = this->type_->get_backend(gogo); if (this->vals_ == NULL) - { - Btype* btype = this->type_->get_backend(gogo); - return expr_to_tree(gogo->backend()->zero_expression(btype)); - } - - tree type_tree = type_to_tree(this->type_->get_backend(gogo)); - if (type_tree == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(type_tree) == RECORD_TYPE); + return expr_to_tree(gogo->backend()->zero_expression(btype)); - bool is_constant = true; const Struct_field_list* fields = this->type_->struct_type()->fields(); - vec *elts; - vec_alloc (elts, fields->size()); - Struct_field_list::const_iterator pf = fields->begin(); Expression_list::const_iterator pv = this->vals_->begin(); - for (tree field = TYPE_FIELDS(type_tree); - field != NULL_TREE; - field = DECL_CHAIN(field), ++pf) + std::vector init; + for (Struct_field_list::const_iterator pf = fields->begin(); + pf != fields->end(); + ++pf) { - go_assert(pf != fields->end()); - Btype* fbtype = pf->type()->get_backend(gogo); - - tree val; if (pv == this->vals_->end()) - val = expr_to_tree(gogo->backend()->zero_expression(fbtype)); + init.push_back(gogo->backend()->zero_expression(fbtype)); else if (*pv == NULL) { - val = expr_to_tree(gogo->backend()->zero_expression(fbtype)); + init.push_back(gogo->backend()->zero_expression(fbtype)); ++pv; } else { - val = Expression::convert_for_assignment(context, pf->type(), - (*pv)->type(), - (*pv)->get_tree(context), - this->location()); + Expression* val = + Expression::convert_for_assignment(gogo, pf->type(), + *pv, this->location()); + init.push_back(tree_to_expr(val->get_tree(context))); ++pv; } - - if (val == error_mark_node || TREE_TYPE(val) == error_mark_node) - return error_mark_node; - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = elts->quick_push(empty); - elt->index = field; - elt->value = val; - if (!TREE_CONSTANT(val)) - is_constant = false; } - go_assert(pf == fields->end()); - tree ret = build_constructor(type_tree, elts); - if (is_constant) - TREE_CONSTANT(ret) = 1; - return ret; + Bexpression* ret = + gogo->backend()->constructor_expression(btype, init, this->location()); + return expr_to_tree(ret); } // Export a struct construction. @@ -12555,7 +12124,7 @@ Expression::make_struct_composite_literal(Type* type, Expression_list* vals, // Construct an array. This class is not used directly; instead we // use the child classes, Fixed_array_construction_expression and -// Open_array_construction_expression. +// Slice_construction_expression. class Array_construction_expression : public Expression { @@ -12608,9 +12177,9 @@ protected: vals() { return this->vals_; } - // Get a constructor tree for the array values. - tree - get_constructor_tree(Translate_context* context, tree type_tree); + // Get the backend constructor for the array values. + Bexpression* + get_constructor(Translate_context* context, Btype* btype); void do_dump_expression(Ast_dump_context*) const; @@ -12723,16 +12292,17 @@ Array_construction_expression::do_check_types(Gogo*) } } -// Get a constructor tree for the array values. +// Get a constructor expression for the array values. -tree -Array_construction_expression::get_constructor_tree(Translate_context* context, - tree type_tree) +Bexpression* +Array_construction_expression::get_constructor(Translate_context* context, + Btype* array_btype) { - vec *values; - vec_alloc (values, (this->vals_ == NULL ? 0 : this->vals_->size())); Type* element_type = this->type_->array_type()->element_type(); - bool is_constant = true; + + std::vector indexes; + std::vector vals; + Gogo* gogo = context->gogo(); if (this->vals_ != NULL) { size_t i = 0; @@ -12745,45 +12315,32 @@ Array_construction_expression::get_constructor_tree(Translate_context* context, { if (this->indexes_ != NULL) go_assert(pi != this->indexes_->end()); - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = values->quick_push(empty); if (this->indexes_ == NULL) - elt->index = size_int(i); + indexes.push_back(i); else - elt->index = size_int(*pi); - + indexes.push_back(*pi); if (*pv == NULL) { - Gogo* gogo = context->gogo(); Btype* ebtype = element_type->get_backend(gogo); Bexpression *zv = gogo->backend()->zero_expression(ebtype); - elt->value = expr_to_tree(zv); + vals.push_back(zv); } else { - tree value_tree = (*pv)->get_tree(context); - elt->value = Expression::convert_for_assignment(context, - element_type, - (*pv)->type(), - value_tree, - this->location()); + Expression* val_expr = + Expression::convert_for_assignment(gogo, element_type, *pv, + this->location()); + vals.push_back(tree_to_expr(val_expr->get_tree(context))); } - if (elt->value == error_mark_node) - return error_mark_node; - if (!TREE_CONSTANT(elt->value)) - is_constant = false; if (this->indexes_ != NULL) ++pi; } if (this->indexes_ != NULL) go_assert(pi == this->indexes_->end()); } - - tree ret = build_constructor(type_tree, values); - if (is_constant) - TREE_CONSTANT(ret) = 1; - return ret; + return gogo->backend()->array_constructor_expression(array_btype, indexes, + vals, this->location()); } // Export an array construction. @@ -12894,43 +12451,47 @@ Fixed_array_construction_expression::do_get_tree(Translate_context* context) { Type* type = this->type(); Btype* btype = type->get_backend(context->gogo()); - return this->get_constructor_tree(context, type_to_tree(btype)); + return expr_to_tree(this->get_constructor(context, btype)); } -// Construct an open array. +// Construct a slice. -class Open_array_construction_expression : public Array_construction_expression +class Slice_construction_expression : public Array_construction_expression { public: - Open_array_construction_expression(Type* type, - const std::vector* indexes, - Expression_list* vals, Location location) - : Array_construction_expression(EXPRESSION_OPEN_ARRAY_CONSTRUCTION, - type, indexes, vals, location) + Slice_construction_expression(Type* type, + const std::vector* indexes, + Expression_list* vals, Location location) + : Array_construction_expression(EXPRESSION_SLICE_CONSTRUCTION, + type, indexes, vals, location), + valtype_(NULL) { go_assert(type->is_slice_type()); } protected: - // Note that taking the address of an open array literal is invalid. + // Note that taking the address of a slice literal is invalid. Expression* do_copy() { - return new Open_array_construction_expression(this->type(), - this->indexes(), - (this->vals() == NULL - ? NULL - : this->vals()->copy()), - this->location()); + return new Slice_construction_expression(this->type(), this->indexes(), + (this->vals() == NULL + ? NULL + : this->vals()->copy()), + this->location()); } tree do_get_tree(Translate_context*); + + private: + // The type of the values in this slice. + Type* valtype_; }; -// Return a tree for constructing an open array. +// Return a tree for constructing a slice. tree -Open_array_construction_expression::do_get_tree(Translate_context* context) +Slice_construction_expression::do_get_tree(Translate_context* context) { Array_type* array_type = this->type()->array_type(); if (array_type == NULL) @@ -12940,49 +12501,43 @@ Open_array_construction_expression::do_get_tree(Translate_context* context) } Type* element_type = array_type->element_type(); - Btype* belement_type = element_type->get_backend(context->gogo()); - tree element_type_tree = type_to_tree(belement_type); - if (element_type_tree == error_mark_node) - return error_mark_node; + if (this->valtype_ == NULL) + { + mpz_t lenval; + Expression* length; + if (this->vals() == NULL || this->vals()->empty()) + mpz_init_set_ui(lenval, 0); + else + { + if (this->indexes() == NULL) + mpz_init_set_ui(lenval, this->vals()->size()); + else + mpz_init_set_ui(lenval, this->indexes()->back() + 1); + } + Location loc = this->location(); + Type* int_type = Type::lookup_integer_type("int"); + length = Expression::make_integer(&lenval, int_type, loc); + mpz_clear(lenval); + this->valtype_ = Type::make_array_type(element_type, length); + } tree values; - tree length_tree; + Gogo* gogo = context->gogo(); + Btype* val_btype = this->valtype_->get_backend(gogo); if (this->vals() == NULL || this->vals()->empty()) { // We need to create a unique value. - tree max = size_int(0); - tree constructor_type = build_array_type(element_type_tree, - build_index_type(max)); - if (constructor_type == error_mark_node) - return error_mark_node; - vec *vec; - vec_alloc(vec, 1); - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = vec->quick_push(empty); - elt->index = size_int(0); - Gogo* gogo = context->gogo(); - Btype* btype = element_type->get_backend(gogo); - elt->value = expr_to_tree(gogo->backend()->zero_expression(btype)); - values = build_constructor(constructor_type, vec); - if (TREE_CONSTANT(elt->value)) - TREE_CONSTANT(values) = 1; - length_tree = size_int(0); + Btype* int_btype = Type::lookup_integer_type("int")->get_backend(gogo); + Bexpression* zero = gogo->backend()->zero_expression(int_btype); + std::vector index(1, 0); + std::vector val(1, zero); + Bexpression* ctor = + gogo->backend()->array_constructor_expression(val_btype, index, val, + this->location()); + values = expr_to_tree(ctor); } else - { - unsigned long max_index; - if (this->indexes() == NULL) - max_index = this->vals()->size() - 1; - else - max_index = this->indexes()->back(); - tree max_tree = size_int(max_index); - tree constructor_type = build_array_type(element_type_tree, - build_index_type(max_tree)); - if (constructor_type == error_mark_node) - return error_mark_node; - values = this->get_constructor_tree(context, constructor_type); - length_tree = size_int(max_index + 1); - } + values = expr_to_tree(this->get_constructor(context, val_btype)); if (values == error_mark_node) return error_mark_node; @@ -13030,10 +12585,9 @@ Open_array_construction_expression::do_get_tree(Translate_context* context) } else { - tree memsize = TYPE_SIZE_UNIT(TREE_TYPE(values)); - space = context->gogo()->allocate_memory(element_type, memsize, - this->location()); - space = save_expr(space); + Expression* alloc = + context->gogo()->allocate_memory(this->valtype_, this->location()); + space = save_expr(alloc->get_tree(context)); tree s = fold_convert(build_pointer_type(TREE_TYPE(values)), space); tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(), @@ -13042,7 +12596,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context) set = build2(MODIFY_EXPR, void_type_node, ref, values); } - // Build a constructor for the open array. + // Build a constructor for the slice. tree type_tree = type_to_tree(this->type()->get_backend(context->gogo())); if (type_tree == error_mark_node) @@ -13059,6 +12613,7 @@ Open_array_construction_expression::do_get_tree(Translate_context* context) elt->index = field; elt->value = fold_convert(TREE_TYPE(field), space); + tree length_tree = this->valtype_->array_type()->length()->get_tree(context); elt = init->quick_push(empty); field = DECL_CHAIN(field); go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); @@ -13091,7 +12646,7 @@ Expression::make_slice_composite_literal(Type* type, Expression_list* vals, Location location) { go_assert(type->is_slice_type()); - return new Open_array_construction_expression(type, NULL, vals, location); + return new Slice_construction_expression(type, NULL, vals, location); } // Construct a map. @@ -13102,13 +12657,16 @@ class Map_construction_expression : public Expression Map_construction_expression(Type* type, Expression_list* vals, Location location) : Expression(EXPRESSION_MAP_CONSTRUCTION, location), - type_(type), vals_(vals) + type_(type), vals_(vals), element_type_(NULL), constructor_temp_(NULL) { go_assert(vals == NULL || vals->size() % 2 == 0); } protected: int do_traverse(Traverse* traverse); + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + Type* do_type() { return this->type_; } @@ -13140,6 +12698,10 @@ class Map_construction_expression : public Expression Type* type_; // The list of values. Expression_list* vals_; + // The type of the key-value pair struct for each map element. + Struct_type* element_type_; + // A temporary reference to the variable storing the constructor initializer. + Temporary_statement* constructor_temp_; }; // Traversal. @@ -13155,6 +12717,69 @@ Map_construction_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +// Flatten constructor initializer into a temporary variable since +// we need to take its address for __go_construct_map. + +Expression* +Map_construction_expression::do_flatten(Gogo* gogo, Named_object*, + Statement_inserter* inserter) +{ + if (!this->is_error_expression() + && this->vals_ != NULL + && !this->vals_->empty() + && this->constructor_temp_ == NULL) + { + Map_type* mt = this->type_->map_type(); + Type* key_type = mt->key_type(); + Type* val_type = mt->val_type(); + this->element_type_ = Type::make_builtin_struct_type(2, + "__key", key_type, + "__val", val_type); + + Expression_list* value_pairs = new Expression_list(); + Location loc = this->location(); + + size_t i = 0; + for (Expression_list::const_iterator pv = this->vals_->begin(); + pv != this->vals_->end(); + ++pv, ++i) + { + Expression_list* key_value_pair = new Expression_list(); + Expression* key = + Expression::convert_for_assignment(gogo, key_type, *pv, loc); + + ++pv; + Expression* val = + Expression::convert_for_assignment(gogo, val_type, *pv, loc); + + key_value_pair->push_back(key); + key_value_pair->push_back(val); + value_pairs->push_back( + Expression::make_struct_composite_literal(this->element_type_, + key_value_pair, loc)); + } + + mpz_t lenval; + mpz_init_set_ui(lenval, i); + Expression* element_count = Expression::make_integer(&lenval, NULL, loc); + mpz_clear(lenval); + + Type* ctor_type = + Type::make_array_type(this->element_type_, element_count); + Expression* constructor = + new Fixed_array_construction_expression(ctor_type, NULL, + value_pairs, loc); + + this->constructor_temp_ = + Statement::make_temporary(NULL, constructor, loc); + constructor->issue_nil_check(); + this->constructor_temp_->set_is_address_taken(); + inserter->insert(this->constructor_temp_); + } + + return this; +} + // Final type determination. void @@ -13216,167 +12841,53 @@ Map_construction_expression::do_check_types(Gogo*) tree Map_construction_expression::do_get_tree(Translate_context* context) { - Gogo* gogo = context->gogo(); - Location loc = this->location(); - - Map_type* mt = this->type_->map_type(); - - // Build a struct to hold the key and value. - tree struct_type = make_node(RECORD_TYPE); - - Type* key_type = mt->key_type(); - tree id = get_identifier("__key"); - tree key_type_tree = type_to_tree(key_type->get_backend(gogo)); - if (key_type_tree == error_mark_node) - return error_mark_node; - tree key_field = build_decl(loc.gcc_location(), FIELD_DECL, id, - key_type_tree); - DECL_CONTEXT(key_field) = struct_type; - TYPE_FIELDS(struct_type) = key_field; - - Type* val_type = mt->val_type(); - id = get_identifier("__val"); - tree val_type_tree = type_to_tree(val_type->get_backend(gogo)); - if (val_type_tree == error_mark_node) + if (this->is_error_expression()) return error_mark_node; - tree val_field = build_decl(loc.gcc_location(), FIELD_DECL, id, - val_type_tree); - DECL_CONTEXT(val_field) = struct_type; - DECL_CHAIN(key_field) = val_field; - - layout_type(struct_type); + Location loc = this->location(); - bool is_constant = true; size_t i = 0; - tree valaddr; - tree make_tmp; - + Expression* ventries; if (this->vals_ == NULL || this->vals_->empty()) - { - valaddr = null_pointer_node; - make_tmp = NULL_TREE; - } + ventries = Expression::make_nil(loc); else { - vec *values; - vec_alloc(values, this->vals_->size() / 2); - - for (Expression_list::const_iterator pv = this->vals_->begin(); - pv != this->vals_->end(); - ++pv, ++i) - { - bool one_is_constant = true; - - vec *one; - vec_alloc(one, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = one->quick_push(empty); - elt->index = key_field; - tree val_tree = (*pv)->get_tree(context); - elt->value = Expression::convert_for_assignment(context, key_type, - (*pv)->type(), - val_tree, loc); - if (elt->value == error_mark_node) - return error_mark_node; - if (!TREE_CONSTANT(elt->value)) - one_is_constant = false; - - ++pv; - - elt = one->quick_push(empty); - elt->index = val_field; - val_tree = (*pv)->get_tree(context); - elt->value = Expression::convert_for_assignment(context, val_type, - (*pv)->type(), - val_tree, loc); - if (elt->value == error_mark_node) - return error_mark_node; - if (!TREE_CONSTANT(elt->value)) - one_is_constant = false; - - elt = values->quick_push(empty); - elt->index = size_int(i); - elt->value = build_constructor(struct_type, one); - if (one_is_constant) - TREE_CONSTANT(elt->value) = 1; - else - is_constant = false; - } - - tree index_type = build_index_type(size_int(i - 1)); - tree array_type = build_array_type(struct_type, index_type); - tree init = build_constructor(array_type, values); - if (is_constant) - TREE_CONSTANT(init) = 1; - tree tmp; - if (current_function_decl != NULL) - { - tmp = create_tmp_var(array_type, get_name(array_type)); - DECL_INITIAL(tmp) = init; - make_tmp = fold_build1_loc(loc.gcc_location(), DECL_EXPR, - void_type_node, tmp); - TREE_ADDRESSABLE(tmp) = 1; - } - else - { - tmp = build_decl(loc.gcc_location(), VAR_DECL, - create_tmp_var_name("M"), array_type); - DECL_EXTERNAL(tmp) = 0; - TREE_PUBLIC(tmp) = 0; - TREE_STATIC(tmp) = 1; - DECL_ARTIFICIAL(tmp) = 1; - if (!TREE_CONSTANT(init)) - make_tmp = fold_build2_loc(loc.gcc_location(), INIT_EXPR, - void_type_node, tmp, init); - else - { - TREE_READONLY(tmp) = 1; - TREE_CONSTANT(tmp) = 1; - DECL_INITIAL(tmp) = init; - make_tmp = NULL_TREE; - } - rest_of_decl_compilation(tmp, 1, 0); - } + go_assert(this->constructor_temp_ != NULL); + i = this->vals_->size() / 2; - valaddr = build_fold_addr_expr(tmp); + Expression* ctor_ref = + Expression::make_temporary_reference(this->constructor_temp_, loc); + ventries = Expression::make_unary(OPERATOR_AND, ctor_ref, loc); } - Bexpression* bdescriptor = mt->map_descriptor_pointer(gogo, loc); - tree descriptor = expr_to_tree(bdescriptor); - - tree type_tree = type_to_tree(this->type_->get_backend(gogo)); - if (type_tree == error_mark_node) - return error_mark_node; - - static tree construct_map_fndecl; - tree call = Gogo::call_builtin(&construct_map_fndecl, - loc, - "__go_construct_map", - 6, - type_tree, - TREE_TYPE(descriptor), - descriptor, - sizetype, - size_int(i), - sizetype, - TYPE_SIZE_UNIT(struct_type), - sizetype, - byte_position(val_field), - sizetype, - TYPE_SIZE_UNIT(TREE_TYPE(val_field)), - const_ptr_type_node, - fold_convert(const_ptr_type_node, valaddr)); - if (call == error_mark_node) - return error_mark_node; - - tree ret; - if (make_tmp == NULL) - ret = call; - else - ret = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, type_tree, - make_tmp, call); - return ret; + Map_type* mt = this->type_->map_type(); + if (this->element_type_ == NULL) + this->element_type_ = + Type::make_builtin_struct_type(2, + "__key", mt->key_type(), + "__val", mt->val_type()); + Expression* descriptor = Expression::make_map_descriptor(mt, loc); + + Type* uintptr_t = Type::lookup_integer_type("uintptr"); + mpz_t countval; + mpz_init_set_ui(countval, i); + Expression* count = Expression::make_integer(&countval, uintptr_t, loc); + mpz_clear(countval); + + Expression* entry_size = + Expression::make_type_info(this->element_type_, TYPE_INFO_SIZE); + + unsigned int field_index; + const Struct_field* valfield = + this->element_type_->find_local_field("__val", &field_index); + Expression* val_offset = + Expression::make_struct_field_offset(this->element_type_, valfield); + Expression* val_size = + Expression::make_type_info(mt->val_type(), TYPE_INFO_SIZE); + + Expression* map_ctor = + Runtime::make_call(Runtime::CONSTRUCT_MAP, loc, 6, descriptor, count, + entry_size, val_offset, val_size, ventries); + return map_ctor->get_tree(context); } // Export an array construction. @@ -13589,7 +13100,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function, } if (is_pointer) - ret = Expression::make_heap_composite(ret, this->location()); + ret = Expression::make_heap_expression(ret, this->location()); return ret; } @@ -14031,8 +13542,7 @@ Composite_literal_expression::make_array( return new Fixed_array_construction_expression(type, indexes, vals, location); else - return new Open_array_construction_expression(type, indexes, vals, - location); + return new Slice_construction_expression(type, indexes, vals, location); } // Lower a map composite literal. @@ -14112,7 +13622,7 @@ Expression::is_composite_literal() const case EXPRESSION_COMPOSITE_LITERAL: case EXPRESSION_STRUCT_CONSTRUCTION: case EXPRESSION_FIXED_ARRAY_CONSTRUCTION: - case EXPRESSION_OPEN_ARRAY_CONSTRUCTION: + case EXPRESSION_SLICE_CONSTRUCTION: case EXPRESSION_MAP_CONSTRUCTION: return true; default: @@ -14140,10 +13650,10 @@ Expression::is_nonconstant_composite_literal() const static_cast(this); return !pace->is_constant_array(); } - case EXPRESSION_OPEN_ARRAY_CONSTRUCTION: + case EXPRESSION_SLICE_CONSTRUCTION: { - const Open_array_construction_expression *pace = - static_cast(this); + const Slice_construction_expression *pace = + static_cast(this); return !pace->is_constant_array(); } case EXPRESSION_MAP_CONSTRUCTION: @@ -14195,6 +13705,21 @@ Type_guard_expression::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } +Expression* +Type_guard_expression::do_flatten(Gogo*, Named_object*, + Statement_inserter* inserter) +{ + if (!this->expr_->is_variable()) + { + Temporary_statement* temp = Statement::make_temporary(NULL, this->expr_, + this->location()); + inserter->insert(temp); + this->expr_ = + Expression::make_temporary_reference(temp, this->location()); + } + return this; +} + // Check types of a type guard expression. The expression must have // an interface type, but the actual type conversion is checked at run // time. @@ -14236,24 +13761,23 @@ Type_guard_expression::do_check_types(Gogo*) tree Type_guard_expression::do_get_tree(Translate_context* context) { - tree expr_tree = this->expr_->get_tree(context); - if (expr_tree == error_mark_node) - return error_mark_node; + Expression* conversion; if (this->type_->interface_type() != NULL) - return Expression::convert_interface_to_interface(context, this->type_, - this->expr_->type(), - expr_tree, true, - this->location()); + conversion = + Expression::convert_interface_to_interface(this->type_, this->expr_, + true, this->location()); else - return Expression::convert_for_assignment(context, this->type_, - this->expr_->type(), expr_tree, - this->location()); + conversion = + Expression::convert_for_assignment(context->gogo(), this->type_, + this->expr_, this->location()); + + return conversion->get_tree(context); } // Dump ast representation for a type guard expression. void -Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context) +Type_guard_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { this->expr_->dump_expression(ast_dump_context); @@ -14270,16 +13794,16 @@ Expression::make_type_guard(Expression* expr, Type* type, return new Type_guard_expression(expr, type, location); } -// Class Heap_composite_expression. +// Class Heap_expression. -// When you take the address of a composite literal, it is allocated +// When you take the address of an escaping expression, it is allocated // on the heap. This class implements that. -class Heap_composite_expression : public Expression +class Heap_expression : public Expression { public: - Heap_composite_expression(Expression* expr, Location location) - : Expression(EXPRESSION_HEAP_COMPOSITE, location), + Heap_expression(Expression* expr, Location location) + : Expression(EXPRESSION_HEAP, location), expr_(expr) { } @@ -14299,8 +13823,8 @@ class Heap_composite_expression : public Expression Expression* do_copy() { - return Expression::make_heap_composite(this->expr_->copy(), - this->location()); + return Expression::make_heap_expression(this->expr_->copy(), + this->location()); } tree @@ -14316,38 +13840,45 @@ class Heap_composite_expression : public Expression do_dump_expression(Ast_dump_context*) const; private: - // The composite literal which is being put on the heap. + // The expression which is being put on the heap. Expression* expr_; }; -// Return a tree which allocates a composite literal on the heap. +// Return a tree which allocates an expression on the heap. tree -Heap_composite_expression::do_get_tree(Translate_context* context) +Heap_expression::do_get_tree(Translate_context* context) { tree expr_tree = this->expr_->get_tree(context); if (expr_tree == error_mark_node || TREE_TYPE(expr_tree) == error_mark_node) return error_mark_node; - tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree)); - go_assert(TREE_CODE(expr_size) == INTEGER_CST); - tree space = context->gogo()->allocate_memory(this->expr_->type(), - expr_size, this->location()); - space = fold_convert(build_pointer_type(TREE_TYPE(expr_tree)), space); + + Expression* alloc = + Expression::make_allocation(this->expr_->type(), this->location()); + + Gogo* gogo = context->gogo(); + Btype* btype = this->expr_->type()->get_backend(gogo); + size_t expr_size = gogo->backend()->type_size(btype); + tree space = alloc->get_tree(context); + if (expr_size == 0) + return space; + space = save_expr(space); tree ref = build_fold_indirect_ref_loc(this->location().gcc_location(), space); TREE_THIS_NOTRAP(ref) = 1; - tree ret = build2(COMPOUND_EXPR, TREE_TYPE(space), + tree ret = build2(COMPOUND_EXPR, + type_to_tree(this->type()->get_backend(gogo)), build2(MODIFY_EXPR, void_type_node, ref, expr_tree), space); SET_EXPR_LOCATION(ret, this->location().gcc_location()); return ret; } -// Dump ast representation for a heap composite expression. +// Dump ast representation for a heap expression. void -Heap_composite_expression::do_dump_expression( +Heap_expression::do_dump_expression( Ast_dump_context* ast_dump_context) const { ast_dump_context->ostream() << "&("; @@ -14355,12 +13886,12 @@ Heap_composite_expression::do_dump_expression( ast_dump_context->ostream() << ")"; } -// Allocate a composite literal on the heap. +// Allocate an expression on the heap. Expression* -Expression::make_heap_composite(Expression* expr, Location location) +Expression::make_heap_expression(Expression* expr, Location location) { - return new Heap_composite_expression(expr, location); + return new Heap_expression(expr, location); } // Class Receive_expression. @@ -14399,32 +13930,57 @@ Receive_expression::do_check_types(Gogo*) } } -// Get a tree for a receive expression. +// Flattening for receive expressions creates a temporary variable to store +// received data in for receives. -tree -Receive_expression::do_get_tree(Translate_context* context) +Expression* +Receive_expression::do_flatten(Gogo*, Named_object*, + Statement_inserter* inserter) { - Location loc = this->location(); - Channel_type* channel_type = this->channel_->type()->channel_type(); if (channel_type == NULL) { - go_assert(this->channel_->type()->is_error()); - return error_mark_node; + go_assert(saw_errors()); + return this; } - Expression* td = Expression::make_type_descriptor(channel_type, loc); - tree td_tree = td->get_tree(context); - Type* element_type = channel_type->element_type(); - Btype* element_type_btype = element_type->get_backend(context->gogo()); - tree element_type_tree = type_to_tree(element_type_btype); - - tree channel = this->channel_->get_tree(context); - if (element_type_tree == error_mark_node || channel == error_mark_node) - return error_mark_node; + if (this->temp_receiver_ == NULL) + { + this->temp_receiver_ = Statement::make_temporary(element_type, NULL, + this->location()); + this->temp_receiver_->set_is_address_taken(); + inserter->insert(this->temp_receiver_); + } + + return this; +} + +// Get a tree for a receive expression. + +tree +Receive_expression::do_get_tree(Translate_context* context) +{ + Location loc = this->location(); + + Channel_type* channel_type = this->channel_->type()->channel_type(); + if (channel_type == NULL) + { + go_assert(this->channel_->type()->is_error()); + return error_mark_node; + } + Expression* td = Expression::make_type_descriptor(channel_type, loc); - return Gogo::receive_from_channel(element_type_tree, td_tree, channel, loc); + Expression* recv_ref = + Expression::make_temporary_reference(this->temp_receiver_, loc); + Expression* recv_addr = + Expression::make_temporary_reference(this->temp_receiver_, loc); + recv_addr = Expression::make_unary(OPERATOR_AND, recv_addr, loc); + Expression* recv = + Runtime::make_call(Runtime::RECEIVE, loc, 3, + td, this->channel_, recv_addr); + recv = Expression::make_compound(recv, recv_ref, loc); + return recv->get_tree(context); } // Dump ast representation for a receive expression. @@ -14725,6 +14281,101 @@ Expression::make_slice_info(Expression* slice, Slice_info slice_info, return new Slice_info_expression(slice, slice_info, location); } +// An expression that represents a slice value: a struct with value pointer, +// length, and capacity fields. + +class Slice_value_expression : public Expression +{ + public: + Slice_value_expression(Type* type, Expression* valptr, Expression* len, + Expression* cap, Location location) + : Expression(EXPRESSION_SLICE_VALUE, location), + type_(type), valptr_(valptr), len_(len), cap_(cap) + { } + + protected: + int + do_traverse(Traverse*); + + Type* + do_type() + { return this->type_; } + + void + do_determine_type(const Type_context*) + { go_unreachable(); } + + Expression* + do_copy() + { + return new Slice_value_expression(this->type_, this->valptr_->copy(), + this->len_->copy(), this->cap_->copy(), + this->location()); + } + + tree + do_get_tree(Translate_context* context); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The type of the slice value. + Type* type_; + // The pointer to the values in the slice. + Expression* valptr_; + // The length of the slice. + Expression* len_; + // The capacity of the slice. + Expression* cap_; +}; + +int +Slice_value_expression::do_traverse(Traverse* traverse) +{ + if (Expression::traverse(&this->valptr_, traverse) == TRAVERSE_EXIT + || Expression::traverse(&this->len_, traverse) == TRAVERSE_EXIT + || Expression::traverse(&this->cap_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return TRAVERSE_CONTINUE; +} + +tree +Slice_value_expression::do_get_tree(Translate_context* context) +{ + std::vector vals(3); + vals[0] = tree_to_expr(this->valptr_->get_tree(context)); + vals[1] = tree_to_expr(this->len_->get_tree(context)); + vals[2] = tree_to_expr(this->cap_->get_tree(context)); + + Gogo* gogo = context->gogo(); + Btype* btype = this->type_->get_backend(gogo); + Bexpression* ret = + gogo->backend()->constructor_expression(btype, vals, this->location()); + return expr_to_tree(ret); +} + +void +Slice_value_expression::do_dump_expression( + Ast_dump_context* ast_dump_context) const +{ + ast_dump_context->ostream() << "slicevalue("; + ast_dump_context->ostream() << "values: "; + this->valptr_->dump_expression(ast_dump_context); + ast_dump_context->ostream() << ", length: "; + this->len_->dump_expression(ast_dump_context); + ast_dump_context->ostream() << ", capacity: "; + this->cap_->dump_expression(ast_dump_context); + ast_dump_context->ostream() << ")"; +} + +Expression* +Expression::make_slice_value(Type* at, Expression* valptr, Expression* len, + Expression* cap, Location location) +{ + go_assert(at->is_slice_type()); + return new Slice_value_expression(at, valptr, len, cap, location); +} // An expression that evaluates to some characteristic of a non-empty interface. // This is used to access the method table or underlying object of an interface. @@ -14733,7 +14384,7 @@ class Interface_info_expression : public Expression { public: Interface_info_expression(Expression* iface, Interface_info iface_info, - Location location) + Location location) : Expression(EXPRESSION_INTERFACE_INFO, location), iface_(iface), iface_info_(iface_info) { } @@ -14779,9 +14430,12 @@ Interface_info_expression::do_type() { case INTERFACE_INFO_METHODS: { + Type* pdt = Type::make_type_descriptor_ptr_type(); + if (this->iface_->type()->interface_type()->is_empty()) + return pdt; + Location loc = this->location(); Struct_field_list* sfl = new Struct_field_list(); - Type* pdt = Type::make_type_descriptor_ptr_type(); sfl->push_back( Struct_field(Typed_identifier("__type_descriptor", pdt, loc))); @@ -14855,11 +14509,13 @@ void Interface_info_expression::do_dump_expression( Ast_dump_context* ast_dump_context) const { + bool is_empty = this->iface_->type()->interface_type()->is_empty(); ast_dump_context->ostream() << "interfaceinfo("; this->iface_->dump_expression(ast_dump_context); ast_dump_context->ostream() << ","; ast_dump_context->ostream() << - (this->iface_info_ == INTERFACE_INFO_METHODS ? "methods" + (this->iface_info_ == INTERFACE_INFO_METHODS && !is_empty ? "methods" + : this->iface_info_ == INTERFACE_INFO_TYPE_DESCRIPTOR ? "type_descriptor" : this->iface_info_ == INTERFACE_INFO_OBJECT ? "object" : "unknown"); ast_dump_context->ostream() << ")"; @@ -14874,6 +14530,303 @@ Expression::make_interface_info(Expression* iface, Interface_info iface_info, return new Interface_info_expression(iface, iface_info, location); } +// An expression that represents an interface value. The first field is either +// a type descriptor for an empty interface or a pointer to the interface method +// table for a non-empty interface. The second field is always the object. + +class Interface_value_expression : public Expression +{ + public: + Interface_value_expression(Type* type, Expression* first_field, + Expression* obj, Location location) + : Expression(EXPRESSION_INTERFACE_VALUE, location), + type_(type), first_field_(first_field), obj_(obj) + { } + + protected: + int + do_traverse(Traverse*); + + Type* + do_type() + { return this->type_; } + + void + do_determine_type(const Type_context*) + { go_unreachable(); } + + Expression* + do_copy() + { + return new Interface_value_expression(this->type_, + this->first_field_->copy(), + this->obj_->copy(), this->location()); + } + + tree + do_get_tree(Translate_context* context); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The type of the interface value. + Type* type_; + // The first field of the interface (either a type descriptor or a pointer + // to the method table. + Expression* first_field_; + // The underlying object of the interface. + Expression* obj_; +}; + +int +Interface_value_expression::do_traverse(Traverse* traverse) +{ + if (Expression::traverse(&this->first_field_, traverse) == TRAVERSE_EXIT + || Expression::traverse(&this->obj_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return TRAVERSE_CONTINUE; +} + +tree +Interface_value_expression::do_get_tree(Translate_context* context) +{ + std::vector vals(2); + vals[0] = tree_to_expr(this->first_field_->get_tree(context)); + vals[1] = tree_to_expr(this->obj_->get_tree(context)); + + Gogo* gogo = context->gogo(); + Btype* btype = this->type_->get_backend(gogo); + Bexpression* ret = + gogo->backend()->constructor_expression(btype, vals, this->location()); + return expr_to_tree(ret); +} + +void +Interface_value_expression::do_dump_expression( + Ast_dump_context* ast_dump_context) const +{ + ast_dump_context->ostream() << "interfacevalue("; + ast_dump_context->ostream() << + (this->type_->interface_type()->is_empty() + ? "type_descriptor: " + : "methods: "); + this->first_field_->dump_expression(ast_dump_context); + ast_dump_context->ostream() << ", object: "; + this->obj_->dump_expression(ast_dump_context); + ast_dump_context->ostream() << ")"; +} + +Expression* +Expression::make_interface_value(Type* type, Expression* first_value, + Expression* object, Location location) +{ + return new Interface_value_expression(type, first_value, object, location); +} + +// An interface method table for a pair of types: an interface type and a type +// that implements that interface. + +class Interface_mtable_expression : public Expression +{ + public: + Interface_mtable_expression(Interface_type* itype, Type* type, + bool is_pointer, Location location) + : Expression(EXPRESSION_INTERFACE_MTABLE, location), + itype_(itype), type_(type), is_pointer_(is_pointer), + method_table_type_(NULL), bvar_(NULL) + { } + + protected: + int + do_traverse(Traverse*); + + Type* + do_type(); + + bool + is_immutable() const + { return true; } + + void + do_determine_type(const Type_context*) + { go_unreachable(); } + + Expression* + do_copy() + { + return new Interface_mtable_expression(this->itype_, this->type_, + this->is_pointer_, this->location()); + } + + bool + do_is_addressable() const + { return true; } + + tree + do_get_tree(Translate_context* context); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The interface type for which the methods are defined. + Interface_type* itype_; + // The type to construct the interface method table for. + Type* type_; + // Whether this table contains the method set for the receiver type or the + // pointer receiver type. + bool is_pointer_; + // The type of the method table. + Type* method_table_type_; + // The backend variable that refers to the interface method table. + Bvariable* bvar_; +}; + +int +Interface_mtable_expression::do_traverse(Traverse* traverse) +{ + if (Type::traverse(this->itype_, traverse) == TRAVERSE_EXIT + || Type::traverse(this->type_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return TRAVERSE_CONTINUE; +} + +Type* +Interface_mtable_expression::do_type() +{ + if (this->method_table_type_ != NULL) + return this->method_table_type_; + + const Typed_identifier_list* interface_methods = this->itype_->methods(); + go_assert(!interface_methods->empty()); + + Struct_field_list* sfl = new Struct_field_list; + Typed_identifier tid("__type_descriptor", Type::make_type_descriptor_ptr_type(), + this->location()); + sfl->push_back(Struct_field(tid)); + for (Typed_identifier_list::const_iterator p = interface_methods->begin(); + p != interface_methods->end(); + ++p) + sfl->push_back(Struct_field(*p)); + this->method_table_type_ = Type::make_struct_type(sfl, this->location()); + return this->method_table_type_; +} + +tree +Interface_mtable_expression::do_get_tree(Translate_context* context) +{ + Gogo* gogo = context->gogo(); + Bexpression* ret; + Location loc = Linemap::predeclared_location(); + if (this->bvar_ != NULL) + { + ret = gogo->backend()->var_expression(this->bvar_, this->location()); + return expr_to_tree(ret); + } + + const Typed_identifier_list* interface_methods = this->itype_->methods(); + go_assert(!interface_methods->empty()); + + std::string mangled_name = ((this->is_pointer_ ? "__go_pimt__" : "__go_imt_") + + this->itype_->mangled_name(gogo) + + "__" + + this->type_->mangled_name(gogo)); + + // See whether this interface has any hidden methods. + bool has_hidden_methods = false; + for (Typed_identifier_list::const_iterator p = interface_methods->begin(); + p != interface_methods->end(); + ++p) + { + if (Gogo::is_hidden_name(p->name())) + { + has_hidden_methods = true; + break; + } + } + + // We already know that the named type is convertible to the + // interface. If the interface has hidden methods, and the named + // type is defined in a different package, then the interface + // conversion table will be defined by that other package. + if (has_hidden_methods + && this->type_->named_type() != NULL + && this->type_->named_type()->named_object()->package() != NULL) + { + Btype* btype = this->type()->get_backend(gogo); + this->bvar_ = + gogo->backend()->immutable_struct_reference(mangled_name, btype, loc); + ret = gogo->backend()->var_expression(this->bvar_, this->location()); + return expr_to_tree(ret); + } + + // The first element is the type descriptor. + Type* td_type; + if (!this->is_pointer_) + td_type = this->type_; + else + td_type = Type::make_pointer_type(this->type_); + + // Build an interface method table for a type: a type descriptor followed by a + // list of function pointers, one for each interface method. This is used for + // interfaces. + Expression_list* svals = new Expression_list(); + svals->push_back(Expression::make_type_descriptor(td_type, loc)); + + Named_type* nt = this->type_->named_type(); + Struct_type* st = this->type_->struct_type(); + go_assert(nt != NULL || st != NULL); + + for (Typed_identifier_list::const_iterator p = interface_methods->begin(); + p != interface_methods->end(); + ++p) + { + bool is_ambiguous; + Method* m; + if (nt != NULL) + m = nt->method_function(p->name(), &is_ambiguous); + else + m = st->method_function(p->name(), &is_ambiguous); + go_assert(m != NULL); + Named_object* no = m->named_object(); + + go_assert(no->is_function() || no->is_function_declaration()); + svals->push_back(Expression::make_func_code_reference(no, loc)); + } + + Btype* btype = this->type()->get_backend(gogo); + Expression* mtable = Expression::make_struct_composite_literal(this->type(), + svals, loc); + Bexpression* ctor = tree_to_expr(mtable->get_tree(context)); + + bool is_public = has_hidden_methods && this->type_->named_type() != NULL; + this->bvar_ = gogo->backend()->immutable_struct(mangled_name, false, + !is_public, btype, loc); + gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false, + !is_public, btype, loc, ctor); + ret = gogo->backend()->var_expression(this->bvar_, loc); + return expr_to_tree(ret); +} + +void +Interface_mtable_expression::do_dump_expression( + Ast_dump_context* ast_dump_context) const +{ + ast_dump_context->ostream() << "__go_" + << (this->is_pointer_ ? "pimt__" : "imt_"); + ast_dump_context->dump_type(this->itype_); + ast_dump_context->ostream() << "__"; + ast_dump_context->dump_type(this->type_); +} + +Expression* +Expression::make_interface_mtable_ref(Interface_type* itype, Type* type, + bool is_pointer, Location location) +{ + return new Interface_mtable_expression(itype, type, is_pointer, location); +} + // An expression which evaluates to the offset of a field within a // struct. This, like Type_info_expression, q.v., is only used to // initialize fields of a type descriptor. @@ -15082,12 +15035,14 @@ class Conditional_expression : public Expression {} protected: + int + do_traverse(Traverse*); + Type* do_type(); void - do_determine_type(const Type_context*) - { } + do_determine_type(const Type_context*); Expression* do_copy() @@ -15111,13 +15066,26 @@ class Conditional_expression : public Expression Expression* else_; }; +// Traversal. + +int +Conditional_expression::do_traverse(Traverse* traverse) +{ + if (Expression::traverse(&this->cond_, traverse) == TRAVERSE_EXIT + || Expression::traverse(&this->then_, traverse) == TRAVERSE_EXIT + || Expression::traverse(&this->else_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return TRAVERSE_CONTINUE; +} + // Return the type of the conditional expression. Type* Conditional_expression::do_type() { Type* result_type = Type::make_void_type(); - if (this->then_->type() == this->else_->type()) + if (Type::are_identical(this->then_->type(), this->else_->type(), false, + NULL)) result_type = this->then_->type(); else if (this->then_->is_nil_expression() || this->else_->is_nil_expression()) @@ -15127,6 +15095,16 @@ Conditional_expression::do_type() return result_type; } +// Determine type for a conditional expression. + +void +Conditional_expression::do_determine_type(const Type_context* context) +{ + this->cond_->determine_type_no_context(); + this->then_->determine_type(context); + this->else_->determine_type(context); +} + // Get the backend representation of a conditional expression. tree @@ -15167,6 +15145,108 @@ Expression::make_conditional(Expression* cond, Expression* then, return new Conditional_expression(cond, then, else_expr, location); } +// Compound expressions. + +class Compound_expression : public Expression +{ + public: + Compound_expression(Expression* init, Expression* expr, Location location) + : Expression(EXPRESSION_COMPOUND, location), init_(init), expr_(expr) + {} + + protected: + int + do_traverse(Traverse*); + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + Expression* + do_copy() + { + return new Compound_expression(this->init_->copy(), this->expr_->copy(), + this->location()); + } + + tree + do_get_tree(Translate_context* context); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The expression that is evaluated first and discarded. + Expression* init_; + // The expression that is evaluated and returned. + Expression* expr_; +}; + +// Traversal. + +int +Compound_expression::do_traverse(Traverse* traverse) +{ + if (Expression::traverse(&this->init_, traverse) == TRAVERSE_EXIT + || Expression::traverse(&this->expr_, traverse) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + return TRAVERSE_CONTINUE; +} + +// Return the type of the compound expression. + +Type* +Compound_expression::do_type() +{ + return this->expr_->type(); +} + +// Determine type for a compound expression. + +void +Compound_expression::do_determine_type(const Type_context* context) +{ + this->init_->determine_type_no_context(); + this->expr_->determine_type(context); +} + +// Get the backend representation of a compound expression. + +tree +Compound_expression::do_get_tree(Translate_context* context) +{ + Gogo* gogo = context->gogo(); + Bexpression* binit = tree_to_expr(this->init_->get_tree(context)); + Bstatement* init_stmt = gogo->backend()->expression_statement(binit); + Bexpression* bexpr = tree_to_expr(this->expr_->get_tree(context)); + Bexpression* ret = gogo->backend()->compound_expression(init_stmt, bexpr, + this->location()); + return expr_to_tree(ret); +} + +// Dump ast representation of a conditional expression. + +void +Compound_expression::do_dump_expression( + Ast_dump_context* ast_dump_context) const +{ + ast_dump_context->ostream() << "("; + ast_dump_context->dump_expression(this->init_); + ast_dump_context->ostream() << ","; + ast_dump_context->dump_expression(this->expr_); + ast_dump_context->ostream() << ") "; +} + +// Make a compound expression. + +Expression* +Expression::make_compound(Expression* init, Expression* expr, Location location) +{ + return new Compound_expression(init, expr, location); +} + // Import an expression. This comes at the end in order to see the // various class definitions. diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 99a0d0720eb..dc9ad71c820 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -74,6 +74,7 @@ class Expression EXPRESSION_UNKNOWN_REFERENCE, EXPRESSION_BOOLEAN, EXPRESSION_STRING, + EXPRESSION_STRING_INFO, EXPRESSION_INTEGER, EXPRESSION_FLOAT, EXPRESSION_COMPLEX, @@ -95,19 +96,23 @@ class Expression EXPRESSION_UNSAFE_CONVERSION, EXPRESSION_STRUCT_CONSTRUCTION, EXPRESSION_FIXED_ARRAY_CONSTRUCTION, - EXPRESSION_OPEN_ARRAY_CONSTRUCTION, + EXPRESSION_SLICE_CONSTRUCTION, EXPRESSION_MAP_CONSTRUCTION, EXPRESSION_COMPOSITE_LITERAL, - EXPRESSION_HEAP_COMPOSITE, + EXPRESSION_HEAP, EXPRESSION_RECEIVE, EXPRESSION_TYPE_DESCRIPTOR, EXPRESSION_TYPE_INFO, EXPRESSION_SLICE_INFO, + EXPRESSION_SLICE_VALUE, EXPRESSION_INTERFACE_INFO, + EXPRESSION_INTERFACE_VALUE, + EXPRESSION_INTERFACE_MTABLE, EXPRESSION_STRUCT_FIELD_OFFSET, EXPRESSION_MAP_DESCRIPTOR, EXPRESSION_LABEL_ADDR, - EXPRESSION_CONDITIONAL + EXPRESSION_CONDITIONAL, + EXPRESSION_COMPOUND }; Expression(Expression_classification, Location); @@ -188,6 +193,20 @@ class Expression static Expression* make_string(const std::string&, Location); + // Make an expression that evaluates to some characteristic of an string. + // For simplicity, the enum values must match the field indexes in the + // underlying struct. + enum String_info + { + // The underlying data in the string. + STRING_INFO_DATA, + // The length of the string. + STRING_INFO_LENGTH + }; + + static Expression* + make_string_info(Expression* string, String_info, Location); + // Make a character constant expression. TYPE should be NULL for an // abstract type. static Expression* @@ -312,9 +331,9 @@ class Expression static Expression* make_slice_composite_literal(Type*, Expression_list*, Location); - // Take a composite literal and allocate it on the heap. + // Take an expression and allocate it on the heap. static Expression* - make_heap_composite(Expression*, Location); + make_heap_expression(Expression*, Location); // Make a receive expression. VAL is NULL for a unary receive. static Receive_expression* @@ -358,14 +377,20 @@ class Expression static Expression* make_slice_info(Expression* slice, Slice_info, Location); + // Make an expression for a slice value. + static Expression* + make_slice_value(Type*, Expression* valptr, Expression* len, Expression* cap, + Location); - // Make an expression that evaluates to some characteristic of a + // Make an expression that evaluates to some characteristic of an // interface. For simplicity, the enum values must match the field indexes - // of a non-empty interface in the underlying struct. + // in the underlying struct. enum Interface_info { + // The type descriptor of an empty interface. + INTERFACE_INFO_TYPE_DESCRIPTOR = 0, // The methods of an interface. - INTERFACE_INFO_METHODS, + INTERFACE_INFO_METHODS = 0, // The first argument to pass to an interface method. INTERFACE_INFO_OBJECT }; @@ -373,6 +398,17 @@ class Expression static Expression* make_interface_info(Expression* iface, Interface_info, Location); + // Make an expression for an interface value. + static Expression* + make_interface_value(Type*, Expression*, Expression*, Location); + + // Make an expression that builds a reference to the interface method table + // for TYPE that satisfies interface ITYPE. IS_POINTER is true if this is a + // reference to the interface method table for the pointer receiver type. + static Expression* + make_interface_mtable_ref(Interface_type* itype, Type* type, + bool is_pointer, Location); + // Make an expression which evaluates to the offset of a field in a // struct. This is only used for type descriptors, so there is no // location parameter. @@ -393,6 +429,10 @@ class Expression static Expression* make_conditional(Expression*, Expression*, Expression*, Location); + // Make a compound expression. + static Expression* + make_compound(Expression*, Expression*, Location); + // Return the expression classification. Expression_classification classification() const @@ -700,19 +740,19 @@ class Expression tree get_tree(Translate_context*); - // Return a tree handling any conversions which must be done during + // Return an expression handling any conversions which must be done during // assignment. - static tree - convert_for_assignment(Translate_context*, Type* lhs_type, Type* rhs_type, - tree rhs_tree, Location location); + static Expression* + convert_for_assignment(Gogo*, Type* lhs_type, Expression* rhs, + Location location); - // Return a tree converting a value of one interface type to another + // Return an expression converting a value of one interface type to another // interface type. If FOR_TYPE_GUARD is true this is for a type // assertion. - static tree - convert_interface_to_interface(Translate_context*, Type* lhs_type, - Type* rhs_type, tree rhs_tree, - bool for_type_guard, Location); + static Expression* + convert_interface_to_interface(Type* lhs_type, + Expression* rhs, bool for_type_guard, + Location); // Return a backend expression implementing the comparison LEFT OP RIGHT. // TYPE is the type of both sides. @@ -736,12 +776,10 @@ class Expression static Expression* import_expression(Import*); - // Return a tree which checks that VAL, of arbitrary integer type, - // is non-negative and is not more than the maximum value of - // BOUND_TYPE. If SOFAR is not NULL, it is or'red into the result. - // The return value may be NULL if SOFAR is NULL. - static tree - check_bounds(tree val, tree bound_type, tree sofar, Location); + // Return an expression which checks that VAL, of arbitrary integer type, + // is non-negative and is not more than the maximum integer value. + static Expression* + check_bounds(Expression* val, Location); // Dump an expression to a dump constext. void @@ -881,17 +919,14 @@ class Expression : NULL); } - static tree - convert_type_to_interface(Translate_context*, Type*, Type*, tree, - Location); + static Expression* + convert_type_to_interface(Type*, Expression*, Location); - static tree - get_interface_type_descriptor(Translate_context*, Type*, tree, - Location); + static Expression* + get_interface_type_descriptor(Expression*); - static tree - convert_interface_to_type(Translate_context*, Type*, Type*, tree, - Location); + static Expression* + convert_interface_to_type(Type*, Expression*, Location); // The expression classification. Expression_classification classification_; @@ -1408,8 +1443,8 @@ class Call_expression : public Expression Call_expression(Expression* fn, Expression_list* args, bool is_varargs, Location location) : Expression(EXPRESSION_CALL, location), - fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL), - is_varargs_(is_varargs), are_hidden_fields_ok_(false), + fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL), + call_temp_(NULL), is_varargs_(is_varargs), are_hidden_fields_ok_(false), varargs_are_lowered_(false), types_are_determined_(false), is_deferred_(false), issued_error_(false) { } @@ -1489,6 +1524,9 @@ class Call_expression : public Expression virtual Expression* do_lower(Gogo*, Named_object*, Statement_inserter*, int); + virtual Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + bool do_discarding_value() { return true; } @@ -1550,8 +1588,8 @@ class Call_expression : public Expression interface_method_function(Interface_field_reference_expression*, Expression**); - tree - set_results(Translate_context*, tree); + Bexpression* + set_results(Translate_context*, Bexpression*); // The function to call. Expression* fn_; @@ -1563,8 +1601,10 @@ class Call_expression : public Expression // The list of temporaries which will hold the results if the // function returns a tuple. std::vector* results_; - // The tree for the call, used for a call which returns a tuple. - tree tree_; + // The backend expression for the call, used for a call which returns a tuple. + Bexpression* call_; + // A temporary variable to store this call if the function returns a tuple. + Temporary_statement* call_temp_; // True if the last argument is a varargs argument (f(a...)). bool is_varargs_; // True if this statement may pass hidden fields in the arguments. @@ -1838,7 +1878,7 @@ class Map_index_expression : public Expression Location location) : Expression(EXPRESSION_MAP_INDEX, location), map_(map), index_(index), is_lvalue_(false), - is_in_tuple_assignment_(false) + is_in_tuple_assignment_(false), value_pointer_(NULL) { } // Return the map. @@ -1881,18 +1921,21 @@ class Map_index_expression : public Expression set_is_in_tuple_assignment() { this->is_in_tuple_assignment_ = true; } - // Return a tree for the map index. This returns a tree which + // Return an expression for the map index. This returns an expression which // evaluates to a pointer to a value in the map. If INSERT is true, // the key will be inserted if not present, and the value pointer // will be zero initialized. If INSERT is false, and the key is not // present in the map, the pointer will be NULL. - tree - get_value_pointer(Translate_context*, bool insert); + Expression* + get_value_pointer(bool insert); protected: int do_traverse(Traverse*); + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + Type* do_type(); @@ -1934,6 +1977,8 @@ class Map_index_expression : public Expression bool is_lvalue_; // Whether this is in a tuple assignment to a pair of values. bool is_in_tuple_assignment_; + // A pointer to the value at this index. + Expression* value_pointer_; }; // An expression which represents a method bound to its first @@ -2230,6 +2275,9 @@ class Type_guard_expression : public Expression int do_traverse(Traverse* traverse); + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + Type* do_type() { return this->type_; } @@ -2268,7 +2316,7 @@ class Receive_expression : public Expression public: Receive_expression(Expression* channel, Location location) : Expression(EXPRESSION_RECEIVE, location), - channel_(channel) + channel_(channel), temp_receiver_(NULL) { } // Return the channel. @@ -2288,6 +2336,9 @@ class Receive_expression : public Expression Type* do_type(); + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + void do_determine_type(const Type_context*) { this->channel_->determine_type_no_context(); } @@ -2314,6 +2365,8 @@ class Receive_expression : public Expression private: // The channel from which we are receiving. Expression* channel_; + // A temporary reference to the variable storing the received data. + Temporary_statement* temp_receiver_; }; // A numeric constant. This is used both for untyped constants and diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 1950090b9e0..e92acae7af4 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -636,10 +636,10 @@ class Var_init { public: Var_init() - : var_(NULL), init_(NULL_TREE) + : var_(NULL), init_(NULL) { } - Var_init(Named_object* var, tree init) + Var_init(Named_object* var, Bstatement* init) : var_(var), init_(init) { } @@ -649,15 +649,15 @@ class Var_init { return this->var_; } // Return the initialization expression. - tree + Bstatement* init() const { return this->init_; } private: // The variable being initialized. Named_object* var_; - // The initialization expression to run. - tree init_; + // The initialization statement. + Bstatement* init_; }; typedef std::list Var_inits; @@ -868,15 +868,13 @@ Gogo::write_globals() // initializer purely for its side effects. bool is_sink = no->name()[0] == '_' && no->name()[1] == '.'; - tree var_init_tree = NULL_TREE; + Bstatement* var_init_stmt = NULL; if (!no->var_value()->has_pre_init()) { - tree init = no->var_value()->get_init_tree(this, NULL); - if (init == error_mark_node) - go_assert(saw_errors()); - else if (init == NULL_TREE) + Bexpression* var_binit = no->var_value()->get_init(this, NULL); + if (var_binit == NULL) ; - else if (TREE_CONSTANT(init)) + else if (TREE_CONSTANT(expr_to_tree(var_binit))) { if (expression_requires(no->var_value()->init(), NULL, this->var_depends_on(no->var_value()), @@ -885,17 +883,20 @@ Gogo::write_globals() "initialization expression for %qs depends " "upon itself", no->message_name().c_str()); - this->backend()->global_variable_set_init(var, - tree_to_expr(init)); + this->backend()->global_variable_set_init(var, var_binit); } - else if (is_sink - || int_size_in_bytes(TREE_TYPE(init)) == 0 - || int_size_in_bytes(TREE_TYPE(vec[i])) == 0) - var_init_tree = init; + else if (is_sink) + var_init_stmt = + this->backend()->expression_statement(var_binit); else - var_init_tree = fold_build2_loc(no->location().gcc_location(), - MODIFY_EXPR, void_type_node, - vec[i], init); + { + Location loc = no->var_value()->location(); + Bexpression* var_expr = + this->backend()->var_expression(var, loc); + var_init_stmt = + this->backend()->assignment_statement(var_expr, var_binit, + loc); + } } else { @@ -907,19 +908,21 @@ Gogo::write_globals() push_struct_function(init_fndecl); else push_cfun(DECL_STRUCT_FUNCTION(init_fndecl)); - tree var_decl = is_sink ? NULL_TREE : vec[i]; - var_init_tree = no->var_value()->get_init_block(this, NULL, - var_decl); + Bvariable* var_decl = is_sink ? NULL : var; + var_init_stmt = + no->var_value()->get_init_block(this, NULL, var_decl); + pop_cfun(); } - if (var_init_tree != NULL_TREE && var_init_tree != error_mark_node) + if (var_init_stmt != NULL) { if (no->var_value()->init() == NULL && !no->var_value()->has_pre_init()) - append_to_statement_list(var_init_tree, &var_init_stmt_list); + append_to_statement_list(stat_to_tree(var_init_stmt), + &var_init_stmt_list); else - var_inits.push_back(Var_init(no, var_init_tree)); + var_inits.push_back(Var_init(no, var_init_stmt)); } else if (this->var_depends_on(no->var_value()) != NULL) { @@ -927,7 +930,12 @@ Gogo::write_globals() // not in its init or preinit. This variable needs to // participate in dependency analysis sorting, in case // some other variable depends on this one. - var_inits.push_back(Var_init(no, integer_zero_node)); + Btype* int_btype = + Type::lookup_integer_type("int")->get_backend(this); + Bexpression* zero = this->backend()->zero_expression(int_btype); + Bstatement* zero_stmt = + this->backend()->expression_statement(zero); + var_inits.push_back(Var_init(no, zero_stmt)); } if (!is_sink && no->var_value()->type()->has_pointer()) @@ -950,7 +958,7 @@ Gogo::write_globals() for (Var_inits::const_iterator p = var_inits.begin(); p != var_inits.end(); ++p) - append_to_statement_list(p->init(), &init_stmt_list); + append_to_statement_list(stat_to_tree(p->init()), &init_stmt_list); } // After all the variables are initialized, call the "init" @@ -1106,7 +1114,7 @@ Named_object::get_tree(Gogo* gogo, Named_object* function) cfun->function_end_locus = func->block()->end_location().gcc_location(); - func->build_tree(gogo, this); + func->build(gogo, this); gimplify_function_tree(decl); @@ -1139,84 +1147,6 @@ Named_object::get_tree(Gogo* gogo, Named_object* function) return ret; } -// Get the initial value of a variable as a tree. This does not -// consider whether the variable is in the heap--it returns the -// initial value as though it were always stored in the stack. - -tree -Variable::get_init_tree(Gogo* gogo, Named_object* function) -{ - go_assert(this->preinit_ == NULL); - if (this->init_ == NULL) - { - go_assert(!this->is_parameter_); - if (this->is_global_ || this->is_in_heap()) - return NULL; - Btype* btype = this->type_->get_backend(gogo); - return expr_to_tree(gogo->backend()->zero_expression(btype)); - } - else - { - Translate_context context(gogo, function, NULL, NULL); - tree rhs_tree = this->init_->get_tree(&context); - return Expression::convert_for_assignment(&context, this->type(), - this->init_->type(), - rhs_tree, this->location()); - } -} - -// Get the initial value of a variable when a block is required. -// VAR_DECL is the decl to set; it may be NULL for a sink variable. - -tree -Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl) -{ - go_assert(this->preinit_ != NULL); - - // We want to add the variable assignment to the end of the preinit - // block. The preinit block may have a TRY_FINALLY_EXPR and a - // TRY_CATCH_EXPR; if it does, we want to add to the end of the - // regular statements. - - Translate_context context(gogo, function, NULL, NULL); - Bblock* bblock = this->preinit_->get_backend(&context); - tree block_tree = block_to_tree(bblock); - if (block_tree == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(block_tree) == BIND_EXPR); - tree statements = BIND_EXPR_BODY(block_tree); - while (statements != NULL_TREE - && (TREE_CODE(statements) == TRY_FINALLY_EXPR - || TREE_CODE(statements) == TRY_CATCH_EXPR)) - statements = TREE_OPERAND(statements, 0); - - // It's possible to have pre-init statements without an initializer - // if the pre-init statements set the variable. - if (this->init_ != NULL) - { - tree rhs_tree = this->init_->get_tree(&context); - if (rhs_tree == error_mark_node) - return error_mark_node; - if (var_decl == NULL_TREE) - append_to_statement_list(rhs_tree, &statements); - else - { - tree val = Expression::convert_for_assignment(&context, this->type(), - this->init_->type(), - rhs_tree, - this->location()); - if (val == error_mark_node) - return error_mark_node; - tree set = fold_build2_loc(this->location().gcc_location(), - MODIFY_EXPR, void_type_node, var_decl, - val); - append_to_statement_list(set, &statements); - } - } - - return block_tree; -} - // Get the backend representation. Bfunction* @@ -1272,469 +1202,6 @@ Function::get_decl() const return function_to_tree(this->fndecl_); } -// We always pass the receiver to a method as a pointer. If the -// receiver is actually declared as a non-pointer type, then we copy -// the value into a local variable, so that it has the right type. In -// this function we create the real PARM_DECL to use, and set -// DEC_INITIAL of the var_decl to be the value passed in. - -tree -Function::make_receiver_parm_decl(Gogo* gogo, Named_object* no, tree var_decl) -{ - if (var_decl == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(var_decl) == VAR_DECL); - tree val_type = TREE_TYPE(var_decl); - bool is_in_heap = no->var_value()->is_in_heap(); - if (is_in_heap) - { - go_assert(POINTER_TYPE_P(val_type)); - val_type = TREE_TYPE(val_type); - } - - source_location loc = DECL_SOURCE_LOCATION(var_decl); - std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl)); - name += ".pointer"; - tree id = get_identifier_from_string(name); - tree parm_decl = build_decl(loc, PARM_DECL, id, build_pointer_type(val_type)); - DECL_CONTEXT(parm_decl) = current_function_decl; - DECL_ARG_TYPE(parm_decl) = TREE_TYPE(parm_decl); - - go_assert(DECL_INITIAL(var_decl) == NULL_TREE); - tree init = build_fold_indirect_ref_loc(loc, parm_decl); - - if (is_in_heap) - { - tree size = TYPE_SIZE_UNIT(val_type); - tree space = gogo->allocate_memory(no->var_value()->type(), size, - no->location()); - space = save_expr(space); - space = fold_convert(build_pointer_type(val_type), space); - tree spaceref = build_fold_indirect_ref_loc(no->location().gcc_location(), - space); - TREE_THIS_NOTRAP(spaceref) = 1; - tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node, - spaceref, init); - init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space), set, space); - } - - DECL_INITIAL(var_decl) = init; - - return parm_decl; -} - -// If we take the address of a parameter, then we need to copy it into -// the heap. We will access it as a local variable via an -// indirection. - -tree -Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl) -{ - if (var_decl == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(var_decl) == VAR_DECL); - Location loc(DECL_SOURCE_LOCATION(var_decl)); - - std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl)); - name += ".param"; - tree id = get_identifier_from_string(name); - - tree type = TREE_TYPE(var_decl); - go_assert(POINTER_TYPE_P(type)); - type = TREE_TYPE(type); - - tree parm_decl = build_decl(loc.gcc_location(), PARM_DECL, id, type); - DECL_CONTEXT(parm_decl) = current_function_decl; - DECL_ARG_TYPE(parm_decl) = type; - - tree size = TYPE_SIZE_UNIT(type); - tree space = gogo->allocate_memory(no->var_value()->type(), size, loc); - space = save_expr(space); - space = fold_convert(TREE_TYPE(var_decl), space); - tree spaceref = build_fold_indirect_ref_loc(loc.gcc_location(), space); - TREE_THIS_NOTRAP(spaceref) = 1; - tree init = build2(COMPOUND_EXPR, TREE_TYPE(space), - build2(MODIFY_EXPR, void_type_node, spaceref, parm_decl), - space); - DECL_INITIAL(var_decl) = init; - - return parm_decl; -} - -// Get a tree for function code. - -void -Function::build_tree(Gogo* gogo, Named_object* named_function) -{ - tree fndecl = this->get_decl(); - go_assert(fndecl != NULL_TREE); - - tree params = NULL_TREE; - tree* pp = ¶ms; - - tree declare_vars = NULL_TREE; - for (Bindings::const_definitions_iterator p = - this->block_->bindings()->begin_definitions(); - p != this->block_->bindings()->end_definitions(); - ++p) - { - if ((*p)->is_variable() && (*p)->var_value()->is_parameter()) - { - Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); - *pp = var_to_tree(bvar); - - // We always pass the receiver to a method as a pointer. If - // the receiver is declared as a non-pointer type, then we - // copy the value into a local variable. - if ((*p)->var_value()->is_receiver() - && (*p)->var_value()->type()->points_to() == NULL) - { - tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp); - tree var = *pp; - if (var != error_mark_node) - { - go_assert(TREE_CODE(var) == VAR_DECL); - DECL_CHAIN(var) = declare_vars; - declare_vars = var; - } - *pp = parm_decl; - } - else if ((*p)->var_value()->is_in_heap()) - { - // If we take the address of a parameter, then we need - // to copy it into the heap. - tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp); - tree var = *pp; - if (var != error_mark_node) - { - go_assert(TREE_CODE(var) == VAR_DECL); - DECL_CHAIN(var) = declare_vars; - declare_vars = var; - } - *pp = parm_decl; - } - - if (*pp != error_mark_node) - { - go_assert(TREE_CODE(*pp) == PARM_DECL); - pp = &DECL_CHAIN(*pp); - } - } - else if ((*p)->is_result_variable()) - { - Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); - tree var_decl = var_to_tree(bvar); - - Type* type = (*p)->result_var_value()->type(); - tree init; - if (!(*p)->result_var_value()->is_in_heap()) - { - Btype* btype = type->get_backend(gogo); - init = expr_to_tree(gogo->backend()->zero_expression(btype)); - } - else - { - Location loc = (*p)->location(); - tree type_tree = type_to_tree(type->get_backend(gogo)); - tree space = gogo->allocate_memory(type, - TYPE_SIZE_UNIT(type_tree), - loc); - tree ptr_type_tree = build_pointer_type(type_tree); - init = fold_convert_loc(loc.gcc_location(), ptr_type_tree, space); - } - - if (var_decl != error_mark_node) - { - go_assert(TREE_CODE(var_decl) == VAR_DECL); - DECL_INITIAL(var_decl) = init; - DECL_CHAIN(var_decl) = declare_vars; - declare_vars = var_decl; - } - } - } - - *pp = NULL_TREE; - - DECL_ARGUMENTS(fndecl) = params; - - // If we need a closure variable, fetch it by calling a runtime - // function. The caller will have called __go_set_closure before - // the function call. - if (this->closure_var_ != NULL) - { - Bvariable* bvar = - this->closure_var_->get_backend_variable(gogo, named_function); - tree var_decl = var_to_tree(bvar); - if (var_decl != error_mark_node) - { - go_assert(TREE_CODE(var_decl) == VAR_DECL); - static tree get_closure_fndecl; - tree get_closure = Gogo::call_builtin(&get_closure_fndecl, - this->location_, - "__go_get_closure", - 0, - ptr_type_node); - - // Mark the __go_get_closure function as pure, since it - // depends only on the global variable g. - DECL_PURE_P(get_closure_fndecl) = 1; - - get_closure = fold_convert_loc(this->location_.gcc_location(), - TREE_TYPE(var_decl), get_closure); - DECL_INITIAL(var_decl) = get_closure; - DECL_CHAIN(var_decl) = declare_vars; - declare_vars = var_decl; - } - } - - if (this->block_ != NULL) - { - go_assert(DECL_INITIAL(fndecl) == NULL_TREE); - - // Declare variables if necessary. - tree bind = NULL_TREE; - tree defer_init = NULL_TREE; - if (declare_vars != NULL_TREE || this->defer_stack_ != NULL) - { - tree block = make_node(BLOCK); - BLOCK_SUPERCONTEXT(block) = fndecl; - DECL_INITIAL(fndecl) = block; - BLOCK_VARS(block) = declare_vars; - TREE_USED(block) = 1; - - bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), - NULL_TREE, block); - TREE_SIDE_EFFECTS(bind) = 1; - - if (this->defer_stack_ != NULL) - { - Translate_context dcontext(gogo, named_function, this->block_, - tree_to_block(bind)); - Bstatement* bdi = this->defer_stack_->get_backend(&dcontext); - defer_init = stat_to_tree(bdi); - } - } - - // Build the trees for all the statements in the function. - Translate_context context(gogo, named_function, NULL, NULL); - Bblock* bblock = this->block_->get_backend(&context); - tree code = block_to_tree(bblock); - - tree init = NULL_TREE; - tree except = NULL_TREE; - tree fini = NULL_TREE; - - // Initialize variables if necessary. - for (tree v = declare_vars; v != NULL_TREE; v = DECL_CHAIN(v)) - { - tree dv = build1(DECL_EXPR, void_type_node, v); - SET_EXPR_LOCATION(dv, DECL_SOURCE_LOCATION(v)); - append_to_statement_list(dv, &init); - } - - // If we have a defer stack, initialize it at the start of a - // function. - if (defer_init != NULL_TREE && defer_init != error_mark_node) - { - SET_EXPR_LOCATION(defer_init, - this->block_->start_location().gcc_location()); - append_to_statement_list(defer_init, &init); - - // Clean up the defer stack when we leave the function. - this->build_defer_wrapper(gogo, named_function, &except, &fini); - } - - if (code != NULL_TREE && code != error_mark_node) - { - if (init != NULL_TREE) - code = build2(COMPOUND_EXPR, void_type_node, init, code); - if (except != NULL_TREE) - code = build2(TRY_CATCH_EXPR, void_type_node, code, - build2(CATCH_EXPR, void_type_node, NULL, except)); - if (fini != NULL_TREE) - code = build2(TRY_FINALLY_EXPR, void_type_node, code, fini); - } - - // Stick the code into the block we built for the receiver, if - // we built on. - if (bind != NULL_TREE && code != NULL_TREE && code != error_mark_node) - { - BIND_EXPR_BODY(bind) = code; - code = bind; - } - - DECL_SAVED_TREE(fndecl) = code; - } - - // If we created a descriptor for the function, make sure we emit it. - if (this->descriptor_ != NULL) - { - Translate_context context(gogo, NULL, NULL, NULL); - this->descriptor_->get_tree(&context); - } -} - -// Build the wrappers around function code needed if the function has -// any defer statements. This sets *EXCEPT to an exception handler -// and *FINI to a finally handler. - -void -Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function, - tree *except, tree *fini) -{ - Location end_loc = this->block_->end_location(); - - // Add an exception handler. This is used if a panic occurs. Its - // purpose is to stop the stack unwinding if a deferred function - // calls recover. There are more details in - // libgo/runtime/go-unwind.c. - - tree stmt_list = NULL_TREE; - - Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1, - this->defer_stack(end_loc)); - Translate_context context(gogo, named_function, NULL, NULL); - tree call_tree = call->get_tree(&context); - if (call_tree != error_mark_node) - append_to_statement_list(call_tree, &stmt_list); - - tree retval = this->return_value(gogo, named_function, end_loc, &stmt_list); - tree set; - if (retval == NULL_TREE) - set = NULL_TREE; - else - set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node, - DECL_RESULT(this->get_decl()), retval); - tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR, - void_type_node, set); - append_to_statement_list(ret_stmt, &stmt_list); - - go_assert(*except == NULL_TREE); - *except = stmt_list; - - // Add some finally code to run the defer functions. This is used - // both in the normal case, when no panic occurs, and also if a - // panic occurs to run any further defer functions. Of course, it - // is possible for a defer function to call panic which should be - // caught by another defer function. To handle that we use a loop. - // finish: - // try { __go_undefer(); } catch { __go_check_defer(); goto finish; } - // if (return values are named) return named_vals; - - stmt_list = NULL; - - tree label = create_artificial_label(end_loc.gcc_location()); - tree define_label = fold_build1_loc(end_loc.gcc_location(), LABEL_EXPR, - void_type_node, label); - append_to_statement_list(define_label, &stmt_list); - - call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1, - this->defer_stack(end_loc)); - tree undefer = call->get_tree(&context); - - call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1, - this->defer_stack(end_loc)); - tree defer = call->get_tree(&context); - - if (undefer == error_mark_node || defer == error_mark_node) - return; - - tree jump = fold_build1_loc(end_loc.gcc_location(), GOTO_EXPR, void_type_node, - label); - tree catch_body = build2(COMPOUND_EXPR, void_type_node, defer, jump); - catch_body = build2(CATCH_EXPR, void_type_node, NULL, catch_body); - tree try_catch = build2(TRY_CATCH_EXPR, void_type_node, undefer, catch_body); - - append_to_statement_list(try_catch, &stmt_list); - - if (this->type_->results() != NULL - && !this->type_->results()->empty() - && !this->type_->results()->front().name().empty()) - { - // If the result variables are named, and we are returning from - // this function rather than panicing through it, we need to - // return them again, because they might have been changed by a - // defer function. The runtime routines set the defer_stack - // variable to true if we are returning from this function. - retval = this->return_value(gogo, named_function, end_loc, - &stmt_list); - set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node, - DECL_RESULT(this->get_decl()), retval); - ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR, - void_type_node, set); - - Expression* ref = - Expression::make_temporary_reference(this->defer_stack_, end_loc); - tree tref = ref->get_tree(&context); - tree s = build3_loc(end_loc.gcc_location(), COND_EXPR, void_type_node, - tref, ret_stmt, NULL_TREE); - - append_to_statement_list(s, &stmt_list); - - } - - go_assert(*fini == NULL_TREE); - *fini = stmt_list; -} - -// Return the value to assign to DECL_RESULT(this->get_decl()). This may -// also add statements to STMT_LIST, which need to be executed before -// the assignment. This is used for a return statement with no -// explicit values. - -tree -Function::return_value(Gogo* gogo, Named_object* named_function, - Location location, tree* stmt_list) const -{ - const Typed_identifier_list* results = this->type_->results(); - if (results == NULL || results->empty()) - return NULL_TREE; - - go_assert(this->results_ != NULL); - if (this->results_->size() != results->size()) - { - go_assert(saw_errors()); - return error_mark_node; - } - - tree retval; - if (results->size() == 1) - { - Bvariable* bvar = - this->results_->front()->get_backend_variable(gogo, - named_function); - tree ret = var_to_tree(bvar); - if (this->results_->front()->result_var_value()->is_in_heap()) - ret = build_fold_indirect_ref_loc(location.gcc_location(), ret); - return ret; - } - else - { - tree rettype = TREE_TYPE(DECL_RESULT(this->get_decl())); - retval = create_tmp_var(rettype, "RESULT"); - tree field = TYPE_FIELDS(rettype); - int index = 0; - for (Typed_identifier_list::const_iterator pr = results->begin(); - pr != results->end(); - ++pr, ++index, field = DECL_CHAIN(field)) - { - go_assert(field != NULL); - Named_object* no = (*this->results_)[index]; - Bvariable* bvar = no->get_backend_variable(gogo, named_function); - tree val = var_to_tree(bvar); - if (no->result_var_value()->is_in_heap()) - val = build_fold_indirect_ref_loc(location.gcc_location(), val); - tree set = fold_build2_loc(location.gcc_location(), MODIFY_EXPR, - void_type_node, - build3(COMPONENT_REF, TREE_TYPE(field), - retval, field, NULL_TREE), - val); - append_to_statement_list(set, stmt_list); - } - return retval; - } -} - // Build the descriptor for a function declaration. This won't // necessarily happen if the package has just a declaration for the // function and no other reference to it, but we may still need the @@ -1834,38 +1301,6 @@ go_type_for_mode(enum machine_mode mode, int unsignedp) return NULL_TREE; } -// Return a tree which allocates SIZE bytes which will holds value of -// type TYPE. - -tree -Gogo::allocate_memory(Type* type, tree size, Location location) -{ - // If the package imports unsafe, then it may play games with - // pointers that look like integers. - if (this->imported_unsafe_ || type->has_pointer()) - { - static tree new_fndecl; - return Gogo::call_builtin(&new_fndecl, - location, - "__go_new", - 1, - ptr_type_node, - sizetype, - size); - } - else - { - static tree new_nopointers_fndecl; - return Gogo::call_builtin(&new_nopointers_fndecl, - location, - "__go_new_nopointers", - 1, - ptr_type_node, - sizetype, - size); - } -} - // Build a builtin struct with a list of fields. The name is // STRUCT_NAME. STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE // node; this exists so that the struct can have fields which point to @@ -1915,94 +1350,6 @@ Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type, return struct_type; } -// Return a type to use for pointer to const char for a string. - -tree -Gogo::const_char_pointer_type_tree() -{ - static tree type; - if (type == NULL_TREE) - { - tree const_char_type = build_qualified_type(unsigned_char_type_node, - TYPE_QUAL_CONST); - type = build_pointer_type(const_char_type); - go_preserve_from_gc(type); - } - return type; -} - -// Return a tree for a string constant. - -tree -Gogo::string_constant_tree(const std::string& val) -{ - tree index_type = build_index_type(size_int(val.length())); - tree const_char_type = build_qualified_type(unsigned_char_type_node, - TYPE_QUAL_CONST); - tree string_type = build_array_type(const_char_type, index_type); - string_type = build_variant_type_copy(string_type); - TYPE_STRING_FLAG(string_type) = 1; - tree string_val = build_string(val.length(), val.data()); - TREE_TYPE(string_val) = string_type; - return string_val; -} - -// Return a tree for a Go string constant. - -tree -Gogo::go_string_constant_tree(const std::string& val) -{ - tree string_type = type_to_tree(Type::make_string_type()->get_backend(this)); - - vec *init; - vec_alloc(init, 2); - - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = init->quick_push(empty); - tree field = TYPE_FIELDS(string_type); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__data") == 0); - elt->index = field; - tree str = Gogo::string_constant_tree(val); - elt->value = fold_convert(TREE_TYPE(field), - build_fold_addr_expr(str)); - - elt = init->quick_push(empty); - field = DECL_CHAIN(field); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__length") == 0); - elt->index = field; - elt->value = build_int_cst_type(TREE_TYPE(field), val.length()); - - tree constructor = build_constructor(string_type, init); - TREE_READONLY(constructor) = 1; - TREE_CONSTANT(constructor) = 1; - - return constructor; -} - -// Return a tree for a pointer to a Go string constant. This is only -// used for type descriptors, so we return a pointer to a constant -// decl. - -tree -Gogo::ptr_go_string_constant_tree(const std::string& val) -{ - tree pval = this->go_string_constant_tree(val); - - tree decl = build_decl(UNKNOWN_LOCATION, VAR_DECL, - create_tmp_var_name("SP"), TREE_TYPE(pval)); - DECL_EXTERNAL(decl) = 0; - TREE_PUBLIC(decl) = 0; - TREE_USED(decl) = 1; - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - TREE_STATIC(decl) = 1; - DECL_ARTIFICIAL(decl) = 1; - DECL_INITIAL(decl) = pval; - rest_of_decl_compilation(decl, 1, 0); - - return build_fold_addr_expr(decl); -} - // Build a constructor for a slice. SLICE_TYPE_TREE is the type of // the slice. VALUES is the value pointer and COUNT is the number of // entries. If CAPACITY is not NULL, it is the capacity; otherwise @@ -2048,136 +1395,6 @@ Gogo::slice_constructor(tree slice_type_tree, tree values, tree count, return build_constructor(slice_type_tree, init); } -// Build an interface method table for a type: a list of function -// pointers, one for each interface method. This is used for -// interfaces. - -tree -Gogo::interface_method_table_for_type(const Interface_type* interface, - Type* type, bool is_pointer) -{ - const Typed_identifier_list* interface_methods = interface->methods(); - go_assert(!interface_methods->empty()); - - std::string mangled_name = ((is_pointer ? "__go_pimt__" : "__go_imt_") - + interface->mangled_name(this) - + "__" - + type->mangled_name(this)); - - tree id = get_identifier_from_string(mangled_name); - - // See whether this interface has any hidden methods. - bool has_hidden_methods = false; - for (Typed_identifier_list::const_iterator p = interface_methods->begin(); - p != interface_methods->end(); - ++p) - { - if (Gogo::is_hidden_name(p->name())) - { - has_hidden_methods = true; - break; - } - } - - // We already know that the named type is convertible to the - // interface. If the interface has hidden methods, and the named - // type is defined in a different package, then the interface - // conversion table will be defined by that other package. - if (has_hidden_methods - && type->named_type() != NULL - && type->named_type()->named_object()->package() != NULL) - { - tree array_type = build_array_type(const_ptr_type_node, NULL); - tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type); - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; - go_preserve_from_gc(decl); - return decl; - } - - size_t count = interface_methods->size(); - vec *pointers; - vec_alloc(pointers, count + 1); - - // The first element is the type descriptor. - constructor_elt empty = {NULL, NULL}; - constructor_elt* elt = pointers->quick_push(empty); - elt->index = size_zero_node; - Type* td_type; - if (!is_pointer) - td_type = type; - else - td_type = Type::make_pointer_type(type); - - Location loc = Linemap::predeclared_location(); - Bexpression* tdp_bexpr = td_type->type_descriptor_pointer(this, loc); - tree tdp = expr_to_tree(tdp_bexpr); - elt->value = fold_convert(const_ptr_type_node, tdp); - - Named_type* nt = type->named_type(); - Struct_type* st = type->struct_type(); - go_assert(nt != NULL || st != NULL); - size_t i = 1; - for (Typed_identifier_list::const_iterator p = interface_methods->begin(); - p != interface_methods->end(); - ++p, ++i) - { - bool is_ambiguous; - Method* m; - if (nt != NULL) - m = nt->method_function(p->name(), &is_ambiguous); - else - m = st->method_function(p->name(), &is_ambiguous); - go_assert(m != NULL); - - Named_object* no = m->named_object(); - Bfunction* bf; - if (no->is_function()) - bf = no->func_value()->get_or_make_decl(this, no); - else if (no->is_function_declaration()) - bf = no->func_declaration_value()->get_or_make_decl(this, no); - else - go_unreachable(); - tree fndecl = build_fold_addr_expr(function_to_tree(bf)); - - elt = pointers->quick_push(empty); - elt->index = size_int(i); - elt->value = fold_convert(const_ptr_type_node, fndecl); - } - go_assert(i == count + 1); - - tree array_type = build_array_type(const_ptr_type_node, - build_index_type(size_int(count))); - tree constructor = build_constructor(array_type, pointers); - - tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type); - TREE_STATIC(decl) = 1; - TREE_USED(decl) = 1; - TREE_READONLY(decl) = 1; - TREE_CONSTANT(decl) = 1; - DECL_INITIAL(decl) = constructor; - - // If the interface type has hidden methods, and the table is for a - // named type, then this is the only definition of the table. - // Otherwise it is a comdat table which may be defined in multiple - // packages. - if (has_hidden_methods && type->named_type() != NULL) - TREE_PUBLIC(decl) = 1; - else - { - make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl)); - resolve_unique_section(decl, 1, 0); - } - - rest_of_decl_compilation(decl, 1, 0); - - go_preserve_from_gc(decl); - - return decl; -} - // Mark a function as a builtin library function. void @@ -2250,70 +1467,3 @@ Gogo::call_builtin(tree* pdecl, Location location, const char* name, return ret; } - -// Return a tree for receiving a value of type TYPE_TREE on CHANNEL. -// TYPE_DESCRIPTOR_TREE is the channel's type descriptor. This does a -// blocking receive and returns the value read from the channel. - -tree -Gogo::receive_from_channel(tree type_tree, tree type_descriptor_tree, - tree channel, Location location) -{ - if (type_tree == error_mark_node || channel == error_mark_node) - return error_mark_node; - - if (int_size_in_bytes(type_tree) <= 8 - && !AGGREGATE_TYPE_P(type_tree) - && !FLOAT_TYPE_P(type_tree)) - { - static tree receive_small_fndecl; - tree call = Gogo::call_builtin(&receive_small_fndecl, - location, - "__go_receive_small", - 2, - uint64_type_node, - TREE_TYPE(type_descriptor_tree), - type_descriptor_tree, - ptr_type_node, - channel); - if (call == error_mark_node) - return error_mark_node; - // This can panic if there are too many operations on a closed - // channel. - TREE_NOTHROW(receive_small_fndecl) = 0; - int bitsize = GET_MODE_BITSIZE(TYPE_MODE(type_tree)); - tree int_type_tree = go_type_for_size(bitsize, 1); - return fold_convert_loc(location.gcc_location(), type_tree, - fold_convert_loc(location.gcc_location(), - int_type_tree, call)); - } - else - { - tree tmp = create_tmp_var(type_tree, get_name(type_tree)); - DECL_IGNORED_P(tmp) = 0; - TREE_ADDRESSABLE(tmp) = 1; - tree make_tmp = build1(DECL_EXPR, void_type_node, tmp); - SET_EXPR_LOCATION(make_tmp, location.gcc_location()); - tree tmpaddr = build_fold_addr_expr(tmp); - tmpaddr = fold_convert(ptr_type_node, tmpaddr); - static tree receive_big_fndecl; - tree call = Gogo::call_builtin(&receive_big_fndecl, - location, - "__go_receive_big", - 3, - void_type_node, - TREE_TYPE(type_descriptor_tree), - type_descriptor_tree, - ptr_type_node, - channel, - ptr_type_node, - tmpaddr); - if (call == error_mark_node) - return error_mark_node; - // This can panic if there are too many operations on a closed - // channel. - TREE_NOTHROW(receive_big_fndecl) = 0; - return build2(COMPOUND_EXPR, type_tree, make_tmp, - build2(COMPOUND_EXPR, type_tree, call, tmp)); - } -} diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index 9739f289f4d..6df4b6bf325 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -1005,6 +1005,10 @@ Label* Gogo::add_label_definition(const std::string& label_name, Location location) { + // A label with a blank identifier is never declared or defined. + if (label_name == "_") + return NULL; + go_assert(!this->functions_.empty()); Function* func = this->functions_.back().function->func_value(); Label* label = func->add_label_definition(this, label_name, location); @@ -3330,6 +3334,7 @@ Build_method_tables::type(Type* type) Struct_type* st = type->struct_type(); if (nt != NULL || st != NULL) { + Translate_context context(this->gogo_, NULL, NULL, NULL); for (std::vector::const_iterator p = this->interfaces_.begin(); p != this->interfaces_.end(); @@ -3343,8 +3348,8 @@ Build_method_tables::type(Type* type) if ((*p)->implements_interface(Type::make_pointer_type(nt), NULL)) { - nt->interface_method_table(this->gogo_, *p, false); - nt->interface_method_table(this->gogo_, *p, true); + nt->interface_method_table(*p, false)->get_tree(&context); + nt->interface_method_table(*p, true)->get_tree(&context); } } else @@ -3352,8 +3357,8 @@ Build_method_tables::type(Type* type) if ((*p)->implements_interface(Type::make_pointer_type(st), NULL)) { - st->interface_method_table(this->gogo_, *p, false); - st->interface_method_table(this->gogo_, *p, true); + st->interface_method_table(*p, false)->get_tree(&context); + st->interface_method_table(*p, true)->get_tree(&context); } } } @@ -3361,6 +3366,28 @@ Build_method_tables::type(Type* type) return TRAVERSE_CONTINUE; } +// Return an expression which allocates memory to hold values of type TYPE. + +Expression* +Gogo::allocate_memory(Type* type, Location location) +{ + Btype* btype = type->get_backend(this); + size_t size = this->backend()->type_size(btype); + mpz_t size_val; + mpz_init_set_ui(size_val, size); + Type* uintptr = Type::lookup_integer_type("uintptr"); + Expression* size_expr = + Expression::make_integer(&size_val, uintptr, location); + + // If the package imports unsafe, then it may play games with + // pointers that look like integers. + bool use_new_pointers = this->imported_unsafe_ || type->has_pointer(); + return Runtime::make_call((use_new_pointers + ? Runtime::NEW + : Runtime::NEW_NOPOINTERS), + location, 1, size_expr); +} + // Traversal class used to check for return statements. class Check_return_statements_traverse : public Traverse @@ -4111,6 +4138,293 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) return this->fndecl_; } +// Build the backend representation for the function code. + +void +Function::build(Gogo* gogo, Named_object* named_function) +{ + Translate_context context(gogo, named_function, NULL, NULL); + + // A list of parameter variables for this function. + std::vector param_vars; + + // Variables that need to be declared for this function and their + // initial values. + std::vector vars; + std::vector var_inits; + for (Bindings::const_definitions_iterator p = + this->block_->bindings()->begin_definitions(); + p != this->block_->bindings()->end_definitions(); + ++p) + { + Location loc = (*p)->location(); + if ((*p)->is_variable() && (*p)->var_value()->is_parameter()) + { + Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); + Bvariable* parm_bvar = bvar; + + // We always pass the receiver to a method as a pointer. If + // the receiver is declared as a non-pointer type, then we + // copy the value into a local variable. + if ((*p)->var_value()->is_receiver() + && (*p)->var_value()->type()->points_to() == NULL) + { + std::string name = (*p)->name() + ".pointer"; + Type* var_type = (*p)->var_value()->type(); + Variable* parm_var = + new Variable(Type::make_pointer_type(var_type), NULL, false, + true, false, loc); + Named_object* parm_no = + Named_object::make_variable(name, NULL, parm_var); + parm_bvar = parm_no->get_backend_variable(gogo, named_function); + + vars.push_back(bvar); + Expression* parm_ref = + Expression::make_var_reference(parm_no, loc); + parm_ref = Expression::make_unary(OPERATOR_MULT, parm_ref, loc); + if ((*p)->var_value()->is_in_heap()) + parm_ref = Expression::make_heap_expression(parm_ref, loc); + var_inits.push_back(tree_to_expr(parm_ref->get_tree(&context))); + } + else if ((*p)->var_value()->is_in_heap()) + { + // If we take the address of a parameter, then we need + // to copy it into the heap. + std::string parm_name = (*p)->name() + ".param"; + Variable* parm_var = new Variable((*p)->var_value()->type(), NULL, + false, true, false, loc); + Named_object* parm_no = + Named_object::make_variable(parm_name, NULL, parm_var); + parm_bvar = parm_no->get_backend_variable(gogo, named_function); + + vars.push_back(bvar); + Expression* var_ref = + Expression::make_var_reference(parm_no, loc); + var_ref = Expression::make_heap_expression(var_ref, loc); + var_inits.push_back(tree_to_expr(var_ref->get_tree(&context))); + } + param_vars.push_back(parm_bvar); + } + else if ((*p)->is_result_variable()) + { + Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function); + + Type* type = (*p)->result_var_value()->type(); + Bexpression* init; + if (!(*p)->result_var_value()->is_in_heap()) + { + Btype* btype = type->get_backend(gogo); + init = gogo->backend()->zero_expression(btype); + } + else + { + Expression* alloc = Expression::make_allocation(type, loc); + init = tree_to_expr(alloc->get_tree(&context)); + } + + vars.push_back(bvar); + var_inits.push_back(init); + } + } + if (!gogo->backend()->function_set_parameters(this->fndecl_, param_vars)) + { + go_assert(saw_errors()); + return; + } + + // If we need a closure variable, fetch it by calling a runtime + // function. The caller will have called __go_set_closure before + // the function call. + if (this->closure_var_ != NULL) + { + Bvariable* closure_bvar = + this->closure_var_->get_backend_variable(gogo, named_function); + vars.push_back(closure_bvar); + + Expression* closure = + Runtime::make_call(Runtime::GET_CLOSURE, this->location_, 0); + var_inits.push_back(tree_to_expr(closure->get_tree(&context))); + } + + if (this->block_ != NULL) + { + // Declare variables if necessary. + Bblock* var_decls = NULL; + + Bstatement* defer_init = NULL; + if (!vars.empty() || this->defer_stack_ != NULL) + { + var_decls = + gogo->backend()->block(this->fndecl_, NULL, vars, + this->block_->start_location(), + this->block_->end_location()); + + if (this->defer_stack_ != NULL) + { + Translate_context dcontext(gogo, named_function, this->block_, + var_decls); + defer_init = this->defer_stack_->get_backend(&dcontext); + } + } + + // Build the backend representation for all the statements in the + // function. + Translate_context context(gogo, named_function, NULL, NULL); + Bblock* code_block = this->block_->get_backend(&context); + + // Initialize variables if necessary. + std::vector init; + go_assert(vars.size() == var_inits.size()); + for (size_t i = 0; i < vars.size(); ++i) + { + Bstatement* init_stmt = + gogo->backend()->init_statement(vars[i], var_inits[i]); + init.push_back(init_stmt); + } + Bstatement* var_init = gogo->backend()->statement_list(init); + + // Initialize all variables before executing this code block. + Bstatement* code_stmt = gogo->backend()->block_statement(code_block); + code_stmt = gogo->backend()->compound_statement(var_init, code_stmt); + + // If we have a defer stack, initialize it at the start of a + // function. + Bstatement* except = NULL; + Bstatement* fini = NULL; + if (defer_init != NULL) + { + // Clean up the defer stack when we leave the function. + this->build_defer_wrapper(gogo, named_function, &except, &fini); + + // Wrap the code for this function in an exception handler to handle + // defer calls. + code_stmt = + gogo->backend()->exception_handler_statement(code_stmt, + except, fini, + this->location_); + } + + // Stick the code into the block we built for the receiver, if + // we built one. + if (var_decls != NULL) + { + std::vector code_stmt_list(1, code_stmt); + gogo->backend()->block_add_statements(var_decls, code_stmt_list); + code_stmt = gogo->backend()->block_statement(var_decls); + } + + if (!gogo->backend()->function_set_body(this->fndecl_, code_stmt)) + { + go_assert(saw_errors()); + return; + } + } + + // If we created a descriptor for the function, make sure we emit it. + if (this->descriptor_ != NULL) + { + Translate_context context(gogo, NULL, NULL, NULL); + this->descriptor_->get_tree(&context); + } +} + +// Build the wrappers around function code needed if the function has +// any defer statements. This sets *EXCEPT to an exception handler +// and *FINI to a finally handler. + +void +Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function, + Bstatement** except, Bstatement** fini) +{ + Location end_loc = this->block_->end_location(); + + // Add an exception handler. This is used if a panic occurs. Its + // purpose is to stop the stack unwinding if a deferred function + // calls recover. There are more details in + // libgo/runtime/go-unwind.c. + + std::vector stmts; + Expression* call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1, + this->defer_stack(end_loc)); + Translate_context context(gogo, named_function, NULL, NULL); + Bexpression* defer = tree_to_expr(call->get_tree(&context)); + stmts.push_back(gogo->backend()->expression_statement(defer)); + + Bstatement* ret_bstmt = this->return_value(gogo, named_function, end_loc); + if (ret_bstmt != NULL) + stmts.push_back(ret_bstmt); + + go_assert(*except == NULL); + *except = gogo->backend()->statement_list(stmts); + + call = Runtime::make_call(Runtime::CHECK_DEFER, end_loc, 1, + this->defer_stack(end_loc)); + defer = tree_to_expr(call->get_tree(&context)); + + call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1, + this->defer_stack(end_loc)); + Bexpression* undefer = tree_to_expr(call->get_tree(&context)); + Bstatement* function_defer = + gogo->backend()->function_defer_statement(this->fndecl_, undefer, defer, + end_loc); + stmts = std::vector(1, function_defer); + if (this->type_->results() != NULL + && !this->type_->results()->empty() + && !this->type_->results()->front().name().empty()) + { + // If the result variables are named, and we are returning from + // this function rather than panicing through it, we need to + // return them again, because they might have been changed by a + // defer function. The runtime routines set the defer_stack + // variable to true if we are returning from this function. + + ret_bstmt = this->return_value(gogo, named_function, end_loc); + Bexpression* nil = + tree_to_expr(Expression::make_nil(end_loc)->get_tree(&context)); + Bexpression* ret = + gogo->backend()->compound_expression(ret_bstmt, nil, end_loc); + Expression* ref = + Expression::make_temporary_reference(this->defer_stack_, end_loc); + Bexpression* bref = tree_to_expr(ref->get_tree(&context)); + ret = gogo->backend()->conditional_expression(NULL, bref, ret, NULL, + end_loc); + stmts.push_back(gogo->backend()->expression_statement(ret)); + } + + go_assert(*fini == NULL); + *fini = gogo->backend()->statement_list(stmts); +} + +// Return the statement that assigns values to this function's result struct. + +Bstatement* +Function::return_value(Gogo* gogo, Named_object* named_function, + Location location) const +{ + const Typed_identifier_list* results = this->type_->results(); + if (results == NULL || results->empty()) + return NULL; + + go_assert(this->results_ != NULL); + if (this->results_->size() != results->size()) + { + go_assert(saw_errors()); + return gogo->backend()->error_statement(); + } + + std::vector vals(results->size()); + for (size_t i = 0; i < vals.size(); ++i) + { + Named_object* no = (*this->results_)[i]; + Bvariable* bvar = no->get_backend_variable(gogo, named_function); + Bexpression* val = gogo->backend()->var_expression(bvar, location); + if (no->result_var_value()->is_in_heap()) + val = gogo->backend()->indirect_expression(val, true, location); + vals[i] = val; + } + return gogo->backend()->return_statement(this->fndecl_, vals, location); +} + // Class Block. Block::Block(Block* enclosing, Location location) @@ -4857,6 +5171,74 @@ Variable::determine_type() } } +// Get the initial value of a variable. This does not +// consider whether the variable is in the heap--it returns the +// initial value as though it were always stored in the stack. + +Bexpression* +Variable::get_init(Gogo* gogo, Named_object* function) +{ + go_assert(this->preinit_ == NULL); + Location loc = this->location(); + if (this->init_ == NULL) + { + go_assert(!this->is_parameter_); + if (this->is_global_ || this->is_in_heap()) + return NULL; + Btype* btype = this->type()->get_backend(gogo); + return gogo->backend()->zero_expression(btype); + } + else + { + Translate_context context(gogo, function, NULL, NULL); + Expression* init = Expression::make_cast(this->type(), this->init_, loc); + return tree_to_expr(init->get_tree(&context)); + } +} + +// Get the initial value of a variable when a block is required. +// VAR_DECL is the decl to set; it may be NULL for a sink variable. + +Bstatement* +Variable::get_init_block(Gogo* gogo, Named_object* function, + Bvariable* var_decl) +{ + go_assert(this->preinit_ != NULL); + + // We want to add the variable assignment to the end of the preinit + // block. + + Translate_context context(gogo, function, NULL, NULL); + Bblock* bblock = this->preinit_->get_backend(&context); + + // It's possible to have pre-init statements without an initializer + // if the pre-init statements set the variable. + Bstatement* decl_init = NULL; + if (this->init_ != NULL) + { + if (var_decl == NULL) + { + Bexpression* init_bexpr = + tree_to_expr(this->init_->get_tree(&context)); + decl_init = gogo->backend()->expression_statement(init_bexpr); + } + else + { + Location loc = this->location(); + Expression* val_expr = + Expression::convert_for_assignment(gogo, this->type(), + this->init_, this->location()); + Bexpression* val = tree_to_expr(val_expr->get_tree(&context)); + Bexpression* var_ref = gogo->backend()->var_expression(var_decl, loc); + decl_init = gogo->backend()->assignment_statement(var_ref, val, loc); + } + } + Bstatement* block_stmt = gogo->backend()->block_statement(bblock); + if (decl_init != NULL) + block_stmt = gogo->backend()->compound_statement(block_stmt, decl_init); + return block_stmt; +} + // Export the variable void diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 3f2808781b7..3dc401d6955 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -612,34 +612,9 @@ class Gogo void build_interface_method_tables(); - // Build an interface method table for a type: a list of function - // pointers, one for each interface method. This returns a decl. - tree - interface_method_table_for_type(const Interface_type*, Type*, - bool is_pointer); - - // Return a tree which allocate SIZE bytes to hold values of type - // TYPE. - tree - allocate_memory(Type *type, tree size, Location); - - // Return a type to use for pointer to const char. - static tree - const_char_pointer_type_tree(); - - // Build a string constant with the right type. - static tree - string_constant_tree(const std::string&); - - // Build a Go string constant. This returns a pointer to the - // constant. - tree - go_string_constant_tree(const std::string&); - - // Receive a value from a channel. - static tree - receive_from_channel(tree type_tree, tree type_descriptor_tree, tree channel, - Location); + // Return an expression which allocates memory to hold values of type TYPE. + Expression* + allocate_memory(Type *type, Location); private: // During parsing, we keep a stack of functions. Each function on @@ -687,11 +662,6 @@ class Gogo void register_gc_vars(const std::vector&, tree*); - // Build a pointer to a Go string constant. This returns a pointer - // to the pointer. - tree - ptr_go_string_constant_tree(const std::string&); - // Type used to map import names to packages. typedef std::map Imports; @@ -1119,14 +1089,14 @@ class Function tree get_decl() const; - // Set the function decl to hold a tree of the function code. + // Set the function decl to hold a backend representation of the function + // code. void - build_tree(Gogo*, Named_object*); + build(Gogo*, Named_object*); - // Get the value to return when not explicitly specified. May also - // add statements to execute first to STMT_LIST. - tree - return_value(Gogo*, Named_object*, Location, tree* stmt_list) const; + // Get the statement that assigns values to this function's result struct. + Bstatement* + return_value(Gogo*, Named_object*, Location) const; // Get a tree for the variable holding the defer stack. Expression* @@ -1151,14 +1121,8 @@ class Function // Type for mapping from label names to Label objects. typedef Unordered_map(std::string, Label*) Labels; - tree - make_receiver_parm_decl(Gogo*, Named_object*, tree); - - tree - copy_parm_to_heap(Gogo*, Named_object*, tree); - void - build_defer_wrapper(Gogo*, Named_object*, tree*, tree*); + build_defer_wrapper(Gogo*, Named_object*, Bstatement**, Bstatement**); typedef std::vector > Closure_fields; @@ -1531,16 +1495,16 @@ class Variable get_backend_variable(Gogo*, Named_object*, const Package*, const std::string&); - // Get the initial value of the variable as a tree. This may only + // Get the initial value of the variable. This may only // be called if has_pre_init() returns false. - tree - get_init_tree(Gogo*, Named_object* function); + Bexpression* + get_init(Gogo*, Named_object* function); // Return a series of statements which sets the value of the // variable in DECL. This should only be called is has_pre_init() // returns true. DECL may be NULL for a sink variable. - tree - get_init_block(Gogo*, Named_object* function, tree decl); + Bstatement* + get_init_block(Gogo*, Named_object* function, Bvariable* decl); // Export the variable. void diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 7614e6fc795..3d60171dde2 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -2955,7 +2955,7 @@ Parse::create_closure(Named_object* function, Enclosing_vars* enclosing_vars, Struct_type* st = closure_var->var_value()->type()->deref()->struct_type(); Expression* cv = Expression::make_struct_composite_literal(st, initializer, location); - return Expression::make_heap_composite(cv, location); + return Expression::make_heap_expression(cv, location); } // PrimaryExpr = Operand { Selector | Index | Slice | TypeGuard | Call } . @@ -3538,7 +3538,7 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit, expr = Expression::make_type(Type::make_pointer_type(expr->type()), location); else if (op == OPERATOR_AND && expr->is_composite_literal()) - expr = Expression::make_heap_composite(expr, location); + expr = Expression::make_heap_expression(expr, location); else if (op != OPERATOR_CHANOP) expr = Expression::make_unary(op, expr, location); else @@ -3765,7 +3765,8 @@ Parse::labeled_stmt(const std::string& label_name, Location location) { // Mark the label as used to avoid a useless error about an // unused label. - label->set_is_used(); + if (label != NULL) + label->set_is_used(); error_at(location, "missing statement after label"); this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON, diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index a303a50410f..8c6e82b2267 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -142,11 +142,8 @@ DEF_GO_RUNTIME(SEND_SMALL, "__go_send_small", P3(TYPE, CHAN, UINT64), R0()) // Send a big value on a channel. DEF_GO_RUNTIME(SEND_BIG, "__go_send_big", P3(TYPE, CHAN, POINTER), R0()) -// Receive a small value from a channel. -DEF_GO_RUNTIME(RECEIVE_SMALL, "__go_receive_small", P2(TYPE, CHAN), R1(UINT64)) - -// Receive a big value from a channel. -DEF_GO_RUNTIME(RECEIVE_BIG, "__go_receive_big", P3(TYPE, CHAN, POINTER), R0()) +// Receive a value from a channel. +DEF_GO_RUNTIME(RECEIVE, "__go_receive", P3(TYPE, CHAN, POINTER), R0()) // Receive a value from a channel returning whether it is closed. DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P3(TYPE, CHAN, POINTER), @@ -208,7 +205,7 @@ DEF_GO_RUNTIME(RUNTIME_ERROR, "__go_runtime_error", P1(INT32), R0()) // Close. -DEF_GO_RUNTIME(CLOSE, "__go_close", P1(CHAN), R0()) +DEF_GO_RUNTIME(CLOSE, "__go_builtin_close", P1(CHAN), R0()) // Copy. @@ -233,6 +230,11 @@ DEF_GO_RUNTIME(NEW_NOPOINTERS, "__go_new_nopointers", P1(UINTPTR), R1(POINTER)) // Start a new goroutine. DEF_GO_RUNTIME(GO, "__go_go", P2(FUNC_PTR, POINTER), R0()) +// Get the function closure. +DEF_GO_RUNTIME(GET_CLOSURE, "__go_get_closure", P0(), R1(POINTER)) + +// Set the function closure. +DEF_GO_RUNTIME(SET_CLOSURE, "__go_set_closure", P1(POINTER), R0()) // Defer a function. DEF_GO_RUNTIME(DEFER, "__go_defer", P3(BOOLPTR, FUNC_PTR, POINTER), R0()) @@ -270,7 +272,7 @@ DEF_GO_RUNTIME(IFACEI2T2, "runtime.ifaceI2T2", P3(TYPE, IFACE, POINTER), // 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()) +DEF_GO_RUNTIME(ASSERT_INTERFACE, "__go_assert_interface", P2(TYPE, TYPE), R1(POINTER)) // Convert one interface type to another. This is used for an // assignment. diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index d195ab9845a..49a864faa44 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -264,8 +264,7 @@ Variable_declaration_statement::do_get_backend(Translate_context* context) Variable* var = this->var_->var_value(); Bvariable* bvar = this->var_->get_backend_variable(context->gogo(), context->function()); - tree init = var->get_init_tree(context->gogo(), context->function()); - Bexpression* binit = init == NULL ? NULL : tree_to_expr(init); + Bexpression* binit = var->get_init(context->gogo(), context->function()); if (!var->is_in_heap()) { @@ -638,13 +637,17 @@ Assignment_statement::do_check_types(Gogo*) Bstatement* Assignment_statement::do_get_backend(Translate_context* context) { - tree rhs_tree = this->rhs_->get_tree(context); if (this->lhs_->is_sink_expression()) - return context->backend()->expression_statement(tree_to_expr(rhs_tree)); + { + tree rhs_tree = this->rhs_->get_tree(context); + return context->backend()->expression_statement(tree_to_expr(rhs_tree)); + } + tree lhs_tree = this->lhs_->get_tree(context); - rhs_tree = Expression::convert_for_assignment(context, this->lhs_->type(), - this->rhs_->type(), rhs_tree, - this->location()); + Expression* rhs = + Expression::convert_for_assignment(context->gogo(), this->lhs_->type(), + this->rhs_, this->location()); + tree rhs_tree = rhs->get_tree(context); return context->backend()->assignment_statement(tree_to_expr(lhs_tree), tree_to_expr(rhs_tree), this->location()); @@ -2187,7 +2190,7 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function, location); // Allocate the initialized struct on the heap. - constructor = Expression::make_heap_composite(constructor, location); + constructor = Expression::make_heap_expression(constructor, location); // Look up the thunk. Named_object* named_thunk = gogo->lookup(thunk_name, NULL); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 2148a1a43e6..91a535f01c8 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -3075,34 +3075,6 @@ String_type::do_get_backend(Gogo* gogo) return backend_string_type; } -// Return a tree for the length of STRING. - -tree -String_type::length_tree(Gogo*, tree string) -{ - tree string_type = TREE_TYPE(string); - go_assert(TREE_CODE(string_type) == RECORD_TYPE); - tree length_field = DECL_CHAIN(TYPE_FIELDS(string_type)); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(length_field)), - "__length") == 0); - return fold_build3(COMPONENT_REF, TREE_TYPE(length_field), string, - length_field, NULL_TREE); -} - -// Return a tree for a pointer to the bytes of STRING. - -tree -String_type::bytes_tree(Gogo*, tree string) -{ - tree string_type = TREE_TYPE(string); - go_assert(TREE_CODE(string_type) == RECORD_TYPE); - tree bytes_field = TYPE_FIELDS(string_type); - go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(bytes_field)), - "__data") == 0); - return fold_build3(COMPONENT_REF, TREE_TYPE(bytes_field), string, - bytes_field, NULL_TREE); -} - // The type descriptor for the string type. Expression* @@ -4916,9 +4888,8 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const // the interface INTERFACE. IS_POINTER is true if this is for a // pointer to THIS. -tree -Struct_type::interface_method_table(Gogo* gogo, - const Interface_type* interface, +Expression* +Struct_type::interface_method_table(Interface_type* interface, bool is_pointer) { std::pair @@ -4937,7 +4908,7 @@ Struct_type::interface_method_table(Gogo* gogo, ins.first->second = smtp; } - return Type::interface_method_table(gogo, this, interface, is_pointer, + return Type::interface_method_table(this, interface, is_pointer, &smtp->first, &smtp->second); } @@ -8198,13 +8169,12 @@ Named_type::method_function(const std::string& name, bool* is_ambiguous) const // the interface INTERFACE. IS_POINTER is true if this is for a // pointer to THIS. -tree -Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface, - bool is_pointer) +Expression* +Named_type::interface_method_table(Interface_type* interface, bool is_pointer) { - return Type::interface_method_table(gogo, this, interface, is_pointer, - &this->interface_method_tables_, - &this->pointer_interface_method_tables_); + return Type::interface_method_table(this, interface, is_pointer, + &this->interface_method_tables_, + &this->pointer_interface_method_tables_); } // Return whether a named type has any hidden fields. @@ -9385,9 +9355,9 @@ Type::method_function(const Methods* methods, const std::string& name, // Return a pointer to the interface method table for TYPE for the // interface INTERFACE. -tree -Type::interface_method_table(Gogo* gogo, Type* type, - const Interface_type *interface, +Expression* +Type::interface_method_table(Type* type, + Interface_type *interface, bool is_pointer, Interface_method_tables** method_tables, Interface_method_tables** pointer_tables) @@ -9399,23 +9369,18 @@ Type::interface_method_table(Gogo* gogo, Type* type, if (*pimt == NULL) *pimt = new Interface_method_tables(5); - std::pair val(interface, NULL_TREE); + std::pair val(interface, NULL); std::pair ins = (*pimt)->insert(val); + Location loc = Linemap::predeclared_location(); if (ins.second) { // This is a new entry in the hash table. - go_assert(ins.first->second == NULL_TREE); - ins.first->second = gogo->interface_method_table_for_type(interface, - type, - is_pointer); + go_assert(ins.first->second == NULL); + ins.first->second = + Expression::make_interface_mtable_ref(interface, type, is_pointer, loc); } - - tree decl = ins.first->second; - if (decl == error_mark_node) - return error_mark_node; - go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL); - return build_fold_addr_expr(decl); + return Expression::make_unary(OPERATOR_AND, ins.first->second, loc); } // Look for field or method NAME for TYPE. Return an Expression for diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 5fda4e7285e..d2ca1bf27fb 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -1019,14 +1019,14 @@ class Type // A mapping from interfaces to the associated interface method // tables for this type. This maps to a decl. - typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical, + typedef Unordered_map_hash(Interface_type*, Expression*, Type_hash_identical, Type_identical) Interface_method_tables; // Return a pointer to the interface method table for TYPE for the // interface INTERFACE. - static tree - interface_method_table(Gogo* gogo, Type* type, - const Interface_type *interface, bool is_pointer, + static Expression* + interface_method_table(Type* type, + Interface_type *interface, bool is_pointer, Interface_method_tables** method_tables, Interface_method_tables** pointer_tables); @@ -1688,14 +1688,6 @@ class String_type : public Type : Type(TYPE_STRING) { } - // Return a tree for the length of STRING. - static tree - length_tree(Gogo*, tree string); - - // Return a tree which points to the bytes of STRING. - static tree - bytes_tree(Gogo*, tree string); - protected: bool do_has_pointer() const @@ -2205,9 +2197,8 @@ class Struct_type : public Type // the interface INTERFACE. If IS_POINTER is true, set the type // descriptor to a pointer to this type, otherwise set it to this // type. - tree - interface_method_table(Gogo*, const Interface_type* interface, - bool is_pointer); + Expression* + interface_method_table(Interface_type* interface, bool is_pointer); // Traverse just the field types of a struct type. int @@ -2946,9 +2937,8 @@ class Named_type : public Type // the interface INTERFACE. If IS_POINTER is true, set the type // descriptor to a pointer to this type, otherwise set it to this // type. - tree - interface_method_table(Gogo*, const Interface_type* interface, - bool is_pointer); + Expression* + interface_method_table(Interface_type* interface, bool is_pointer); // Whether this type has any hidden fields. bool diff --git a/libgo/runtime/chan.c b/libgo/runtime/chan.c index 1d9e6681d35..38a2aafc775 100644 --- a/libgo/runtime/chan.c +++ b/libgo/runtime/chan.c @@ -483,31 +483,10 @@ __go_send_big(ChanType *t, Hchan* c, byte* p) runtime_chansend(t, c, p, nil, runtime_getcallerpc(&t)); } -// The compiler generates a call to __go_receive_small to receive a -// value 8 bytes or smaller. -uint64 -__go_receive_small(ChanType *t, Hchan* c) -{ - union { - byte b[sizeof(uint64)]; - uint64 v; - } u; - byte *p; - - u.v = 0; -#ifndef WORDS_BIGENDIAN - p = u.b; -#else - p = u.b + sizeof(uint64) - t->__element_type->__size; -#endif - runtime_chanrecv(t, c, p, nil, nil); - return u.v; -} - -// The compiler generates a call to __go_receive_big to receive a -// value larger than 8 bytes. +// The compiler generates a call to __go_receive to receive a +// value from a channel. void -__go_receive_big(ChanType *t, Hchan* c, byte* p) +__go_receive(ChanType *t, Hchan* c, byte* p) { runtime_chanrecv(t, c, p, nil, nil); } -- 2.11.4.GIT