Commit 7035307e by Chris Manghane Committed by Ian Lance Taylor

Sync to current external repository.

user:        Ian Lance Taylor <iant@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
date:        Fri Mar 07 16:02:18 2014 -0800
files:       go/expressions.cc
description:
compiler: Use backend interface for constant expressions.


user:        Chris Manghane <cmang@golang.org>
date:        Thu Mar 06 16:00:18 2014 -0800
files:       go/expressions.cc
description:
compiler: Use backend interface for struct construction.


user:        Chris Manghane <cmang@golang.org>
date:        Wed Mar 05 13:09:37 2014 -0800
files:       go/expressions.cc
description:
compiler: Use backend interface for type conversions.


user:        Chris Manghane <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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 <cmang@golang.org>
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.

From-SVN: r209393
parent 88f592e3
2014-04-14 Chris Manghane <cmang@google.com>
* 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 <iant@google.com>
* go-gcc.cc (Gcc_backend::immutable_struct): If IS_COMMON, set
......
......@@ -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<Bexpression*>&, Location);
Bexpression*
array_constructor_expression(Btype*, const std::vector<unsigned long>&,
const std::vector<Bexpression*>&, 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<Bexpression*>& args,
Location);
// Statements.
Bstatement*
......@@ -294,6 +324,10 @@ class Gcc_backend : public Backend
Bstatement*
statement_list(const std::vector<Bstatement*>&);
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<Bvariable*>&);
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<Bexpression*>& vals,
Location location)
{
tree type_tree = btype->get_tree();
if (type_tree == error_mark_node)
return this->error_expression();
vec<constructor_elt, va_gc> *init;
vec_alloc(init, vals.size());
bool is_constant = true;
tree field = TYPE_FIELDS(type_tree);
for (std::vector<Bexpression*>::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<unsigned long>& indexes,
const std::vector<Bexpression*>& 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<constructor_elt, va_gc> *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<Bexpression*>& 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<Bvariable*>& param_vars)
{
tree func_tree = function->get_tree();
if (func_tree == error_mark_node)
return false;
tree params = NULL_TREE;
tree *pp = &params;
for (std::vector<Bvariable*>::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;
......
......@@ -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<Bexpression*>& 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<unsigned long>& indexes,
const std::vector<Bexpression*>& 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<Bexpression*>& 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<Bstatement*>&) = 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<Bvariable*>& 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.
......
This source diff could not be displayed because it is too large. You can view the blob instead.
......@@ -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<Temporary_statement*>* 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
......
......@@ -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_init> 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 = &params;
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<constructor_elt, va_gc> *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<constructor_elt, va_gc> *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));
}
}
......@@ -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<Interface_type*>::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<Bvariable*> param_vars;
// Variables that need to be declared for this function and their
// initial values.
std::vector<Bvariable*> vars;
std::vector<Bexpression*> 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<Bstatement*> 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<Bstatement*> 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<Bstatement*> 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<Bstatement*>(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<Bexpression*> 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
......
......@@ -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<Named_object*>&, 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<std::string, Package*> 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<std::pair<Named_object*,
Location> > 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
......
......@@ -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,6 +3765,7 @@ Parse::labeled_stmt(const std::string& label_name, Location location)
{
// Mark the label as used to avoid a useless error about an
// unused label.
if (label != NULL)
label->set_is_used();
error_at(location, "missing statement after label");
......
......@@ -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.
......
......@@ -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())
{
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);
......
......@@ -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<Struct_type*, Struct_type::Struct_method_table_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,11 +8169,10 @@ 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,
return Type::interface_method_table(this, interface, is_pointer,
&this->interface_method_tables_,
&this->pointer_interface_method_tables_);
}
......@@ -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<const Interface_type*, tree> val(interface, NULL_TREE);
std::pair<Interface_type*, Expression*> val(interface, NULL);
std::pair<Interface_method_tables::iterator, bool> 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
......
......@@ -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
......
......@@ -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);
}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment