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
This commit is contained in:
Chris Manghane 2014-04-14 22:43:47 +00:00 committed by Ian Lance Taylor
parent 88f592e3f4
commit 7035307e8f
14 changed files with 2985 additions and 2881 deletions

View File

@ -1,3 +1,22 @@
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

View File

@ -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"
@ -234,6 +235,18 @@ class Gcc_backend : public Backend
Bexpression*
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);
@ -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;

View File

@ -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.

File diff suppressed because it is too large Load Diff

View File

@ -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

File diff suppressed because it is too large Load Diff

View File

@ -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

View File

@ -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

View File

@ -2955,7 +2955,7 @@ Parse::create_closure(Named_object* function, Enclosing_vars* enclosing_vars,
Struct_type* st = closure_var->var_value()->type()->deref()->struct_type();
Expression* cv = Expression::make_struct_composite_literal(st, initializer,
location);
return Expression::make_heap_composite(cv, location);
return Expression::make_heap_expression(cv, location);
}
// PrimaryExpr = Operand { Selector | Index | Slice | TypeGuard | Call } .
@ -3538,7 +3538,7 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
expr = Expression::make_type(Type::make_pointer_type(expr->type()),
location);
else if (op == OPERATOR_AND && expr->is_composite_literal())
expr = Expression::make_heap_composite(expr, location);
expr = Expression::make_heap_expression(expr, location);
else if (op != OPERATOR_CHANOP)
expr = Expression::make_unary(op, expr, location);
else
@ -3765,7 +3765,8 @@ Parse::labeled_stmt(const std::string& label_name, Location location)
{
// Mark the label as used to avoid a useless error about an
// unused label.
label->set_is_used();
if (label != NULL)
label->set_is_used();
error_at(location, "missing statement after label");
this->unget_token(Token::make_operator_token(OPERATOR_SEMICOLON,

View File

@ -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.

View File

@ -264,8 +264,7 @@ Variable_declaration_statement::do_get_backend(Translate_context* context)
Variable* var = this->var_->var_value();
Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
context->function());
tree init = var->get_init_tree(context->gogo(), context->function());
Bexpression* binit = init == NULL ? NULL : tree_to_expr(init);
Bexpression* binit = var->get_init(context->gogo(), context->function());
if (!var->is_in_heap())
{
@ -638,13 +637,17 @@ Assignment_statement::do_check_types(Gogo*)
Bstatement*
Assignment_statement::do_get_backend(Translate_context* context)
{
tree rhs_tree = this->rhs_->get_tree(context);
if (this->lhs_->is_sink_expression())
return context->backend()->expression_statement(tree_to_expr(rhs_tree));
{
tree rhs_tree = this->rhs_->get_tree(context);
return context->backend()->expression_statement(tree_to_expr(rhs_tree));
}
tree lhs_tree = this->lhs_->get_tree(context);
rhs_tree = Expression::convert_for_assignment(context, this->lhs_->type(),
this->rhs_->type(), rhs_tree,
this->location());
Expression* rhs =
Expression::convert_for_assignment(context->gogo(), this->lhs_->type(),
this->rhs_, this->location());
tree rhs_tree = rhs->get_tree(context);
return context->backend()->assignment_statement(tree_to_expr(lhs_tree),
tree_to_expr(rhs_tree),
this->location());
@ -2187,7 +2190,7 @@ Thunk_statement::simplify_statement(Gogo* gogo, Named_object* function,
location);
// Allocate the initialized struct on the heap.
constructor = Expression::make_heap_composite(constructor, location);
constructor = Expression::make_heap_expression(constructor, location);
// Look up the thunk.
Named_object* named_thunk = gogo->lookup(thunk_name, NULL);

View File

@ -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,13 +8169,12 @@ Named_type::method_function(const std::string& name, bool* is_ambiguous) const
// the interface INTERFACE. IS_POINTER is true if this is for a
// pointer to THIS.
tree
Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
bool is_pointer)
Expression*
Named_type::interface_method_table(Interface_type* interface, bool is_pointer)
{
return Type::interface_method_table(gogo, this, interface, is_pointer,
&this->interface_method_tables_,
&this->pointer_interface_method_tables_);
return Type::interface_method_table(this, interface, is_pointer,
&this->interface_method_tables_,
&this->pointer_interface_method_tables_);
}
// Return whether a named type has any hidden fields.
@ -9385,9 +9355,9 @@ Type::method_function(const Methods* methods, const std::string& name,
// Return a pointer to the interface method table for TYPE for the
// interface INTERFACE.
tree
Type::interface_method_table(Gogo* gogo, Type* type,
const Interface_type *interface,
Expression*
Type::interface_method_table(Type* type,
Interface_type *interface,
bool is_pointer,
Interface_method_tables** method_tables,
Interface_method_tables** pointer_tables)
@ -9399,23 +9369,18 @@ Type::interface_method_table(Gogo* gogo, Type* type,
if (*pimt == NULL)
*pimt = new Interface_method_tables(5);
std::pair<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

View File

@ -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

View File

@ -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);
}