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.
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),
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];
}
// 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();
else if (init == NULL_TREE)
;
else if (TREE_CONSTANT(init))
- this->backend()->global_variable_set_init(var,
- tree_to_expr(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);
&& !this->func_declaration_value()->asm_name().empty())
decl_name = this->func_declaration_value()->asm_name();
else if (this->is_type()
- && this->type_value()->location() == BUILTINS_LOCATION)
+ && Linemap::is_predeclared_location(this->type_value()->location()))
{
// We don't need the package name for builtin types.
decl_name = Gogo::unpack_hidden_name(this->name_);
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
// 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());
}
}
}
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:
go_unreachable();
}
if (this->init_ == NULL)
{
go_assert(!this->is_parameter_);
- return this->type_->get_init_tree(gogo,
- (this->is_global_
- || this->is_in_heap()));
+ 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
{
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
// want the real function type for a function declaration.
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
}
}
- 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;
// want the real function type for a function declaration.
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;
DECL_ARG_TYPE(parm_decl) = TREE_TYPE(parm_decl);
go_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);
+ 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;
if (var_decl == error_mark_node)
return error_mark_node;
go_assert(TREE_CODE(var_decl) == VAR_DECL);
- source_location loc = DECL_SOURCE_LOCATION(var_decl);
+ Location loc(DECL_SOURCE_LOCATION(var_decl));
std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
name += ".param";
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),
Type* type = (*p)->result_var_value()->type();
tree init;
if (!(*p)->result_var_value()->is_in_heap())
- init = type->get_init_tree(gogo, false);
+ {
+ Btype* btype = type->get_backend(gogo);
+ init = expr_to_tree(gogo->backend()->zero_expression(btype));
+ }
else
{
- source_location loc = (*p)->location();
- tree type_tree = type->get_tree(gogo);
+ 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);
- tree subinit = type->get_init_tree(gogo, true);
- if (subinit == NULL_TREE)
- init = fold_convert_loc(loc, ptr_type_tree, space);
- else
- {
- space = save_expr(space);
- space = fold_convert_loc(loc, ptr_type_tree, 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);
- }
+ init = fold_convert_loc(loc.gcc_location(), ptr_type_tree, space);
}
if (var_decl != error_mark_node)
// function.
if (defer_init != NULL_TREE && defer_init != error_mark_node)
{
- 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
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);
go_assert(*except == NULL_TREE);
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);
call = Runtime::make_call(Runtime::UNDEFER, end_loc, 1,
if (undefer == error_mark_node || defer == error_mark_node)
return;
- tree jump = fold_build1_loc(end_loc, GOTO_EXPR, void_type_node, label);
+ 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);
+
}
go_assert(*fini == NULL_TREE);
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())
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, ret);
+ ret = build_fold_indirect_ref_loc(location.gcc_location(), ret);
return ret;
}
else
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, val);
- tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
+ 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);
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->get_tree(go_get_gogo());
+ 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->get_tree(go_get_gogo());
+ 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);
return build_constructor(slice_type_tree, init);
}
-// 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;
- go_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));
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_key_field)),
- "__key") == 0);
-
- tree map_entry_val_field = DECL_CHAIN(map_entry_key_field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_entry_val_field)),
- "__val") == 0);
-
- // Initialize the entries.
-
- tree map_descriptor_field = TYPE_FIELDS(struct_type);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(map_descriptor_field)),
- "__map_descriptor") == 0);
- tree entry_size_field = DECL_CHAIN(map_descriptor_field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(entry_size_field)),
- "__entry_size") == 0);
- tree key_offset_field = DECL_CHAIN(entry_size_field);
- go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(key_offset_field)),
- "__key_offset") == 0);
- tree val_offset_field = DECL_CHAIN(key_offset_field);
- go_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())
- go_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)
- go_assert(saw_errors());
-
- DECL_INITIAL(decl) = constructor;
-
- if (type_descriptor_location == TYPE_DESCRIPTOR_DEFINED)
- TREE_PUBLIC(decl) = 1;
- else
- {
- go_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.
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();
// 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 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);