#include "types.h"
#include "expressions.h"
#include "statements.h"
+#include "runtime.h"
+#include "backend.h"
#include "gogo.h"
// Whether we have seen any errors.
libname, NULL_TREE);
if (const_p)
TREE_READONLY(decl) = 1;
- built_in_decls[bcode] = decl;
- implicit_built_in_decls[bcode] = decl;
+ set_builtin_decl(bcode, decl, true);
builtin_functions[name] = decl;
if (libname != NULL)
{
for ++ and --. */
tree t = go_type_for_size(BITS_PER_UNIT, 1);
tree p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
- define_builtin(BUILT_IN_ADD_AND_FETCH_1, "__sync_fetch_and_add_1", NULL,
+ define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_1, "__sync_fetch_and_add_1", NULL,
build_function_type_list(t, p, t, NULL_TREE), false);
t = go_type_for_size(BITS_PER_UNIT * 2, 1);
p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
- define_builtin (BUILT_IN_ADD_AND_FETCH_2, "__sync_fetch_and_add_2", NULL,
+ define_builtin (BUILT_IN_SYNC_ADD_AND_FETCH_2, "__sync_fetch_and_add_2", NULL,
build_function_type_list(t, p, t, NULL_TREE), false);
t = go_type_for_size(BITS_PER_UNIT * 4, 1);
p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
- define_builtin(BUILT_IN_ADD_AND_FETCH_4, "__sync_fetch_and_add_4", NULL,
+ define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_4, "__sync_fetch_and_add_4", NULL,
build_function_type_list(t, p, t, NULL_TREE), false);
t = go_type_for_size(BITS_PER_UNIT * 8, 1);
p = build_pointer_type(build_qualified_type(t, TYPE_QUAL_VOLATILE));
- define_builtin(BUILT_IN_ADD_AND_FETCH_8, "__sync_fetch_and_add_8", NULL,
+ define_builtin(BUILT_IN_SYNC_ADD_AND_FETCH_8, "__sync_fetch_and_add_8", NULL,
build_function_type_list(t, p, t, NULL_TREE), false);
// We use __builtin_expect for magic import functions.
NULL_TREE),
true);
- // We use __builtin_memmove for the predeclared copy function.
- define_builtin(BUILT_IN_MEMMOVE, "__builtin_memmove", "memmove",
- build_function_type_list(ptr_type_node,
- ptr_type_node,
+ // We use __builtin_memcmp for struct comparisons.
+ define_builtin(BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp",
+ build_function_type_list(integer_type_node,
+ const_ptr_type_node,
const_ptr_type_node,
size_type_node,
NULL_TREE),
false);
- // We provide sqrt for the math library.
- define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt",
+ // We provide some functions for the math library.
+ tree math_function_type = build_function_type_list(double_type_node,
+ double_type_node,
+ NULL_TREE);
+ tree math_function_type_long =
+ build_function_type_list(long_double_type_node, long_double_type_node,
+ long_double_type_node, NULL_TREE);
+ tree math_function_type_two = build_function_type_list(double_type_node,
+ double_type_node,
+ double_type_node,
+ NULL_TREE);
+ tree math_function_type_long_two =
+ build_function_type_list(long_double_type_node, long_double_type_node,
+ long_double_type_node, NULL_TREE);
+ define_builtin(BUILT_IN_ACOS, "__builtin_acos", "acos",
+ math_function_type, true);
+ define_builtin(BUILT_IN_ACOSL, "__builtin_acosl", "acosl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_ASIN, "__builtin_asin", "asin",
+ math_function_type, true);
+ define_builtin(BUILT_IN_ASINL, "__builtin_asinl", "asinl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_ATAN, "__builtin_atan", "atan",
+ math_function_type, true);
+ define_builtin(BUILT_IN_ATANL, "__builtin_atanl", "atanl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_ATAN2, "__builtin_atan2", "atan2",
+ math_function_type_two, true);
+ define_builtin(BUILT_IN_ATAN2L, "__builtin_atan2l", "atan2l",
+ math_function_type_long_two, true);
+ define_builtin(BUILT_IN_CEIL, "__builtin_ceil", "ceil",
+ math_function_type, true);
+ define_builtin(BUILT_IN_CEILL, "__builtin_ceill", "ceill",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_COS, "__builtin_cos", "cos",
+ math_function_type, true);
+ define_builtin(BUILT_IN_COSL, "__builtin_cosl", "cosl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_EXP, "__builtin_exp", "exp",
+ math_function_type, true);
+ define_builtin(BUILT_IN_EXPL, "__builtin_expl", "expl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_EXPM1, "__builtin_expm1", "expm1",
+ math_function_type, true);
+ define_builtin(BUILT_IN_EXPM1L, "__builtin_expm1l", "expm1l",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_FABS, "__builtin_fabs", "fabs",
+ math_function_type, true);
+ define_builtin(BUILT_IN_FABSL, "__builtin_fabsl", "fabsl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_FLOOR, "__builtin_floor", "floor",
+ math_function_type, true);
+ define_builtin(BUILT_IN_FLOORL, "__builtin_floorl", "floorl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_FMOD, "__builtin_fmod", "fmod",
+ math_function_type_two, true);
+ define_builtin(BUILT_IN_FMODL, "__builtin_fmodl", "fmodl",
+ math_function_type_long_two, true);
+ define_builtin(BUILT_IN_LDEXP, "__builtin_ldexp", "ldexp",
build_function_type_list(double_type_node,
double_type_node,
+ integer_type_node,
NULL_TREE),
true);
- define_builtin(BUILT_IN_SQRTL, "__builtin_sqrtl", "sqrtl",
+ define_builtin(BUILT_IN_LDEXPL, "__builtin_ldexpl", "ldexpl",
build_function_type_list(long_double_type_node,
long_double_type_node,
+ integer_type_node,
NULL_TREE),
true);
+ define_builtin(BUILT_IN_LOG, "__builtin_log", "log",
+ math_function_type, true);
+ define_builtin(BUILT_IN_LOGL, "__builtin_logl", "logl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_LOG1P, "__builtin_log1p", "log1p",
+ math_function_type, true);
+ define_builtin(BUILT_IN_LOG1PL, "__builtin_log1pl", "log1pl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_LOG10, "__builtin_log10", "log10",
+ math_function_type, true);
+ define_builtin(BUILT_IN_LOG10L, "__builtin_log10l", "log10l",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_LOG2, "__builtin_log2", "log2",
+ math_function_type, true);
+ define_builtin(BUILT_IN_LOG2L, "__builtin_log2l", "log2l",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_SIN, "__builtin_sin", "sin",
+ math_function_type, true);
+ define_builtin(BUILT_IN_SINL, "__builtin_sinl", "sinl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_SQRT, "__builtin_sqrt", "sqrt",
+ math_function_type, true);
+ define_builtin(BUILT_IN_SQRTL, "__builtin_sqrtl", "sqrtl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_TAN, "__builtin_tan", "tan",
+ math_function_type, true);
+ define_builtin(BUILT_IN_TANL, "__builtin_tanl", "tanl",
+ math_function_type_long, true);
+ define_builtin(BUILT_IN_TRUNC, "__builtin_trunc", "trunc",
+ math_function_type, true);
+ define_builtin(BUILT_IN_TRUNCL, "__builtin_truncl", "truncl",
+ math_function_type_long, true);
// We use __builtin_return_address in the thunk we build for
// functions which call recover.
{
if (this->init_fn_name_.empty())
{
- gcc_assert(this->package_ != NULL);
+ go_assert(this->package_ != NULL);
if (this->is_main_package())
{
// Use a name which the runtime knows.
void
Gogo::init_imports(tree* init_stmt_list)
{
- gcc_assert(this->is_main_package());
+ go_assert(this->is_main_package());
if (this->imported_init_fns_.empty())
return;
constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
tree field = TYPE_FIELDS(root_type);
elt->index = field;
- tree decl = (*p)->get_tree(this, NULL);
- gcc_assert(TREE_CODE(decl) == VAR_DECL);
+ Bvariable* bvar = (*p)->get_backend_variable(this, NULL);
+ tree decl = var_to_tree(bvar);
+ go_assert(TREE_CODE(decl) == VAR_DECL);
elt->value = build_fold_addr_expr(decl);
elt = VEC_quick_push(constructor_elt, init, NULL);
rest_of_decl_compilation(decl, 1, 0);
static tree register_gc_fndecl;
- tree call = Gogo::call_builtin(®ister_gc_fndecl, BUILTINS_LOCATION,
- "__go_register_gc_roots",
+ tree call = Gogo::call_builtin(®ister_gc_fndecl,
+ Linemap::predeclared_location(),
+ "__go_register_gc_roots",
1,
void_type_node,
build_pointer_type(root_list_type),
{
// Make sure that we thought we needed an initialization function,
// as otherwise we will not have reported it in the export data.
- gcc_assert(this->is_main_package() || this->need_init_fn_);
+ go_assert(this->is_main_package() || this->need_init_fn_);
if (fndecl == NULL_TREE)
fndecl = this->initialization_function_decl();
gimplify_function_tree(fndecl);
cgraph_add_new_function(fndecl, false);
- cgraph_mark_needed_node(cgraph_node(fndecl));
+ cgraph_mark_needed_node(cgraph_get_node(fndecl));
current_function_decl = NULL_TREE;
pop_cfun();
return TRAVERSE_CONTINUE;
}
-// Return true if EXPR refers to VAR.
+// Return true if EXPR, PREINIT, or DEP refers to VAR.
static bool
-expression_requires(Expression* expr, Block* preinit, Named_object* var)
+expression_requires(Expression* expr, Block* preinit, Named_object* dep,
+ Named_object* var)
{
Find_var::Seen_objects seen_objects;
Find_var find_var(var, &seen_objects);
Expression::traverse(&expr, &find_var);
if (preinit != NULL)
preinit->traverse(&find_var);
-
+ if (dep != NULL)
+ {
+ Expression* init = dep->var_value()->init();
+ if (init != NULL)
+ Expression::traverse(&init, &find_var);
+ if (dep->var_value()->has_pre_init())
+ dep->var_value()->preinit()->traverse(&find_var);
+ }
+
return find_var.found();
}
// variable V2 then we initialize V1 after V2.
static void
-sort_var_inits(Var_inits* var_inits)
+sort_var_inits(Gogo* gogo, Var_inits* var_inits)
{
Var_inits ready;
while (!var_inits->empty())
Named_object* var = p1->var();
Expression* init = var->var_value()->init();
Block* preinit = var->var_value()->preinit();
+ Named_object* dep = gogo->var_depends_on(var->var_value());
// Start walking through the list to see which variables VAR
// needs to wait for. We can skip P1->WAITING variables--that
for (; p2 != var_inits->end(); ++p2)
{
- if (expression_requires(init, preinit, p2->var()))
+ Named_object* p2var = p2->var();
+ if (expression_requires(init, preinit, dep, p2var))
{
// Check for cycles.
- if (expression_requires(p2->var()->var_value()->init(),
- p2->var()->var_value()->preinit(),
+ if (expression_requires(p2var->var_value()->init(),
+ p2var->var_value()->preinit(),
+ gogo->var_depends_on(p2var->var_value()),
var))
{
error_at(var->location(),
("initialization expressions for %qs and "
"%qs depend upon each other"),
var->message_name().c_str(),
- p2->var()->message_name().c_str());
+ p2var->message_name().c_str());
inform(p2->var()->location(), "%qs defined here",
- p2->var()->message_name().c_str());
+ p2var->message_name().c_str());
p2 = var_inits->end();
}
else
// VAR does not depends upon any other initialization expressions.
// Check for a loop of VAR on itself. We only do this if
- // INIT is not NULL; when INIT is NULL, it means that
- // PREINIT sets VAR, which we will interpret as a loop.
- if (init != NULL && expression_requires(init, preinit, var))
+ // INIT is not NULL and there is no dependency; when INIT is
+ // NULL, it means that PREINIT sets VAR, which we will
+ // interpret as a loop.
+ if (init != NULL && dep == NULL
+ && expression_requires(init, preinit, NULL, var))
error_at(var->location(),
"initialization expression for %qs depends upon itself",
var->message_name().c_str());
this->build_interface_method_tables();
Bindings* bindings = this->current_bindings();
- size_t count = bindings->size_definitions();
+ size_t count_definitions = bindings->size_definitions();
+ size_t count = count_definitions;
tree* vec = new tree[count];
{
Named_object* no = *p;
- gcc_assert(!no->is_type_declaration() && !no->is_function_declaration());
+ go_assert(!no->is_type_declaration() && !no->is_function_declaration());
// There is nothing to do for a package.
if (no->is_package())
{
}
// There is nothing useful we can output for constants which
- // have ideal or non-integeral type.
+ // have ideal or non-integral type.
if (no->is_const())
{
Type* type = no->const_value()->type();
}
}
- vec[i] = no->get_tree(this, NULL);
-
- if (vec[i] == error_mark_node)
+ if (!no->is_variable())
{
- gcc_assert(saw_errors());
- --i;
- --count;
- continue;
+ vec[i] = no->get_tree(this, NULL);
+ if (vec[i] == error_mark_node)
+ {
+ go_assert(saw_errors());
+ --i;
+ --count;
+ continue;
+ }
}
-
- // If a variable is initialized to a non-constant value, do the
- // initialization in an initialization function.
- if (TREE_CODE(vec[i]) == VAR_DECL)
+ else
{
- gcc_assert(no->is_variable());
+ Bvariable* var = no->get_backend_variable(this, NULL);
+ vec[i] = var_to_tree(var);
+ if (vec[i] == error_mark_node)
+ {
+ go_assert(saw_errors());
+ --i;
+ --count;
+ continue;
+ }
- // Check for a sink variable, which may be used to run
- // an initializer purely for its side effects.
+ // Check for a sink variable, which may be used to run an
+ // initializer purely for its side effects.
bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
tree var_init_tree = NULL_TREE;
{
tree init = no->var_value()->get_init_tree(this, NULL);
if (init == error_mark_node)
- gcc_assert(saw_errors());
+ go_assert(saw_errors());
else if (init == NULL_TREE)
;
else if (TREE_CONSTANT(init))
- DECL_INITIAL(vec[i]) = init;
- else if (is_sink)
+ {
+ if (expression_requires(no->var_value()->init(), NULL,
+ this->var_depends_on(no->var_value()),
+ no))
+ error_at(no->location(),
+ "initialization expression for %qs depends "
+ "upon itself",
+ no->message_name().c_str());
+ this->backend()->global_variable_set_init(var,
+ tree_to_expr(init));
+ }
+ 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
- var_init_tree = fold_build2_loc(no->location(), MODIFY_EXPR,
- void_type_node, vec[i], init);
+ var_init_tree = fold_build2_loc(no->location().gcc_location(),
+ MODIFY_EXPR, void_type_node,
+ vec[i], init);
}
else
{
else
var_inits.push_back(Var_init(no, var_init_tree));
}
+ else if (this->var_depends_on(no->var_value()) != NULL)
+ {
+ // This variable is initialized from something that is
+ // 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));
+ }
if (!is_sink && no->var_value()->type()->has_pointer())
var_gc.push_back(no);
// workable order.
if (!var_inits.empty())
{
- sort_var_inits(&var_inits);
+ sort_var_inits(this, &var_inits);
for (Var_inits::const_iterator p = var_inits.begin();
p != var_inits.end();
++p)
|| this->is_main_package())
this->write_initialization_function(init_fndecl, init_stmt_list);
+ // We should not have seen any new bindings created during the
+ // conversion.
+ go_assert(count_definitions == this->current_bindings()->size_definitions());
+
// Pass everything back to the middle-end.
wrapup_global_declarations(vec, count);
tree
Named_object::get_id(Gogo* gogo)
{
+ go_assert(!this->is_variable() && !this->is_result_variable());
std::string decl_name;
if (this->is_function_declaration()
&& !this->func_declaration_value()->asm_name().empty())
decl_name = this->func_declaration_value()->asm_name();
- else if ((this->is_variable() && !this->var_value()->is_global())
- || (this->is_type()
- && this->type_value()->location() == BUILTINS_LOCATION))
+ else if (this->is_type()
+ && Linemap::is_predeclared_location(this->type_value()->location()))
{
- // We don't need the package name for local variables or builtin
- // types.
+ // We don't need the package name for builtin types.
decl_name = Gogo::unpack_hidden_name(this->name_);
}
else
Named_object::get_tree(Gogo* gogo, Named_object* function)
{
if (this->tree_ != NULL_TREE)
- {
- // If this is a variable whose address is taken, we must rebuild
- // the INDIRECT_REF each time to avoid invalid sharing.
- tree ret = this->tree_;
- if (((this->classification_ == NAMED_OBJECT_VAR
- && this->var_value()->is_in_heap())
- || (this->classification_ == NAMED_OBJECT_RESULT_VAR
- && this->result_var_value()->is_in_heap()))
- && ret != error_mark_node)
- {
- gcc_assert(TREE_CODE(ret) == INDIRECT_REF);
- ret = build_fold_indirect_ref(TREE_OPERAND(ret, 0));
- TREE_THIS_NOTRAP(ret) = 1;
- }
- return ret;
- }
+ return this->tree_;
tree name;
if (this->classification_ == NAMED_OBJECT_TYPE)
case NAMED_OBJECT_CONST:
{
Named_constant* named_constant = this->u_.const_value;
- Translate_context subcontext(gogo, function, NULL, NULL_TREE);
+ Translate_context subcontext(gogo, function, NULL, NULL);
tree expr_tree = named_constant->expr()->get_tree(&subcontext);
if (expr_tree == error_mark_node)
decl = error_mark_node;
Type* type = named_constant->type();
if (type != NULL && !type->is_abstract())
{
- if (!type->is_error())
- expr_tree = fold_convert(type->get_tree(gogo), expr_tree);
- else
+ if (type->is_error())
expr_tree = error_mark_node;
+ else
+ {
+ Btype* btype = type->get_backend(gogo);
+ expr_tree = fold_convert(type_to_tree(btype), expr_tree);
+ }
}
if (expr_tree == error_mark_node)
decl = error_mark_node;
else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree)))
{
- decl = build_decl(named_constant->location(), CONST_DECL,
- name, TREE_TYPE(expr_tree));
+ decl = build_decl(named_constant->location().gcc_location(),
+ CONST_DECL, name, TREE_TYPE(expr_tree));
DECL_INITIAL(decl) = expr_tree;
TREE_CONSTANT(decl) = 1;
TREE_READONLY(decl) = 1;
case NAMED_OBJECT_TYPE:
{
Named_type* named_type = this->u_.type_value;
- tree type_tree = named_type->get_tree(gogo);
+ tree type_tree = type_to_tree(named_type->get_backend(gogo));
if (type_tree == error_mark_node)
decl = error_mark_node;
else
{
decl = TYPE_NAME(type_tree);
- gcc_assert(decl != NULL_TREE);
+ go_assert(decl != NULL_TREE);
// We need to produce a type descriptor for every named
// type, and for a pointer to every named type, since
// descriptor, even though we don't do anything with it.
if (this->package_ == NULL)
{
- named_type->type_descriptor_pointer(gogo);
+ named_type->
+ type_descriptor_pointer(gogo,
+ Linemap::predeclared_location());
Type* pn = Type::make_pointer_type(named_type);
- pn->type_descriptor_pointer(gogo);
+ pn->type_descriptor_pointer(gogo,
+ Linemap::predeclared_location());
}
}
}
return error_mark_node;
case NAMED_OBJECT_VAR:
- {
- Variable* var = this->u_.var_value;
- Type* type = var->type();
- if (type->is_error_type()
- || (type->is_undefined()
- && (!var->is_global() || this->package() == NULL)))
- {
- // Force the error for an undefined type, just in case.
- type->base();
- decl = error_mark_node;
- }
- else
- {
- tree var_type = type->get_tree(gogo);
- bool is_parameter = var->is_parameter();
- if (var->is_receiver() && type->points_to() == NULL)
- is_parameter = false;
- if (var->is_in_heap())
- {
- is_parameter = false;
- var_type = build_pointer_type(var_type);
- }
- decl = build_decl(var->location(),
- is_parameter ? PARM_DECL : VAR_DECL,
- name, var_type);
- if (!var->is_global())
- {
- tree fnid = function->get_id(gogo);
- tree fndecl = function->func_value()->get_or_make_decl(gogo,
- function,
- fnid);
- DECL_CONTEXT(decl) = fndecl;
- }
- if (is_parameter)
- DECL_ARG_TYPE(decl) = TREE_TYPE(decl);
-
- if (var->is_global())
- {
- const Package* package = this->package();
- if (package == NULL)
- TREE_STATIC(decl) = 1;
- else
- DECL_EXTERNAL(decl) = 1;
- if (!Gogo::is_hidden_name(this->name_))
- {
- TREE_PUBLIC(decl) = 1;
- std::string asm_name = (package == NULL
- ? gogo->unique_prefix()
- : package->unique_prefix());
- asm_name.append(1, '.');
- asm_name.append(IDENTIFIER_POINTER(name),
- IDENTIFIER_LENGTH(name));
- tree asm_id = get_identifier_from_string(asm_name);
- SET_DECL_ASSEMBLER_NAME(decl, asm_id);
- }
- }
-
- // FIXME: We should only set this for variables which are
- // actually used somewhere.
- TREE_USED(decl) = 1;
- }
- }
- break;
-
case NAMED_OBJECT_RESULT_VAR:
- {
- Result_variable* result = this->u_.result_var_value;
- Type* type = result->type();
- if (type->is_error())
- decl = error_mark_node;
- else
- {
- gcc_assert(result->function() == function->func_value());
- source_location loc = function->location();
- tree result_type = type->get_tree(gogo);
- tree init;
- if (!result->is_in_heap())
- init = type->get_init_tree(gogo, false);
- else
- {
- tree space = gogo->allocate_memory(type,
- TYPE_SIZE_UNIT(result_type),
- loc);
- result_type = build_pointer_type(result_type);
- tree subinit = type->get_init_tree(gogo, true);
- if (subinit == NULL_TREE)
- init = fold_convert_loc(loc, result_type, space);
- else
- {
- space = save_expr(space);
- space = fold_convert_loc(loc, result_type, space);
- tree spaceref = build_fold_indirect_ref_loc(loc, space);
- TREE_THIS_NOTRAP(spaceref) = 1;
- tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
- spaceref, subinit);
- init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space),
- set, space);
- }
- }
- decl = build_decl(loc, VAR_DECL, name, result_type);
- tree fnid = function->get_id(gogo);
- tree fndecl = function->func_value()->get_or_make_decl(gogo,
- function,
- fnid);
- DECL_CONTEXT(decl) = fndecl;
- DECL_INITIAL(decl) = init;
- TREE_USED(decl) = 1;
- }
- }
- break;
-
case NAMED_OBJECT_SINK:
- gcc_unreachable();
+ go_unreachable();
case NAMED_OBJECT_FUNC:
{
else
push_cfun(DECL_STRUCT_FUNCTION(decl));
- cfun->function_end_locus = func->block()->end_location();
+ cfun->function_end_locus =
+ func->block()->end_location().gcc_location();
current_function_decl = decl;
}
break;
+ case NAMED_OBJECT_ERRONEOUS:
+ decl = error_mark_node;
+ break;
+
default:
- gcc_unreachable();
+ go_unreachable();
}
if (TREE_TYPE(decl) == error_mark_node)
tree ret = decl;
- // If this is a local variable whose address is taken, then we
- // actually store it in the heap. For uses of the variable we need
- // to return a reference to that heap location.
- if (((this->classification_ == NAMED_OBJECT_VAR
- && this->var_value()->is_in_heap())
- || (this->classification_ == NAMED_OBJECT_RESULT_VAR
- && this->result_var_value()->is_in_heap()))
- && ret != error_mark_node)
- {
- gcc_assert(POINTER_TYPE_P(TREE_TYPE(ret)));
- ret = build_fold_indirect_ref(ret);
- TREE_THIS_NOTRAP(ret) = 1;
- }
-
this->tree_ = ret;
if (ret != error_mark_node)
tree
Variable::get_init_tree(Gogo* gogo, Named_object* function)
{
- gcc_assert(this->preinit_ == NULL);
+ go_assert(this->preinit_ == NULL);
if (this->init_ == NULL)
{
- gcc_assert(!this->is_parameter_);
- return this->type_->get_init_tree(gogo, this->is_global_);
+ 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);
+ 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(),
tree
Variable::get_init_block(Gogo* gogo, Named_object* function, tree var_decl)
{
- gcc_assert(this->preinit_ != NULL);
+ 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_TREE);
- tree block_tree = this->preinit_->get_tree(&context);
+ 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;
- gcc_assert(TREE_CODE(block_tree) == BIND_EXPR);
+ 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
this->location());
if (val == error_mark_node)
return error_mark_node;
- tree set = fold_build2_loc(this->location(), MODIFY_EXPR,
- void_type_node, var_decl, val);
+ tree set = fold_build2_loc(this->location().gcc_location(),
+ MODIFY_EXPR, void_type_node, var_decl,
+ val);
append_to_statement_list(set, &statements);
}
}
{
if (this->fndecl_ == NULL_TREE)
{
- tree functype = this->type_->get_tree(gogo);
+ tree functype = type_to_tree(this->type_->get_backend(gogo));
if (functype == error_mark_node)
this->fndecl_ = error_mark_node;
else
{
// The type of a function comes back as a pointer, but we
// want the real function type for a function declaration.
- gcc_assert(POINTER_TYPE_P(functype));
+ go_assert(POINTER_TYPE_P(functype));
functype = TREE_TYPE(functype);
- tree decl = build_decl(this->location(), FUNCTION_DECL, id, functype);
+ tree decl = build_decl(this->location().gcc_location(), FUNCTION_DECL,
+ id, functype);
this->fndecl_ = decl;
// Why do we have to do this in the frontend?
tree restype = TREE_TYPE(functype);
- tree resdecl = build_decl(this->location(), RESULT_DECL, NULL_TREE,
- restype);
+ tree resdecl =
+ build_decl(this->location().gcc_location(), RESULT_DECL, NULL_TREE,
+ restype);
DECL_ARTIFICIAL(resdecl) = 1;
DECL_IGNORED_P(resdecl) = 1;
DECL_CONTEXT(resdecl) = decl;
// If a function calls the predeclared recover function, we
// can't inline it, because recover behaves differently in a
- // function passed directly to defer.
- if (this->calls_recover_ && !this->is_recover_thunk_)
+ // function passed directly to defer. If this is a recover
+ // thunk that we built to test whether a function can be
+ // recovered, we can't inline it, because that will mess up
+ // our return address comparison.
+ if (this->calls_recover_ || this->is_recover_thunk_)
DECL_UNINLINABLE(decl) = 1;
// If this is a thunk created to call a function which calls
{
push_struct_function(decl);
- tree closure_decl = this->closure_var_->get_tree(gogo, no);
+ Bvariable* bvar = this->closure_var_->get_backend_variable(gogo,
+ no);
+ tree closure_decl = var_to_tree(bvar);
if (closure_decl == error_mark_node)
this->fndecl_ = error_mark_node;
else
}
}
- tree functype = this->fntype_->get_tree(gogo);
+ tree functype = type_to_tree(this->fntype_->get_backend(gogo));
tree decl;
if (functype == error_mark_node)
decl = error_mark_node;
{
// The type of a function comes back as a pointer, but we
// want the real function type for a function declaration.
- gcc_assert(POINTER_TYPE_P(functype));
+ go_assert(POINTER_TYPE_P(functype));
functype = TREE_TYPE(functype);
- decl = build_decl(this->location(), FUNCTION_DECL, id, functype);
+ decl = build_decl(this->location().gcc_location(), FUNCTION_DECL, id,
+ functype);
TREE_PUBLIC(decl) = 1;
DECL_EXTERNAL(decl) = 1;
{
if (var_decl == error_mark_node)
return error_mark_node;
- // If the function takes the address of a receiver which is passed
- // by value, then we will have an INDIRECT_REF here. We need to get
- // the real variable.
+ 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();
- tree val_type;
- if (TREE_CODE(var_decl) != INDIRECT_REF)
+ if (is_in_heap)
{
- gcc_assert(!is_in_heap);
- val_type = TREE_TYPE(var_decl);
+ go_assert(POINTER_TYPE_P(val_type));
+ val_type = TREE_TYPE(val_type);
}
- else
- {
- gcc_assert(is_in_heap);
- var_decl = TREE_OPERAND(var_decl, 0);
- if (var_decl == error_mark_node)
- return error_mark_node;
- gcc_assert(POINTER_TYPE_P(TREE_TYPE(var_decl)));
- val_type = TREE_TYPE(TREE_TYPE(var_decl));
- }
- gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+
source_location loc = DECL_SOURCE_LOCATION(var_decl);
std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
name += ".pointer";
DECL_CONTEXT(parm_decl) = current_function_decl;
DECL_ARG_TYPE(parm_decl) = TREE_TYPE(parm_decl);
- gcc_assert(DECL_INITIAL(var_decl) == NULL_TREE);
- // The receiver might be passed as a null pointer.
- tree check = fold_build2_loc(loc, NE_EXPR, boolean_type_node, parm_decl,
- fold_convert_loc(loc, TREE_TYPE(parm_decl),
- null_pointer_node));
- tree ind = build_fold_indirect_ref_loc(loc, parm_decl);
- TREE_THIS_NOTRAP(ind) = 1;
- tree zero_init = no->var_value()->type()->get_init_tree(gogo, false);
- tree init = fold_build3_loc(loc, COND_EXPR, TREE_TYPE(ind),
- check, ind, zero_init);
+ go_assert(DECL_INITIAL(var_decl) == NULL_TREE);
+ tree init = build_fold_indirect_ref_loc(loc, parm_decl);
if (is_in_heap)
{
no->location());
space = save_expr(space);
space = fold_convert(build_pointer_type(val_type), space);
- tree spaceref = build_fold_indirect_ref_loc(no->location(), space);
+ tree spaceref = build_fold_indirect_ref_loc(no->location().gcc_location(),
+ space);
TREE_THIS_NOTRAP(spaceref) = 1;
- tree check = fold_build2_loc(loc, NE_EXPR, boolean_type_node,
- parm_decl,
- fold_convert_loc(loc, TREE_TYPE(parm_decl),
- null_pointer_node));
- tree parmref = build_fold_indirect_ref_loc(no->location(), parm_decl);
- TREE_THIS_NOTRAP(parmref) = 1;
tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
- spaceref, parmref);
- init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space),
- build3(COND_EXPR, void_type_node,
- check, set, NULL_TREE),
- space);
+ spaceref, init);
+ init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space), set, space);
}
DECL_INITIAL(var_decl) = init;
// indirection.
tree
-Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree ref)
+Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl)
{
- if (ref == error_mark_node)
- return error_mark_node;
-
- gcc_assert(TREE_CODE(ref) == INDIRECT_REF);
-
- tree var_decl = TREE_OPERAND(ref, 0);
if (var_decl == error_mark_node)
return error_mark_node;
- gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
- source_location loc = DECL_SOURCE_LOCATION(var_decl);
+ 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);
- gcc_assert(POINTER_TYPE_P(type));
+ go_assert(POINTER_TYPE_P(type));
type = TREE_TYPE(type);
- tree parm_decl = build_decl(loc, PARM_DECL, id, 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 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, 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),
Function::build_tree(Gogo* gogo, Named_object* named_function)
{
tree fndecl = this->fndecl_;
- gcc_assert(fndecl != NULL_TREE);
+ go_assert(fndecl != NULL_TREE);
tree params = NULL_TREE;
tree* pp = ¶ms;
{
if ((*p)->is_variable() && (*p)->var_value()->is_parameter())
{
- *pp = (*p)->get_tree(gogo, named_function);
+ 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
{
tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp);
tree var = *pp;
- if (TREE_CODE(var) == INDIRECT_REF)
- var = TREE_OPERAND(var, 0);
if (var != error_mark_node)
{
- gcc_assert(TREE_CODE(var) == VAR_DECL);
+ go_assert(TREE_CODE(var) == VAR_DECL);
DECL_CHAIN(var) = declare_vars;
declare_vars = var;
}
// 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);
- if (*pp != error_mark_node)
+ tree var = *pp;
+ if (var != error_mark_node)
{
- gcc_assert(TREE_CODE(*pp) == INDIRECT_REF);
- tree var_decl = TREE_OPERAND(*pp, 0);
- if (var_decl != error_mark_node)
- {
- gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
- DECL_CHAIN(var_decl) = declare_vars;
- declare_vars = var_decl;
- }
+ go_assert(TREE_CODE(var) == VAR_DECL);
+ DECL_CHAIN(var) = declare_vars;
+ declare_vars = var;
}
*pp = parm_decl;
}
if (*pp != error_mark_node)
{
- gcc_assert(TREE_CODE(*pp) == PARM_DECL);
+ go_assert(TREE_CODE(*pp) == PARM_DECL);
pp = &DECL_CHAIN(*pp);
}
}
else if ((*p)->is_result_variable())
{
- tree var_decl = (*p)->get_tree(gogo, named_function);
- if (var_decl != error_mark_node
- && (*p)->result_var_value()->is_in_heap())
+ 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())
{
- gcc_assert(TREE_CODE(var_decl) == INDIRECT_REF);
- var_decl = TREE_OPERAND(var_decl, 0);
+ 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)
{
- gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+ go_assert(TREE_CODE(var_decl) == VAR_DECL);
+ DECL_INITIAL(var_decl) = init;
DECL_CHAIN(var_decl) = declare_vars;
declare_vars = var_decl;
}
if (this->block_ != NULL)
{
- gcc_assert(DECL_INITIAL(fndecl) == NULL_TREE);
+ go_assert(DECL_INITIAL(fndecl) == NULL_TREE);
// Declare variables if necessary.
tree bind = NULL_TREE;
- if (declare_vars != 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_TREE);
- tree code = this->block_->get_tree(&context);
+ 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;
// If we have a defer stack, initialize it at the start of a
// function.
- if (this->defer_stack_ != NULL_TREE)
+ if (defer_init != NULL_TREE && defer_init != error_mark_node)
{
- tree defer_init = build1(DECL_EXPR, void_type_node,
- this->defer_stack_);
- SET_EXPR_LOCATION(defer_init, this->block_->start_location());
+ 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.
Function::build_defer_wrapper(Gogo* gogo, Named_object* named_function,
tree *except, tree *fini)
{
- source_location end_loc = this->block_->end_location();
+ 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;
- static tree check_fndecl;
- tree call = Gogo::call_builtin(&check_fndecl,
- end_loc,
- "__go_check_defer",
- 1,
- void_type_node,
- ptr_type_node,
- this->defer_stack(end_loc));
- if (call != error_mark_node)
- append_to_statement_list(call, &stmt_list);
+
+ 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, MODIFY_EXPR, void_type_node,
+ set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
DECL_RESULT(this->fndecl_), retval);
- tree ret_stmt = fold_build1_loc(end_loc, RETURN_EXPR, void_type_node, set);
+ tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR,
+ void_type_node, set);
append_to_statement_list(ret_stmt, &stmt_list);
- gcc_assert(*except == NULL_TREE);
+ go_assert(*except == NULL_TREE);
*except = stmt_list;
// Add some finally code to run the defer functions. This is used
stmt_list = NULL;
- tree label = create_artificial_label(end_loc);
- tree define_label = fold_build1_loc(end_loc, LABEL_EXPR, void_type_node,
- label);
+ 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);
- static tree undefer_fndecl;
- tree undefer = Gogo::call_builtin(&undefer_fndecl,
- end_loc,
- "__go_undefer",
- 1,
- void_type_node,
- ptr_type_node,
- this->defer_stack(end_loc));
- if (undefer_fndecl != NULL_TREE)
- TREE_NOTHROW(undefer_fndecl) = 0;
-
- tree defer = Gogo::call_builtin(&check_fndecl,
- end_loc,
- "__go_check_defer",
- 1,
- void_type_node,
- ptr_type_node,
- this->defer_stack(end_loc));
- tree jump = fold_build1_loc(end_loc, GOTO_EXPR, void_type_node, label);
+ 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);
&& !this->type_->results()->empty()
&& !this->type_->results()->front().name().empty())
{
- // If the result variables are named, we need to return them
- // again, because they might have been changed by a defer
- // function.
+ // 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, MODIFY_EXPR, void_type_node,
+ set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node,
DECL_RESULT(this->fndecl_), retval);
- ret_stmt = fold_build1_loc(end_loc, RETURN_EXPR, void_type_node, set);
- append_to_statement_list(ret_stmt, &stmt_list);
+ 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);
+
}
- gcc_assert(*fini == NULL_TREE);
+ go_assert(*fini == NULL_TREE);
*fini = stmt_list;
}
tree
Function::return_value(Gogo* gogo, Named_object* named_function,
- source_location location, tree* stmt_list) const
+ Location location, tree* stmt_list) const
{
const Typed_identifier_list* results = this->type_->results();
if (results == NULL || results->empty())
return NULL_TREE;
- gcc_assert(this->results_ != NULL);
+ go_assert(this->results_ != NULL);
if (this->results_->size() != results->size())
{
- gcc_assert(saw_errors());
+ go_assert(saw_errors());
return error_mark_node;
}
tree retval;
if (results->size() == 1)
- return this->results_->front()->get_tree(gogo, named_function);
+ {
+ 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->fndecl_));
pr != results->end();
++pr, ++index, field = DECL_CHAIN(field))
{
- gcc_assert(field != NULL);
- tree val;
- val = (*this->results_)[index]->get_tree(gogo, named_function);
- tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
+ 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);
}
}
-// Get the tree for the variable holding the defer stack for this
-// function. At least at present, the value of this variable is not
-// used. However, a pointer to this variable is used as a marker for
-// the functions on the defer stack associated with this function.
-// Doing things this way permits inlining a function which uses defer.
-
-tree
-Function::defer_stack(source_location location)
-{
- if (this->defer_stack_ == NULL_TREE)
- {
- tree var = create_tmp_var(ptr_type_node, "DEFER");
- DECL_INITIAL(var) = null_pointer_node;
- DECL_SOURCE_LOCATION(var) = location;
- TREE_ADDRESSABLE(var) = 1;
- this->defer_stack_ = var;
- }
- return fold_convert_loc(location, ptr_type_node,
- build_fold_addr_expr_loc(location,
- this->defer_stack_));
-}
-
-// Get a tree for the statements in a block.
-
-tree
-Block::get_tree(Translate_context* context)
-{
- Gogo* gogo = context->gogo();
-
- tree block = make_node(BLOCK);
-
- // Put the new block into the block tree.
-
- if (context->block() == NULL)
- {
- tree fndecl;
- if (context->function() != NULL)
- fndecl = context->function()->func_value()->get_decl();
- else
- fndecl = current_function_decl;
- gcc_assert(fndecl != NULL_TREE);
-
- // We may have already created a block for the receiver.
- if (DECL_INITIAL(fndecl) == NULL_TREE)
- {
- BLOCK_SUPERCONTEXT(block) = fndecl;
- DECL_INITIAL(fndecl) = block;
- }
- else
- {
- tree superblock_tree = DECL_INITIAL(fndecl);
- BLOCK_SUPERCONTEXT(block) = superblock_tree;
- gcc_assert(BLOCK_CHAIN(block) == NULL_TREE);
- BLOCK_CHAIN(block) = block;
- }
- }
- else
- {
- tree superblock_tree = context->block_tree();
- BLOCK_SUPERCONTEXT(block) = superblock_tree;
- tree* pp;
- for (pp = &BLOCK_SUBBLOCKS(superblock_tree);
- *pp != NULL_TREE;
- pp = &BLOCK_CHAIN(*pp))
- ;
- *pp = block;
- }
-
- // Expand local variables in the block.
-
- tree* pp = &BLOCK_VARS(block);
- for (Bindings::const_definitions_iterator pv =
- this->bindings_->begin_definitions();
- pv != this->bindings_->end_definitions();
- ++pv)
- {
- if ((!(*pv)->is_variable() || !(*pv)->var_value()->is_parameter())
- && !(*pv)->is_result_variable()
- && !(*pv)->is_const())
- {
- tree var = (*pv)->get_tree(gogo, context->function());
- if (var != error_mark_node && TREE_TYPE(var) != error_mark_node)
- {
- if ((*pv)->is_variable() && (*pv)->var_value()->is_in_heap())
- {
- gcc_assert(TREE_CODE(var) == INDIRECT_REF);
- var = TREE_OPERAND(var, 0);
- gcc_assert(TREE_CODE(var) == VAR_DECL);
- }
- *pp = var;
- pp = &DECL_CHAIN(*pp);
- }
- }
- }
- *pp = NULL_TREE;
-
- Translate_context subcontext(context->gogo(), context->function(),
- this, block);
-
- tree statements = NULL_TREE;
-
- // Expand the statements.
-
- for (std::vector<Statement*>::const_iterator p = this->statements_.begin();
- p != this->statements_.end();
- ++p)
- {
- tree statement = (*p)->get_tree(&subcontext);
- if (statement != error_mark_node)
- append_to_statement_list(statement, &statements);
- }
-
- TREE_USED(block) = 1;
-
- tree bind = build3(BIND_EXPR, void_type_node, BLOCK_VARS(block), statements,
- block);
- TREE_SIDE_EFFECTS(bind) = 1;
-
- return bind;
-}
-
-// Get the LABEL_DECL for a label.
-
-tree
-Label::get_decl()
-{
- if (this->decl_ == NULL)
- {
- tree id = get_identifier_from_string(this->name_);
- this->decl_ = build_decl(this->location_, LABEL_DECL, id, void_type_node);
- DECL_CONTEXT(this->decl_) = current_function_decl;
- }
- return this->decl_;
-}
-
-// Return an expression for the address of this label.
-
-tree
-Label::get_addr(source_location location)
-{
- tree decl = this->get_decl();
- TREE_USED(decl) = 1;
- TREE_ADDRESSABLE(decl) = 1;
- return fold_convert_loc(location, ptr_type_node,
- build_fold_addr_expr_loc(location, decl));
-}
-
-// Get the LABEL_DECL for an unnamed label.
-
-tree
-Unnamed_label::get_decl()
-{
- if (this->decl_ == NULL)
- this->decl_ = create_artificial_label(this->location_);
- return this->decl_;
-}
-
-// Get the LABEL_EXPR for an unnamed label.
-
-tree
-Unnamed_label::get_definition()
-{
- tree t = build1(LABEL_EXPR, void_type_node, this->get_decl());
- SET_EXPR_LOCATION(t, this->location_);
- return t;
-}
-
-// Return a goto to this label.
-
-tree
-Unnamed_label::get_goto(source_location location)
-{
- tree t = build1(GOTO_EXPR, void_type_node, this->get_decl());
- SET_EXPR_LOCATION(t, location);
- return t;
-}
-
// Return the integer type to use for a size.
GO_EXTERN_C
return NULL_TREE;
}
Type* type = Type::lookup_integer_type(name);
- return type->get_tree(go_get_gogo());
+ return type_to_tree(type->get_backend(go_get_gogo()));
}
// Return the type to use for a mode.
return long_double_type_node;
return NULL_TREE;
}
- return type->float_type()->type_tree();
+ return type_to_tree(type->get_backend(go_get_gogo()));
}
else if (mc == MODE_COMPLEX_FLOAT)
{
return complex_long_double_type_node;
return NULL_TREE;
}
- return type->complex_type()->type_tree();
+ return type_to_tree(type->get_backend(go_get_gogo()));
}
else
return NULL_TREE;
// type TYPE.
tree
-Gogo::allocate_memory(Type* type, tree size, source_location location)
+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.
tree
Gogo::go_string_constant_tree(const std::string& val)
{
- tree string_type = Type::make_string_type()->get_tree(this);
+ tree string_type = type_to_tree(Type::make_string_type()->get_backend(this));
VEC(constructor_elt, gc)* init = VEC_alloc(constructor_elt, gc, 2);
constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
tree field = TYPE_FIELDS(string_type);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__data") == 0);
+ 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),
elt = VEC_quick_push(constructor_elt, init, NULL);
field = DECL_CHAIN(field);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__length") == 0);
+ go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__length") == 0);
elt->index = field;
elt->value = build_int_cst_type(TREE_TYPE(field), val.length());
return build_fold_addr_expr(decl);
}
-// Build the type of the struct that holds a slice for the given
-// element type.
-
-tree
-Gogo::slice_type_tree(tree element_type_tree)
-{
- // We use int for the count and capacity fields in a slice header.
- // This matches 6g. The language definition guarantees that we
- // can't allocate space of a size which does not fit in int
- // anyhow. FIXME: integer_type_node is the the C type "int" but is
- // not necessarily the Go type "int". They will differ when the C
- // type "int" has fewer than 32 bits.
- return Gogo::builtin_struct(NULL, "__go_slice", NULL_TREE, 3,
- "__values",
- build_pointer_type(element_type_tree),
- "__count",
- integer_type_node,
- "__capacity",
- integer_type_node);
-}
-
-// Given the tree for a slice type, return the tree for the type of
-// the elements of the slice.
-
-tree
-Gogo::slice_element_type_tree(tree slice_type_tree)
-{
- gcc_assert(TREE_CODE(slice_type_tree) == RECORD_TYPE
- && POINTER_TYPE_P(TREE_TYPE(TYPE_FIELDS(slice_type_tree))));
- return TREE_TYPE(TREE_TYPE(TYPE_FIELDS(slice_type_tree)));
-}
-
// 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
Gogo::slice_constructor(tree slice_type_tree, tree values, tree count,
tree capacity)
{
- gcc_assert(TREE_CODE(slice_type_tree) == RECORD_TYPE);
+ go_assert(TREE_CODE(slice_type_tree) == RECORD_TYPE);
VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 3);
tree field = TYPE_FIELDS(slice_type_tree);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
+ go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0);
constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
elt->index = field;
- gcc_assert(TYPE_MAIN_VARIANT(TREE_TYPE(field))
+ go_assert(TYPE_MAIN_VARIANT(TREE_TYPE(field))
== TYPE_MAIN_VARIANT(TREE_TYPE(values)));
elt->value = values;
}
field = DECL_CHAIN(field);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
+ go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0);
elt = VEC_quick_push(constructor_elt, init, NULL);
elt->index = field;
elt->value = fold_convert(TREE_TYPE(field), count);
field = DECL_CHAIN(field);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
+ go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0);
elt = VEC_quick_push(constructor_elt, init, NULL);
elt->index = field;
elt->value = fold_convert(TREE_TYPE(field), capacity);
return build_constructor(slice_type_tree, init);
}
-// Build a constructor for an empty slice.
-
-tree
-Gogo::empty_slice_constructor(tree slice_type_tree)
-{
- tree element_field = TYPE_FIELDS(slice_type_tree);
- tree ret = Gogo::slice_constructor(slice_type_tree,
- fold_convert(TREE_TYPE(element_field),
- null_pointer_node),
- size_zero_node,
- size_zero_node);
- TREE_CONSTANT(ret) = 1;
- return ret;
-}
-
-// Build a map descriptor for a map of type MAPTYPE.
-
-tree
-Gogo::map_descriptor(Map_type* maptype)
-{
- if (this->map_descriptors_ == NULL)
- this->map_descriptors_ = new Map_descriptors(10);
-
- std::pair<const Map_type*, tree> val(maptype, NULL);
- std::pair<Map_descriptors::iterator, bool> ins =
- this->map_descriptors_->insert(val);
- Map_descriptors::iterator p = ins.first;
- if (!ins.second)
- {
- if (p->second == error_mark_node)
- return error_mark_node;
- gcc_assert(p->second != NULL_TREE && DECL_P(p->second));
- return build_fold_addr_expr(p->second);
- }
-
- Type* keytype = maptype->key_type();
- Type* valtype = maptype->val_type();
-
- std::string mangled_name = ("__go_map_" + maptype->mangled_name(this));
-
- tree id = get_identifier_from_string(mangled_name);
-
- // Get the type of the map descriptor. This is __go_map_descriptor
- // in libgo/map.h.
-
- tree struct_type = this->map_descriptor_type();
-
- // The map entry type is a struct with three fields. This struct is
- // specific to MAPTYPE. Build it.
-
- tree map_entry_type = make_node(RECORD_TYPE);
-
- map_entry_type = Gogo::builtin_struct(NULL, "__map", map_entry_type, 3,
- "__next",
- build_pointer_type(map_entry_type),
- "__key",
- keytype->get_tree(this),
- "__val",
- valtype->get_tree(this));
- if (map_entry_type == error_mark_node)
- {
- p->second = error_mark_node;
- return error_mark_node;
- }
-
- tree map_entry_key_field = DECL_CHAIN(TYPE_FIELDS(map_entry_type));
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_key_field)),
- "__key") == 0);
-
- tree map_entry_val_field = DECL_CHAIN(map_entry_key_field);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_val_field)),
- "__val") == 0);
-
- // Initialize the entries.
-
- tree map_descriptor_field = TYPE_FIELDS(struct_type);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_descriptor_field)),
- "__map_descriptor") == 0);
- tree entry_size_field = DECL_CHAIN(map_descriptor_field);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(entry_size_field)),
- "__entry_size") == 0);
- tree key_offset_field = DECL_CHAIN(entry_size_field);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(key_offset_field)),
- "__key_offset") == 0);
- tree val_offset_field = DECL_CHAIN(key_offset_field);
- gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(val_offset_field)),
- "__val_offset") == 0);
-
- VEC(constructor_elt, gc)* descriptor = VEC_alloc(constructor_elt, gc, 6);
-
- constructor_elt* elt = VEC_quick_push(constructor_elt, descriptor, NULL);
- elt->index = map_descriptor_field;
- elt->value = maptype->type_descriptor_pointer(this);
-
- elt = VEC_quick_push(constructor_elt, descriptor, NULL);
- elt->index = entry_size_field;
- elt->value = TYPE_SIZE_UNIT(map_entry_type);
-
- elt = VEC_quick_push(constructor_elt, descriptor, NULL);
- elt->index = key_offset_field;
- elt->value = byte_position(map_entry_key_field);
-
- elt = VEC_quick_push(constructor_elt, descriptor, NULL);
- elt->index = val_offset_field;
- elt->value = byte_position(map_entry_val_field);
-
- tree constructor = build_constructor(struct_type, descriptor);
-
- tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, struct_type);
- TREE_STATIC(decl) = 1;
- TREE_USED(decl) = 1;
- TREE_READONLY(decl) = 1;
- TREE_CONSTANT(decl) = 1;
- DECL_INITIAL(decl) = constructor;
- 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);
- p->second = decl;
-
- return build_fold_addr_expr(decl);
-}
-
-// Return a tree for the type of a map descriptor. This is struct
-// __go_map_descriptor in libgo/runtime/map.h. This is the same for
-// all map types.
-
-tree
-Gogo::map_descriptor_type()
-{
- static tree struct_type;
- tree dtype = Type::make_type_descriptor_type()->get_tree(this);
- dtype = build_qualified_type(dtype, TYPE_QUAL_CONST);
- return Gogo::builtin_struct(&struct_type, "__go_map_descriptor", NULL_TREE,
- 4,
- "__map_descriptor",
- build_pointer_type(dtype),
- "__entry_size",
- sizetype,
- "__key_offset",
- sizetype,
- "__val_offset",
- sizetype);
-}
-
-// Return the name to use for a type descriptor decl for TYPE. This
-// is used when TYPE does not have a name.
-
-std::string
-Gogo::unnamed_type_descriptor_decl_name(const Type* type)
-{
- return "__go_td_" + type->mangled_name(this);
-}
-
-// Return the name to use for a type descriptor decl for a type named
-// NAME, defined in the function IN_FUNCTION. IN_FUNCTION will
-// normally be NULL.
-
-std::string
-Gogo::type_descriptor_decl_name(const Named_object* no,
- const Named_object* in_function)
-{
- std::string ret = "__go_tdn_";
- if (no->type_value()->is_builtin())
- gcc_assert(in_function == NULL);
- else
- {
- const std::string& unique_prefix(no->package() == NULL
- ? this->unique_prefix()
- : no->package()->unique_prefix());
- const std::string& package_name(no->package() == NULL
- ? this->package_name()
- : no->package()->name());
- ret.append(unique_prefix);
- ret.append(1, '.');
- ret.append(package_name);
- ret.append(1, '.');
- if (in_function != NULL)
- {
- ret.append(Gogo::unpack_hidden_name(in_function->name()));
- ret.append(1, '.');
- }
- }
- ret.append(no->name());
- return ret;
-}
-
-// Where a type descriptor decl should be defined.
-
-Gogo::Type_descriptor_location
-Gogo::type_descriptor_location(const Type* type)
-{
- const Named_type* name = type->named_type();
- if (name != NULL)
- {
- if (name->named_object()->package() != NULL)
- {
- // This is a named type defined in a different package. The
- // descriptor should be defined in that package.
- return TYPE_DESCRIPTOR_UNDEFINED;
- }
- else if (name->is_builtin())
- {
- // We create the descriptor for a builtin type whenever we
- // need it.
- return TYPE_DESCRIPTOR_COMMON;
- }
- else
- {
- // This is a named type defined in this package. The
- // descriptor should be defined here.
- return TYPE_DESCRIPTOR_DEFINED;
- }
- }
- else
- {
- if (type->points_to() != NULL
- && type->points_to()->named_type() != NULL
- && type->points_to()->named_type()->named_object()->package() != NULL)
- {
- // This is an unnamed pointer to a named type defined in a
- // different package. The descriptor should be defined in
- // that package.
- return TYPE_DESCRIPTOR_UNDEFINED;
- }
- else
- {
- // This is an unnamed type. The descriptor could be defined
- // in any package where it is needed, and the linker will
- // pick one descriptor to keep.
- return TYPE_DESCRIPTOR_COMMON;
- }
- }
-}
-
-// Build a type descriptor decl for TYPE. INITIALIZER is a struct
-// composite literal which initializers the type descriptor.
-
-void
-Gogo::build_type_descriptor_decl(const Type* type, Expression* initializer,
- tree* pdecl)
-{
- const Named_type* name = type->named_type();
-
- // We can have multiple instances of unnamed types, but we only want
- // to emit the type descriptor once. We use a hash table to handle
- // this. This is not necessary for named types, as they are unique,
- // and we store the type descriptor decl in the type itself.
- tree* phash = NULL;
- if (name == NULL)
- {
- if (this->type_descriptor_decls_ == NULL)
- this->type_descriptor_decls_ = new Type_descriptor_decls(10);
-
- std::pair<Type_descriptor_decls::iterator, bool> ins =
- this->type_descriptor_decls_->insert(std::make_pair(type, NULL_TREE));
- if (!ins.second)
- {
- // We've already built a type descriptor for this type.
- *pdecl = ins.first->second;
- return;
- }
- phash = &ins.first->second;
- }
-
- std::string decl_name;
- if (name == NULL)
- decl_name = this->unnamed_type_descriptor_decl_name(type);
- else
- decl_name = this->type_descriptor_decl_name(name->named_object(),
- name->in_function());
- tree id = get_identifier_from_string(decl_name);
- tree descriptor_type_tree = initializer->type()->get_tree(this);
- if (descriptor_type_tree == error_mark_node)
- {
- *pdecl = error_mark_node;
- return;
- }
- tree decl = build_decl(name == NULL ? BUILTINS_LOCATION : name->location(),
- VAR_DECL, id,
- build_qualified_type(descriptor_type_tree,
- TYPE_QUAL_CONST));
- TREE_READONLY(decl) = 1;
- TREE_CONSTANT(decl) = 1;
- DECL_ARTIFICIAL(decl) = 1;
-
- go_preserve_from_gc(decl);
- if (phash != NULL)
- *phash = decl;
-
- // We store the new DECL now because we may need to refer to it when
- // expanding INITIALIZER.
- *pdecl = decl;
-
- // If appropriate, just refer to the exported type identifier.
- Gogo::Type_descriptor_location type_descriptor_location =
- this->type_descriptor_location(type);
- if (type_descriptor_location == TYPE_DESCRIPTOR_UNDEFINED)
- {
- TREE_PUBLIC(decl) = 1;
- DECL_EXTERNAL(decl) = 1;
- return;
- }
-
- TREE_STATIC(decl) = 1;
- TREE_USED(decl) = 1;
-
- Translate_context context(this, NULL, NULL, NULL);
- context.set_is_const();
- tree constructor = initializer->get_tree(&context);
-
- if (constructor == error_mark_node)
- gcc_assert(saw_errors());
-
- DECL_INITIAL(decl) = constructor;
-
- if (type_descriptor_location == TYPE_DESCRIPTOR_DEFINED)
- TREE_PUBLIC(decl) = 1;
- else
- {
- gcc_assert(type_descriptor_location == TYPE_DESCRIPTOR_COMMON);
- make_decl_one_only(decl, DECL_ASSEMBLER_NAME(decl));
- resolve_unique_section(decl, 1, 0);
- }
-
- rest_of_decl_compilation(decl, 1, 0);
-}
-
// Build an interface method table for a type: a list of function
// pointers, one for each interface method. This is used for
// interfaces.
bool is_pointer)
{
const Typed_identifier_list* interface_methods = interface->methods();
- gcc_assert(!interface_methods->empty());
+ go_assert(!interface_methods->empty());
std::string mangled_name = ((is_pointer ? "__go_pimt__" : "__go_imt_")
+ interface->mangled_name(this)
td_type = type;
else
td_type = Type::make_pointer_type(type);
- elt->value = fold_convert(const_ptr_type_node,
- td_type->type_descriptor_pointer(this));
+ tree tdp = td_type->type_descriptor_pointer(this,
+ Linemap::predeclared_location());
+ elt->value = fold_convert(const_ptr_type_node, tdp);
size_t i = 1;
for (Typed_identifier_list::const_iterator p = interface_methods->begin();
{
bool is_ambiguous;
Method* m = type->method_function(p->name(), &is_ambiguous);
- gcc_assert(m != NULL);
+ go_assert(m != NULL);
Named_object* no = m->named_object();
fndecl = no->func_declaration_value()->get_or_make_decl(this, no,
fnid);
else
- gcc_unreachable();
+ go_unreachable();
fndecl = build_fold_addr_expr(fndecl);
elt = VEC_quick_push(constructor_elt, pointers, NULL);
elt->index = size_int(i);
elt->value = fold_convert(const_ptr_type_node, fndecl);
}
- gcc_assert(i == count + 1);
+ go_assert(i == count + 1);
tree array_type = build_array_type(const_ptr_type_node,
build_index_type(size_int(count)));
// Build a call to a builtin function.
tree
-Gogo::call_builtin(tree* pdecl, source_location location, const char* name,
+Gogo::call_builtin(tree* pdecl, Location location, const char* name,
int nargs, tree rettype, ...)
{
if (rettype == error_mark_node)
tree fnptr = build_fold_addr_expr(*pdecl);
if (CAN_HAVE_LOCATION_P(fnptr))
- SET_EXPR_LOCATION(fnptr, location);
+ SET_EXPR_LOCATION(fnptr, location.gcc_location());
tree ret = build_call_array(rettype, fnptr, nargs, args);
- SET_EXPR_LOCATION(ret, location);
+ SET_EXPR_LOCATION(ret, location.gcc_location());
delete[] types;
delete[] args;
// Build a call to the runtime error function.
tree
-Gogo::runtime_error(int code, source_location location)
+Gogo::runtime_error(int code, Location location)
{
static tree runtime_error_fndecl;
tree ret = Gogo::call_builtin(&runtime_error_fndecl,
return ret;
}
-// Send VAL on CHANNEL. If BLOCKING is true, the resulting tree has a
-// void type. If BLOCKING is false, the resulting tree has a boolean
-// type, and it will evaluate as true if the value was sent. If
-// FOR_SELECT is true, this is being done because it was chosen in a
-// select statement.
-
-tree
-Gogo::send_on_channel(tree channel, tree val, bool blocking, bool for_select,
- source_location location)
-{
- if (channel == error_mark_node || val == error_mark_node)
- return error_mark_node;
-
- if (int_size_in_bytes(TREE_TYPE(val)) <= 8
- && !AGGREGATE_TYPE_P(TREE_TYPE(val))
- && !FLOAT_TYPE_P(TREE_TYPE(val)))
- {
- val = convert_to_integer(uint64_type_node, val);
- if (blocking)
- {
- static tree send_small_fndecl;
- tree ret = Gogo::call_builtin(&send_small_fndecl,
- location,
- "__go_send_small",
- 3,
- void_type_node,
- ptr_type_node,
- channel,
- uint64_type_node,
- val,
- boolean_type_node,
- (for_select
- ? boolean_true_node
- : boolean_false_node));
- if (ret == error_mark_node)
- return error_mark_node;
- // This can panic if there are too many operations on a
- // closed channel.
- TREE_NOTHROW(send_small_fndecl) = 0;
- return ret;
- }
- else
- {
- gcc_assert(!for_select);
- static tree send_nonblocking_small_fndecl;
- tree ret = Gogo::call_builtin(&send_nonblocking_small_fndecl,
- location,
- "__go_send_nonblocking_small",
- 2,
- boolean_type_node,
- ptr_type_node,
- channel,
- uint64_type_node,
- val);
- if (ret == error_mark_node)
- return error_mark_node;
- // This can panic if there are too many operations on a
- // closed channel.
- TREE_NOTHROW(send_nonblocking_small_fndecl) = 0;
- return ret;
- }
- }
- else
- {
- tree make_tmp;
- if (TREE_ADDRESSABLE(TREE_TYPE(val)) || TREE_CODE(val) == VAR_DECL)
- {
- make_tmp = NULL_TREE;
- val = build_fold_addr_expr(val);
- if (DECL_P(val))
- TREE_ADDRESSABLE(val) = 1;
- }
- else
- {
- tree tmp = create_tmp_var(TREE_TYPE(val), get_name(val));
- DECL_IGNORED_P(tmp) = 0;
- DECL_INITIAL(tmp) = val;
- TREE_ADDRESSABLE(tmp) = 1;
- make_tmp = build1(DECL_EXPR, void_type_node, tmp);
- SET_EXPR_LOCATION(make_tmp, location);
- val = build_fold_addr_expr(tmp);
- }
- val = fold_convert(ptr_type_node, val);
-
- tree call;
- if (blocking)
- {
- static tree send_big_fndecl;
- call = Gogo::call_builtin(&send_big_fndecl,
- location,
- "__go_send_big",
- 3,
- void_type_node,
- ptr_type_node,
- channel,
- ptr_type_node,
- val,
- boolean_type_node,
- (for_select
- ? boolean_true_node
- : boolean_false_node));
- if (call == error_mark_node)
- return error_mark_node;
- // This can panic if there are too many operations on a
- // closed channel.
- TREE_NOTHROW(send_big_fndecl) = 0;
- }
- else
- {
- gcc_assert(!for_select);
- static tree send_nonblocking_big_fndecl;
- call = Gogo::call_builtin(&send_nonblocking_big_fndecl,
- location,
- "__go_send_nonblocking_big",
- 2,
- boolean_type_node,
- ptr_type_node,
- channel,
- ptr_type_node,
- val);
- if (call == error_mark_node)
- return error_mark_node;
- // This can panic if there are too many operations on a
- // closed channel.
- TREE_NOTHROW(send_nonblocking_big_fndecl) = 0;
- }
-
- if (make_tmp == NULL_TREE)
- return call;
- else
- {
- tree ret = build2(COMPOUND_EXPR, TREE_TYPE(call), make_tmp, call);
- SET_EXPR_LOCATION(ret, location);
- return ret;
- }
- }
-}
-
// Return a tree for receiving a value of type TYPE_TREE on CHANNEL.
-// This does a blocking receive and returns the value read from the
-// channel. If FOR_SELECT is true, this is being done because it was
-// chosen in a select statement.
+// 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 channel, bool for_select,
- source_location location)
+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;
"__go_receive_small",
2,
uint64_type_node,
+ TREE_TYPE(type_descriptor_tree),
+ type_descriptor_tree,
ptr_type_node,
- channel,
- boolean_type_node,
- (for_select
- ? boolean_true_node
- : boolean_false_node));
+ channel);
if (call == error_mark_node)
return error_mark_node;
// This can panic if there are too many operations on a closed
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, type_tree,
- fold_convert_loc(location, int_type_tree,
- call));
+ return fold_convert_loc(location.gcc_location(), type_tree,
+ fold_convert_loc(location.gcc_location(),
+ int_type_tree, call));
}
else
{
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);
+ 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;
location,
"__go_receive_big",
3,
- boolean_type_node,
+ void_type_node,
+ TREE_TYPE(type_descriptor_tree),
+ type_descriptor_tree,
ptr_type_node,
channel,
ptr_type_node,
- tmpaddr,
- boolean_type_node,
- (for_select
- ? boolean_true_node
- : boolean_false_node));
+ tmpaddr);
if (call == error_mark_node)
return error_mark_node;
// This can panic if there are too many operations on a closed
// Make a trampoline which calls FNADDR passing CLOSURE.
tree
-Gogo::make_trampoline(tree fnaddr, tree closure, source_location location)
+Gogo::make_trampoline(tree fnaddr, tree closure, Location location)
{
tree trampoline_type = Gogo::trampoline_type_tree();
tree trampoline_size = TYPE_SIZE_UNIT(trampoline_type);
size_type_node,
trampoline_size,
ptr_type_node,
- fold_convert_loc(location, ptr_type_node,
- closure));
+ fold_convert_loc(location.gcc_location(),
+ ptr_type_node, closure));
if (x == error_mark_node)
return error_mark_node;
x = save_expr(x);
// Initialize the trampoline.
- tree ini = build_call_expr(implicit_built_in_decls[BUILT_IN_INIT_TRAMPOLINE],
- 3, x, fnaddr, closure);
+ tree calldecl = builtin_decl_implicit(BUILT_IN_INIT_HEAP_TRAMPOLINE);
+ tree ini = build_call_expr(calldecl, 3, x, fnaddr, closure);
// On some targets the trampoline address needs to be adjusted. For
// example, when compiling in Thumb mode on the ARM, the address
// needs to have the low bit set.
- x = build_call_expr(implicit_built_in_decls[BUILT_IN_ADJUST_TRAMPOLINE],
- 1, x);
+ x = build_call_expr(builtin_decl_explicit(BUILT_IN_ADJUST_TRAMPOLINE), 1, x);
x = fold_convert(TREE_TYPE(fnaddr), x);
return build2(COMPOUND_EXPR, TREE_TYPE(x), ini, x);