===================================================================
@@ -44,6 +44,7 @@ class Backend;
class Export;
class Import;
class Bexpression;
+class Btype;
class Bstatement;
class Bblock;
class Bvariable;
@@ -591,11 +592,6 @@ class Gogo
Expression*
runtime_error(int code, Location);
- // Build a builtin struct with a list of fields.
- static tree
- builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
- int nfields, ...);
-
// Mark a function declaration as a builtin library function.
static void
mark_fndecl_as_builtin_library(tree fndecl);
@@ -650,17 +646,18 @@ class Gogo
Named_object*
initialization_function_decl();
- // Write the magic initialization function.
- void
- write_initialization_function(Named_object* fndecl, tree init_stmt_list);
+ // Create the magic initialization function.
+ Named_object*
+ create_initialization_function(Named_object* fndecl, Bstatement* code_stmt);
// Initialize imported packages.
void
- init_imports(tree*);
+ init_imports(std::vector<Bstatement*>&);
// Register variables with the garbage collector.
void
- register_gc_vars(const std::vector<Named_object*>&, tree*);
+ register_gc_vars(const std::vector<Named_object*>&,
+ std::vector<Bstatement*>&);
// Type used to map import names to packages.
typedef std::map<std::string, Package*> Imports;
@@ -1086,7 +1083,7 @@ class Function
get_or_make_decl(Gogo*, Named_object*);
// Return the function's decl after it has been built.
- tree
+ Bfunction*
get_decl() const;
// Set the function decl to hold a backend representation of the function
@@ -1675,7 +1672,7 @@ class Named_constant
Named_constant(Type* type, Expression* expr, int iota_value,
Location location)
: type_(type), expr_(expr), iota_value_(iota_value), location_(location),
- lowering_(false), is_sink_(false)
+ lowering_(false), is_sink_(false), bconst_(NULL)
{ }
Type*
@@ -1737,6 +1734,10 @@ class Named_constant
static void
import_const(Import*, std::string*, Type**, Expression**);
+ // Get the backend representation of the constant value.
+ Bexpression*
+ get_backend(Gogo*, Named_object*);
+
private:
// The type of the constant.
Type* type_;
@@ -1754,6 +1755,8 @@ class Named_constant
bool lowering_;
// Whether this constant is blank named and needs only type checking.
bool is_sink_;
+ // The backend representation of the constant value.
+ Bexpression* bconst_;
};
// A type declaration.
@@ -2176,9 +2179,10 @@ class Named_object
std::string
get_id(Gogo*);
- // Return a tree representing this object.
- tree
- get_tree(Gogo*, Named_object* function);
+ // Get the backend representation of this object.
+ void
+ get_backend(Gogo*, std::vector<Bexpression*>&, std::vector<Btype*>&,
+ std::vector<Bfunction*>&);
// Define a type declaration.
void
@@ -2219,8 +2223,6 @@ class Named_object
Function_declaration* func_declaration_value;
Package* package_value;
} u_;
- // The DECL tree for this object if we have already converted it.
- tree tree_;
};
// A binding contour. This binds names to objects.
===================================================================
@@ -30,6 +30,7 @@ class Var_expression;
class Temporary_reference_expression;
class Set_and_use_temporary_expression;
class String_expression;
+class Unary_expression;
class Binary_expression;
class Call_expression;
class Func_expression;
@@ -327,6 +328,10 @@ class Expression
static Expression*
make_struct_composite_literal(Type*, Expression_list*, Location);
+ // Make an array composite literal.
+ static Expression*
+ make_array_composite_literal(Type*, Expression_list*, Location);
+
// Make a slice composite literal.
static Expression*
make_slice_composite_literal(Type*, Expression_list*, Location);
@@ -533,6 +538,12 @@ class Expression
Expression*
deref();
+ // If this is a unary expression, return the Unary_expression
+ // structure. Otherwise return NULL.
+ Unary_expression*
+ unary_expression()
+ { return this->convert<Unary_expression, EXPRESSION_UNARY>(); }
+
// If this is a binary expression, return the Binary_expression
// structure. Otherwise return NULL.
Binary_expression*
@@ -1286,6 +1297,143 @@ class String_expression : public Express
Type* type_;
};
+// A Unary expression.
+
+class Unary_expression : public Expression
+{
+ public:
+ Unary_expression(Operator op, Expression* expr, Location location)
+ : Expression(EXPRESSION_UNARY, location),
+ op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
+ expr_(expr), issue_nil_check_(false)
+ { }
+
+ // Return the operator.
+ Operator
+ op() const
+ { return this->op_; }
+
+ // Return the operand.
+ Expression*
+ operand() const
+ { return this->expr_; }
+
+ // Record that an address expression does not escape.
+ void
+ set_does_not_escape()
+ {
+ go_assert(this->op_ == OPERATOR_AND);
+ this->escapes_ = false;
+ }
+
+ // Record that this is an address expression which should create a
+ // temporary variable if necessary. This is used for method calls.
+ void
+ set_create_temp()
+ {
+ go_assert(this->op_ == OPERATOR_AND);
+ this->create_temp_ = true;
+ }
+
+ // Record that this is an address expression of a GC root, which is a
+ // mutable composite literal. This used for registering GC variables.
+ void
+ set_is_gc_root()
+ {
+ go_assert(this->op_ == OPERATOR_AND);
+ this->is_gc_root_ = true;
+ }
+
+ // Apply unary opcode OP to UNC, setting NC. Return true if this
+ // could be done, false if not. Issue errors for overflow.
+ static bool
+ eval_constant(Operator op, const Numeric_constant* unc,
+ Location, Numeric_constant* nc);
+
+ static Expression*
+ do_import(Import*);
+
+ protected:
+ int
+ do_traverse(Traverse* traverse)
+ { return Expression::traverse(&this->expr_, traverse); }
+
+ Expression*
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+
+ Expression*
+ do_flatten(Gogo*, Named_object*, Statement_inserter*);
+
+ bool
+ do_is_constant() const;
+
+ bool
+ do_is_immutable() const
+ {
+ return (this->expr_->is_immutable()
+ || (this->op_ == OPERATOR_AND && this->expr_->is_variable()));
+ }
+
+ bool
+ do_numeric_constant_value(Numeric_constant*) const;
+
+ Type*
+ do_type();
+
+ void
+ do_determine_type(const Type_context*);
+
+ void
+ do_check_types(Gogo*);
+
+ Expression*
+ do_copy()
+ {
+ return Expression::make_unary(this->op_, this->expr_->copy(),
+ this->location());
+ }
+
+ bool
+ do_must_eval_subexpressions_in_order(int*) const
+ { return this->op_ == OPERATOR_MULT; }
+
+ bool
+ do_is_addressable() const
+ { return this->op_ == OPERATOR_MULT; }
+
+ tree
+ do_get_tree(Translate_context*);
+
+ void
+ do_export(Export*) const;
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ void
+ do_issue_nil_check()
+ { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }
+
+ private:
+ // The unary operator to apply.
+ Operator op_;
+ // Normally true. False if this is an address expression which does
+ // not escape the current function.
+ bool escapes_;
+ // True if this is an address expression which should create a
+ // temporary variable if necessary.
+ bool create_temp_;
+ // True if this is an address expression for a GC root. A GC root is a
+ // special struct composite literal that is mutable when addressed, meaning
+ // it cannot be represented as an immutable_struct in the backend.
+ bool is_gc_root_;
+ // The operand.
+ Expression* expr_;
+ // Whether or not to issue a nil check for this expression if its address
+ // is being taken.
+ bool issue_nil_check_;
+};
+
// A binary expression.
class Binary_expression : public Expression
===================================================================
@@ -434,15 +434,9 @@ Temporary_statement::do_get_backend(Tran
{
go_assert(this->bvariable_ == NULL);
- // FIXME: Permitting FUNCTION to be NULL here is a temporary measure
- // until we have a better representation of the init function.
Named_object* function = context->function();
- Bfunction* bfunction;
- if (function == NULL)
- bfunction = NULL;
- else
- bfunction = tree_to_function(function->func_value()->get_decl());
-
+ go_assert(function != NULL);
+ Bfunction* bfunction = function->func_value()->get_decl();
Btype* btype = this->type()->get_backend(context->gogo());
Bexpression* binit;
@@ -2781,8 +2775,6 @@ Return_statement::do_get_backend(Transla
Location loc = this->location();
Function* function = context->function()->func_value();
- tree fndecl = function->get_decl();
-
Function::Results* results = function->result_variables();
std::vector<Bexpression*> retvals;
if (results != NULL && !results->empty())
@@ -2797,7 +2789,7 @@ Return_statement::do_get_backend(Transla
}
}
- return context->backend()->return_statement(tree_to_function(fndecl),
+ return context->backend()->return_statement(function->get_decl(),
retvals, loc);
}
@@ -3803,8 +3795,10 @@ Constant_switch_statement::do_get_backen
this->clauses_->get_backend(context, break_label, &all_cases,
&all_statements);
+ Bfunction* bfunction = context->function()->func_value()->get_decl();
Bstatement* switch_statement;
- switch_statement = context->backend()->switch_statement(switch_val_expr,
+ switch_statement = context->backend()->switch_statement(bfunction,
+ switch_val_expr,
all_cases,
all_statements,
this->location());
@@ -4980,7 +4974,9 @@ Select_clauses::get_backend(Translate_co
std::vector<Bstatement*> statements;
statements.reserve(2);
- Bstatement* switch_stmt = context->backend()->switch_statement(bcall,
+ Bfunction* bfunction = context->function()->func_value()->get_decl();
+ Bstatement* switch_stmt = context->backend()->switch_statement(bfunction,
+ bcall,
cases,
clauses,
location);
===================================================================
@@ -236,830 +236,6 @@ Gogo::define_builtin_function_trees()
false);
}
-// Add statements to INIT_STMT_LIST which run the initialization
-// functions for imported packages. This is only used for the "main"
-// package.
-
-void
-Gogo::init_imports(tree* init_stmt_list)
-{
- go_assert(this->is_main_package());
-
- if (this->imported_init_fns_.empty())
- return;
-
- tree fntype = build_function_type(void_type_node, void_list_node);
-
- // We must call them in increasing priority order.
- std::vector<Import_init> v;
- for (std::set<Import_init>::const_iterator p =
- this->imported_init_fns_.begin();
- p != this->imported_init_fns_.end();
- ++p)
- v.push_back(*p);
- std::sort(v.begin(), v.end());
-
- for (std::vector<Import_init>::const_iterator p = v.begin();
- p != v.end();
- ++p)
- {
- std::string user_name = p->package_name() + ".init";
- tree decl = build_decl(UNKNOWN_LOCATION, FUNCTION_DECL,
- get_identifier_from_string(user_name),
- fntype);
- const std::string& init_name(p->init_name());
- SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(init_name));
- TREE_PUBLIC(decl) = 1;
- DECL_EXTERNAL(decl) = 1;
- append_to_statement_list(build_call_expr(decl, 0), init_stmt_list);
- }
-}
-
-// Register global variables with the garbage collector. We need to
-// register all variables which can hold a pointer value. They become
-// roots during the mark phase. We build a struct that is easy to
-// hook into a list of roots.
-
-// struct __go_gc_root_list
-// {
-// struct __go_gc_root_list* __next;
-// struct __go_gc_root
-// {
-// void* __decl;
-// size_t __size;
-// } __roots[];
-// };
-
-// The last entry in the roots array has a NULL decl field.
-
-void
-Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
- tree* init_stmt_list)
-{
- if (var_gc.empty())
- return;
-
- size_t count = var_gc.size();
-
- tree root_type = Gogo::builtin_struct(NULL, "__go_gc_root", NULL_TREE, 2,
- "__next",
- ptr_type_node,
- "__size",
- sizetype);
-
- tree index_type = build_index_type(size_int(count));
- tree array_type = build_array_type(root_type, index_type);
-
- tree root_list_type = make_node(RECORD_TYPE);
- root_list_type = Gogo::builtin_struct(NULL, "__go_gc_root_list",
- root_list_type, 2,
- "__next",
- build_pointer_type(root_list_type),
- "__roots",
- array_type);
-
- // Build an initialier for the __roots array.
-
- vec<constructor_elt, va_gc> *roots_init;
- vec_alloc(roots_init, count + 1);
-
- size_t i = 0;
- for (std::vector<Named_object*>::const_iterator p = var_gc.begin();
- p != var_gc.end();
- ++p, ++i)
- {
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(root_type);
- elt->index = field;
- 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 = init->quick_push(empty);
- field = DECL_CHAIN(field);
- elt->index = field;
- elt->value = DECL_SIZE_UNIT(decl);
-
- elt = roots_init->quick_push(empty);
- elt->index = size_int(i);
- elt->value = build_constructor(root_type, init);
- }
-
- // The list ends with a NULL entry.
-
- vec<constructor_elt, va_gc> *init;
- vec_alloc(init, 2);
-
- constructor_elt empty = {NULL, NULL};
- constructor_elt* elt = init->quick_push(empty);
- tree field = TYPE_FIELDS(root_type);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
- elt = init->quick_push(empty);
- field = DECL_CHAIN(field);
- elt->index = field;
- elt->value = size_zero_node;
-
- elt = roots_init->quick_push(empty);
- elt->index = size_int(i);
- elt->value = build_constructor(root_type, init);
-
- // Build a constructor for the struct.
-
- vec<constructor_elt, va_gc> *root_list_init;
- vec_alloc(root_list_init, 2);
-
- elt = root_list_init->quick_push(empty);
- field = TYPE_FIELDS(root_list_type);
- elt->index = field;
- elt->value = fold_convert(TREE_TYPE(field), null_pointer_node);
-
- elt = root_list_init->quick_push(empty);
- field = DECL_CHAIN(field);
- elt->index = field;
- elt->value = build_constructor(array_type, roots_init);
-
- // Build a decl to register.
-
- tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
- create_tmp_var_name("gc"), root_list_type);
- DECL_EXTERNAL(decl) = 0;
- TREE_PUBLIC(decl) = 0;
- TREE_STATIC(decl) = 1;
- DECL_ARTIFICIAL(decl) = 1;
- DECL_INITIAL(decl) = build_constructor(root_list_type, root_list_init);
- rest_of_decl_compilation(decl, 1, 0);
-
- static tree register_gc_fndecl;
- 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),
- build_fold_addr_expr(decl));
- if (call != error_mark_node)
- append_to_statement_list(call, init_stmt_list);
-}
-
-// Create the magic initialization function. INIT_STMT_LIST is the
-// code that it needs to run.
-
-void
-Gogo::write_initialization_function(Named_object* initfn, tree init_stmt_list)
-{
- // Make sure that we thought we needed an initialization function,
- // as otherwise we will not have reported it in the export data.
- go_assert(this->is_main_package() || this->need_init_fn_);
-
- if (initfn == NULL)
- initfn = this->initialization_function_decl();
-
- Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn);
- Location loc = this->package_->location();
- std::vector<Bvariable*> vars;
- this->backend()->block(fndecl, NULL, vars, loc, loc);
-
- if (!this->backend()->function_set_body(fndecl, tree_to_stat(init_stmt_list)))
- {
- go_assert(saw_errors());
- return;
- }
- gimplify_function_tree(function_to_tree(fndecl));
- cgraph_add_new_function(function_to_tree(fndecl), false);
-}
-
-// Search for references to VAR in any statements or called functions.
-
-class Find_var : public Traverse
-{
- public:
- // A hash table we use to avoid looping. The index is the name of a
- // named object. We only look through objects defined in this
- // package.
- typedef Unordered_set(const void*) Seen_objects;
-
- Find_var(Named_object* var, Seen_objects* seen_objects)
- : Traverse(traverse_expressions),
- var_(var), seen_objects_(seen_objects), found_(false)
- { }
-
- // Whether the variable was found.
- bool
- found() const
- { return this->found_; }
-
- int
- expression(Expression**);
-
- private:
- // The variable we are looking for.
- Named_object* var_;
- // Names of objects we have already seen.
- Seen_objects* seen_objects_;
- // True if the variable was found.
- bool found_;
-};
-
-// See if EXPR refers to VAR, looking through function calls and
-// variable initializations.
-
-int
-Find_var::expression(Expression** pexpr)
-{
- Expression* e = *pexpr;
-
- Var_expression* ve = e->var_expression();
- if (ve != NULL)
- {
- Named_object* v = ve->named_object();
- if (v == this->var_)
- {
- this->found_ = true;
- return TRAVERSE_EXIT;
- }
-
- if (v->is_variable() && v->package() == NULL)
- {
- Expression* init = v->var_value()->init();
- if (init != NULL)
- {
- std::pair<Seen_objects::iterator, bool> ins =
- this->seen_objects_->insert(v);
- if (ins.second)
- {
- // This is the first time we have seen this name.
- if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
- }
-
- // We traverse the code of any function we see. Note that this
- // means that we will traverse the code of a function whose address
- // is taken even if it is not called.
- Func_expression* fe = e->func_expression();
- if (fe != NULL)
- {
- const Named_object* f = fe->named_object();
- if (f->is_function() && f->package() == NULL)
- {
- std::pair<Seen_objects::iterator, bool> ins =
- this->seen_objects_->insert(f);
- if (ins.second)
- {
- // This is the first time we have seen this name.
- if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
-
- Temporary_reference_expression* tre = e->temporary_reference_expression();
- if (tre != NULL)
- {
- Temporary_statement* ts = tre->statement();
- Expression* init = ts->init();
- if (init != NULL)
- {
- std::pair<Seen_objects::iterator, bool> ins =
- this->seen_objects_->insert(ts);
- if (ins.second)
- {
- // This is the first time we have seen this temporary
- // statement.
- if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
- return TRAVERSE_EXIT;
- }
- }
- }
-
- return TRAVERSE_CONTINUE;
-}
-
-// Return true if EXPR, PREINIT, or DEP refers to VAR.
-
-static bool
-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);
- if (expr != NULL)
- 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();
-}
-
-// Sort variable initializations. If the initialization expression
-// for variable A refers directly or indirectly to the initialization
-// expression for variable B, then we must initialize B before A.
-
-class Var_init
-{
- public:
- Var_init()
- : var_(NULL), init_(NULL)
- { }
-
- Var_init(Named_object* var, Bstatement* init)
- : var_(var), init_(init)
- { }
-
- // Return the variable.
- Named_object*
- var() const
- { return this->var_; }
-
- // Return the initialization expression.
- Bstatement*
- init() const
- { return this->init_; }
-
- private:
- // The variable being initialized.
- Named_object* var_;
- // The initialization statement.
- Bstatement* init_;
-};
-
-typedef std::list<Var_init> Var_inits;
-
-// Sort the variable initializations. The rule we follow is that we
-// emit them in the order they appear in the array, except that if the
-// initialization expression for a variable V1 depends upon another
-// variable V2 then we initialize V1 after V2.
-
-static void
-sort_var_inits(Gogo* gogo, Var_inits* var_inits)
-{
- typedef std::pair<Named_object*, Named_object*> No_no;
- typedef std::map<No_no, bool> Cache;
- Cache cache;
-
- Var_inits ready;
- while (!var_inits->empty())
- {
- Var_inits::iterator p1 = var_inits->begin();
- 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.
- Var_inits::iterator p2 = p1;
- ++p2;
-
- for (; p2 != var_inits->end(); ++p2)
- {
- Named_object* p2var = p2->var();
- No_no key(var, p2var);
- std::pair<Cache::iterator, bool> ins =
- cache.insert(std::make_pair(key, false));
- if (ins.second)
- ins.first->second = expression_requires(init, preinit, dep, p2var);
- if (ins.first->second)
- {
- // Check for cycles.
- key = std::make_pair(p2var, var);
- ins = cache.insert(std::make_pair(key, false));
- if (ins.second)
- ins.first->second =
- expression_requires(p2var->var_value()->init(),
- p2var->var_value()->preinit(),
- gogo->var_depends_on(p2var->var_value()),
- var);
- if (ins.first->second)
- {
- error_at(var->location(),
- ("initialization expressions for %qs and "
- "%qs depend upon each other"),
- var->message_name().c_str(),
- p2var->message_name().c_str());
- inform(p2->var()->location(), "%qs defined here",
- p2var->message_name().c_str());
- p2 = var_inits->end();
- }
- else
- {
- // We can't emit P1 until P2 is emitted. Move P1.
- Var_inits::iterator p3 = p2;
- ++p3;
- var_inits->splice(p3, *var_inits, p1);
- }
- break;
- }
- }
-
- if (p2 == var_inits->end())
- {
- // 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 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());
- ready.splice(ready.end(), *var_inits, p1);
- }
- }
-
- // Now READY is the list in the desired initialization order.
- var_inits->swap(ready);
-}
-
-// Write out the global definitions.
-
-void
-Gogo::write_globals()
-{
- this->build_interface_method_tables();
-
- Bindings* bindings = this->current_bindings();
-
- for (Bindings::const_declarations_iterator p = bindings->begin_declarations();
- p != bindings->end_declarations();
- ++p)
- {
- // If any function declarations needed a descriptor, make sure
- // we build it.
- Named_object* no = p->second;
- if (no->is_function_declaration())
- no->func_declaration_value()->build_backend_descriptor(this);
- }
-
- size_t count_definitions = bindings->size_definitions();
- size_t count = count_definitions;
-
- tree* vec = new tree[count];
-
- Named_object* init_fndecl = NULL;
- tree init_stmt_list = NULL_TREE;
-
- if (this->is_main_package())
- this->init_imports(&init_stmt_list);
-
- // A list of variable initializations.
- Var_inits var_inits;
-
- // A list of variables which need to be registered with the garbage
- // collector.
- std::vector<Named_object*> var_gc;
- var_gc.reserve(count);
-
- tree var_init_stmt_list = NULL_TREE;
- size_t i = 0;
- for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
- p != bindings->end_definitions();
- ++p, ++i)
- {
- Named_object* no = *p;
-
- go_assert(i < count);
-
- go_assert(!no->is_type_declaration() && !no->is_function_declaration());
- // There is nothing to do for a package.
- if (no->is_package())
- {
- --i;
- --count;
- continue;
- }
-
- // There is nothing to do for an object which was imported from
- // a different package into the global scope.
- if (no->package() != NULL)
- {
- --i;
- --count;
- continue;
- }
-
- // Skip blank named functions and constants.
- if ((no->is_function() && no->func_value()->is_sink())
- || (no->is_const() && no->const_value()->is_sink()))
- {
- --i;
- --count;
- continue;
- }
-
- // There is nothing useful we can output for constants which
- // have ideal or non-integral type.
- if (no->is_const())
- {
- Type* type = no->const_value()->type();
- if (type == NULL)
- type = no->const_value()->expr()->type();
- if (type->is_abstract() || type->integer_type() == NULL)
- {
- --i;
- --count;
- continue;
- }
- }
-
- if (!no->is_variable())
- {
- vec[i] = no->get_tree(this, NULL);
- if (vec[i] == error_mark_node)
- {
- go_assert(saw_errors());
- --i;
- --count;
- continue;
- }
- }
- else
- {
- 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.
- bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
-
- Bstatement* var_init_stmt = NULL;
- if (!no->var_value()->has_pre_init())
- {
- Bexpression* var_binit = no->var_value()->get_init(this, NULL);
- if (var_binit == NULL)
- ;
- else if (TREE_CONSTANT(expr_to_tree(var_binit)))
- {
- 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, var_binit);
- }
- else if (is_sink)
- var_init_stmt =
- this->backend()->expression_statement(var_binit);
- else
- {
- Location loc = no->var_value()->location();
- Bexpression* var_expr =
- this->backend()->var_expression(var, loc);
- var_init_stmt =
- this->backend()->assignment_statement(var_expr, var_binit,
- loc);
- }
- }
- else
- {
- // We are going to create temporary variables which
- // means that we need an fndecl.
- if (init_fndecl == NULL)
- init_fndecl = this->initialization_function_decl();
-
- Bvariable* var_decl = is_sink ? NULL : var;
- var_init_stmt =
- no->var_value()->get_init_block(this, init_fndecl, var_decl);
- }
-
- if (var_init_stmt != NULL)
- {
- if (no->var_value()->init() == NULL
- && !no->var_value()->has_pre_init())
- append_to_statement_list(stat_to_tree(var_init_stmt),
- &var_init_stmt_list);
- else
- var_inits.push_back(Var_init(no, var_init_stmt));
- }
- 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.
- Btype* int_btype =
- Type::lookup_integer_type("int")->get_backend(this);
- Bexpression* zero = this->backend()->zero_expression(int_btype);
- Bstatement* zero_stmt =
- this->backend()->expression_statement(zero);
- var_inits.push_back(Var_init(no, zero_stmt));
- }
-
- if (!is_sink && no->var_value()->type()->has_pointer())
- var_gc.push_back(no);
- }
- }
-
- // Register global variables with the garbage collector.
- this->register_gc_vars(var_gc, &init_stmt_list);
-
- // Simple variable initializations, after all variables are
- // registered.
- append_to_statement_list(var_init_stmt_list, &init_stmt_list);
-
- // Complex variable initializations, first sorting them into a
- // workable order.
- if (!var_inits.empty())
- {
- sort_var_inits(this, &var_inits);
- for (Var_inits::const_iterator p = var_inits.begin();
- p != var_inits.end();
- ++p)
- append_to_statement_list(stat_to_tree(p->init()), &init_stmt_list);
- }
-
- // After all the variables are initialized, call the "init"
- // functions if there are any.
- for (std::vector<Named_object*>::const_iterator p =
- this->init_functions_.begin();
- p != this->init_functions_.end();
- ++p)
- {
- tree decl = (*p)->get_tree(this, NULL);
- tree call = build_call_expr(decl, 0);
- append_to_statement_list(call, &init_stmt_list);
- }
-
- // Set up a magic function to do all the initialization actions.
- // This will be called if this package is imported.
- if (init_stmt_list != NULL
- || this->need_init_fn_
- || 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);
-
- finalize_compilation_unit();
-
- check_global_declarations(vec, count);
- emit_debug_global_declarations(vec, count);
-
- delete[] vec;
-}
-
-// Get a tree for a named object.
-
-tree
-Named_object::get_tree(Gogo* gogo, Named_object* function)
-{
- if (this->tree_ != NULL_TREE)
- return this->tree_;
-
- if (Gogo::is_erroneous_name(this->name_))
- {
- this->tree_ = error_mark_node;
- return error_mark_node;
- }
-
- tree decl;
- switch (this->classification_)
- {
- case NAMED_OBJECT_CONST:
- {
- Translate_context subcontext(gogo, function, NULL, NULL);
- Type* type = this->u_.const_value->type();
- Location loc = this->location();
-
- Expression* const_ref = Expression::make_const_reference(this, loc);
- Bexpression* const_decl =
- tree_to_expr(const_ref->get_tree(&subcontext));
- if (type != NULL && type->is_numeric_type())
- {
- Btype* btype = type->get_backend(gogo);
- std::string name = this->get_id(gogo);
- const_decl =
- gogo->backend()->named_constant_expression(btype, name,
- const_decl, loc);
- }
- decl = expr_to_tree(const_decl);
- }
- break;
-
- case NAMED_OBJECT_TYPE:
- {
- Named_type* named_type = this->u_.type_value;
- 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);
- 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
- // other files or packages might refer to them. We need
- // to do this even for hidden types, because they might
- // still be returned by some function. Simply calling the
- // type_descriptor method is enough to create the type
- // descriptor, even though we don't do anything with it.
- if (this->package_ == NULL)
- {
- named_type->
- type_descriptor_pointer(gogo,
- Linemap::predeclared_location());
- Type* pn = Type::make_pointer_type(named_type);
- pn->type_descriptor_pointer(gogo,
- Linemap::predeclared_location());
- }
- }
- }
- break;
-
- case NAMED_OBJECT_TYPE_DECLARATION:
- error("reference to undefined type %qs",
- this->message_name().c_str());
- return error_mark_node;
-
- case NAMED_OBJECT_VAR:
- case NAMED_OBJECT_RESULT_VAR:
- case NAMED_OBJECT_SINK:
- go_unreachable();
-
- case NAMED_OBJECT_FUNC:
- {
- Function* func = this->u_.func_value;
- decl = function_to_tree(func->get_or_make_decl(gogo, this));
- if (decl != error_mark_node)
- {
- if (func->block() != NULL)
- {
- if (DECL_STRUCT_FUNCTION(decl) == NULL)
- push_struct_function(decl);
- else
- push_cfun(DECL_STRUCT_FUNCTION(decl));
-
- cfun->function_start_locus = func->location().gcc_location();
- cfun->function_end_locus =
- func->block()->end_location().gcc_location();
-
- func->build(gogo, this);
-
- gimplify_function_tree(decl);
-
- cgraph_finalize_function(decl, true);
-
- pop_cfun();
- }
- }
- }
- break;
-
- case NAMED_OBJECT_ERRONEOUS:
- decl = error_mark_node;
- break;
-
- default:
- go_unreachable();
- }
-
- if (TREE_TYPE(decl) == error_mark_node)
- decl = error_mark_node;
-
- tree ret = decl;
-
- this->tree_ = ret;
-
- if (ret != error_mark_node)
- go_preserve_from_gc(ret);
-
- return ret;
-}
-
// Get the backend representation.
Bfunction*
@@ -1106,15 +282,6 @@ Function_declaration::get_or_make_decl(G
return this->fndecl_;
}
-// Return the function's decl after it has been built.
-
-tree
-Function::get_decl() const
-{
- go_assert(this->fndecl_ != NULL);
- return function_to_tree(this->fndecl_);
-}
-
// Build the descriptor for a function declaration. This won't
// necessarily happen if the package has just a declaration for the
// function and no other reference to it, but we may still need the
@@ -1214,55 +381,6 @@ go_type_for_mode(enum machine_mode mode,
return NULL_TREE;
}
-// Build a builtin struct with a list of fields. The name is
-// STRUCT_NAME. STRUCT_TYPE is NULL_TREE or an empty RECORD_TYPE
-// node; this exists so that the struct can have fields which point to
-// itself. If PTYPE is not NULL, store the result in *PTYPE. There
-// are NFIELDS fields. Each field is a name (a const char*) followed
-// by a type (a tree).
-
-tree
-Gogo::builtin_struct(tree* ptype, const char* struct_name, tree struct_type,
- int nfields, ...)
-{
- if (ptype != NULL && *ptype != NULL_TREE)
- return *ptype;
-
- va_list ap;
- va_start(ap, nfields);
-
- tree fields = NULL_TREE;
- for (int i = 0; i < nfields; ++i)
- {
- const char* field_name = va_arg(ap, const char*);
- tree type = va_arg(ap, tree);
- if (type == error_mark_node)
- {
- if (ptype != NULL)
- *ptype = error_mark_node;
- return error_mark_node;
- }
- tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL,
- get_identifier(field_name), type);
- DECL_CHAIN(field) = fields;
- fields = field;
- }
-
- va_end(ap);
-
- if (struct_type == NULL_TREE)
- struct_type = make_node(RECORD_TYPE);
- finish_builtin_struct(struct_type, struct_name, fields, NULL_TREE);
-
- if (ptype != NULL)
- {
- go_preserve_from_gc(struct_type);
- *ptype = struct_type;
- }
-
- return struct_type;
-}
-
// 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
===================================================================
@@ -406,9 +406,9 @@ class Backend
// integers, then STATEMENTS[i] is executed. STATEMENTS[i] will
// either end with a goto statement or will fall through into
// STATEMENTS[i + 1]. CASES[i] is empty for the default clause,
- // which need not be last.
+ // which need not be last. FUNCTION is the current function.
virtual Bstatement*
- switch_statement(Bexpression* value,
+ switch_statement(Bfunction* function, Bexpression* value,
const std::vector<std::vector<Bexpression*> >& cases,
const std::vector<Bstatement*>& statements,
Location) = 0;
@@ -534,6 +534,12 @@ class Backend
bool address_is_taken, Location location,
Bstatement** pstatement) = 0;
+ // Create a GC root variable. TYPE is the __go_gc_root_list struct described
+ // in Gogo::register_gc_vars. INIT is the composite literal consisting of a
+ // pointer to the next GC root and the global variables registered.
+ virtual Bvariable*
+ gc_root_variable(Btype* type, Bexpression* init) = 0;
+
// Create a named immutable initialized data structure. This is
// used for type descriptors, map descriptors, and function
// descriptors. This returns a Bvariable because it corresponds to
@@ -653,6 +659,16 @@ class Backend
// true on success, false on failure.
virtual bool
function_set_body(Bfunction* function, Bstatement* code_stmt) = 0;
+
+ // Utility.
+
+ // Write the definitions for all TYPE_DECLS, CONSTANT_DECLS,
+ // FUNCTION_DECLS, and VARIABLE_DECLS declared globally.
+ virtual void
+ write_global_definitions(const std::vector<Btype*>& type_decls,
+ const std::vector<Bexpression*>& constant_decls,
+ const std::vector<Bfunction*>& function_decls,
+ const std::vector<Bvariable*>& variable_decls) = 0;
};
// The backend interface has to define this function.
===================================================================
@@ -3578,127 +3578,7 @@ Expression::make_unsafe_cast(Type* type,
return new Unsafe_type_conversion_expression(type, expr, location);
}
-// Unary expressions.
-
-class Unary_expression : public Expression
-{
- public:
- Unary_expression(Operator op, Expression* expr, Location location)
- : Expression(EXPRESSION_UNARY, location),
- op_(op), escapes_(true), create_temp_(false), expr_(expr),
- issue_nil_check_(false)
- { }
-
- // Return the operator.
- Operator
- op() const
- { return this->op_; }
-
- // Return the operand.
- Expression*
- operand() const
- { return this->expr_; }
-
- // Record that an address expression does not escape.
- void
- set_does_not_escape()
- {
- go_assert(this->op_ == OPERATOR_AND);
- this->escapes_ = false;
- }
-
- // Record that this is an address expression which should create a
- // temporary variable if necessary. This is used for method calls.
- void
- set_create_temp()
- {
- go_assert(this->op_ == OPERATOR_AND);
- this->create_temp_ = true;
- }
-
- // Apply unary opcode OP to UNC, setting NC. Return true if this
- // could be done, false if not. Issue errors for overflow.
- static bool
- eval_constant(Operator op, const Numeric_constant* unc,
- Location, Numeric_constant* nc);
-
- static Expression*
- do_import(Import*);
-
- protected:
- int
- do_traverse(Traverse* traverse)
- { return Expression::traverse(&this->expr_, traverse); }
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- Expression*
- do_flatten(Gogo*, Named_object*, Statement_inserter*);
-
- bool
- do_is_constant() const;
-
- bool
- do_is_immutable() const
- { return this->expr_->is_immutable()
- || (this->op_ == OPERATOR_AND && this->expr_->is_variable()); }
-
- bool
- do_numeric_constant_value(Numeric_constant*) const;
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_unary(this->op_, this->expr_->copy(),
- this->location());
- }
-
- bool
- do_must_eval_subexpressions_in_order(int*) const
- { return this->op_ == OPERATOR_MULT; }
-
- bool
- do_is_addressable() const
- { return this->op_ == OPERATOR_MULT; }
-
- tree
- do_get_tree(Translate_context*);
-
- void
- do_export(Export*) const;
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- void
- do_issue_nil_check()
- { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }
-
- private:
- // The unary operator to apply.
- Operator op_;
- // Normally true. False if this is an address expression which does
- // not escape the current function.
- bool escapes_;
- // True if this is an address expression which should create a
- // temporary variable if necessary.
- bool create_temp_;
- // The operand.
- Expression* expr_;
- // Whether or not to issue a nil check for this expression if its address
- // is being taken.
- bool issue_nil_check_;
-};
+// Class Unary_expression.
// If we are taking the address of a composite literal, and the
// contents are not constant, then we want to make a heap expression
@@ -4214,11 +4094,18 @@ Unary_expression::do_get_tree(Translate_
}
}
- // Build a decl for a constant constructor.
- if ((this->expr_->is_composite_literal()
+ if (this->is_gc_root_)
+ {
+ // Build a decl for a GC root variable. GC roots are mutable, so they
+ // cannot be represented as an immutable_struct in the backend.
+ Bvariable* gc_root = gogo->backend()->gc_root_variable(btype, bexpr);
+ bexpr = gogo->backend()->var_expression(gc_root, loc);
+ }
+ else if ((this->expr_->is_composite_literal()
|| this->expr_->string_expression() != NULL)
&& this->expr_->is_immutable())
{
+ // Build a decl for a constant constructor.
static unsigned int counter;
char buf[100];
snprintf(buf, sizeof buf, "C%u", counter);
@@ -12508,6 +12395,14 @@ Fixed_array_construction_expression::do_
return expr_to_tree(this->get_constructor(context, btype));
}
+Expression*
+Expression::make_array_composite_literal(Type* type, Expression_list* vals,
+ Location location)
+{
+ go_assert(type->array_type() != NULL && !type->is_slice_type());
+ return new Fixed_array_construction_expression(type, NULL, vals, location);
+}
+
// Construct a slice.
class Slice_construction_expression : public Array_construction_expression
===================================================================
@@ -575,6 +575,164 @@ Gogo::current_bindings() const
return this->globals_;
}
+// Add statements to INIT_STMTS which run the initialization
+// functions for imported packages. This is only used for the "main"
+// package.
+
+void
+Gogo::init_imports(std::vector<Bstatement*>& init_stmts)
+{
+ go_assert(this->is_main_package());
+
+ if (this->imported_init_fns_.empty())
+ return;
+
+ Location unknown_loc = Linemap::unknown_location();
+ Function_type* func_type =
+ Type::make_function_type(NULL, NULL, NULL, unknown_loc);
+ Btype* fntype = func_type->get_backend_fntype(this);
+
+ // We must call them in increasing priority order.
+ std::vector<Import_init> v;
+ for (std::set<Import_init>::const_iterator p =
+ this->imported_init_fns_.begin();
+ p != this->imported_init_fns_.end();
+ ++p)
+ v.push_back(*p);
+ std::sort(v.begin(), v.end());
+
+ // We build calls to the init functions, which take no arguments.
+ std::vector<Bexpression*> empty_args;
+ for (std::vector<Import_init>::const_iterator p = v.begin();
+ p != v.end();
+ ++p)
+ {
+ std::string user_name = p->package_name() + ".init";
+ const std::string& init_name(p->init_name());
+
+ Bfunction* pfunc = this->backend()->function(fntype, user_name, init_name,
+ true, true, true, false,
+ false, unknown_loc);
+ Bexpression* pfunc_code =
+ this->backend()->function_code_expression(pfunc, unknown_loc);
+ Bexpression* pfunc_call =
+ this->backend()->call_expression(pfunc_code, empty_args, unknown_loc);
+ init_stmts.push_back(this->backend()->expression_statement(pfunc_call));
+ }
+}
+
+// Register global variables with the garbage collector. We need to
+// register all variables which can hold a pointer value. They become
+// roots during the mark phase. We build a struct that is easy to
+// hook into a list of roots.
+
+// struct __go_gc_root_list
+// {
+// struct __go_gc_root_list* __next;
+// struct __go_gc_root
+// {
+// void* __decl;
+// size_t __size;
+// } __roots[];
+// };
+
+// The last entry in the roots array has a NULL decl field.
+
+void
+Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc,
+ std::vector<Bstatement*>& init_stmts)
+{
+ if (var_gc.empty())
+ return;
+
+ Type* pvt = Type::make_pointer_type(Type::make_void_type());
+ Type* uint_type = Type::lookup_integer_type("uint");
+ Struct_type* root_type = Type::make_builtin_struct_type(2,
+ "__decl", pvt,
+ "__size", uint_type);
+
+ Location builtin_loc = Linemap::predeclared_location();
+ size_t count = var_gc.size();
+ mpz_t lenval;
+ mpz_init_set_ui(lenval, count);
+ Expression* length = Expression::make_integer(&lenval, NULL, builtin_loc);
+ mpz_clear(lenval);
+
+ Array_type* root_array_type = Type::make_array_type(root_type, length);
+ Type* ptdt = Type::make_type_descriptor_ptr_type();
+ Struct_type* root_list_type =
+ Type::make_builtin_struct_type(2,
+ "__next", ptdt,
+ "__roots", root_array_type);
+
+ // Build an initializer for the __roots array.
+
+ Expression_list* roots_init = new Expression_list();
+
+ size_t i = 0;
+ for (std::vector<Named_object*>::const_iterator p = var_gc.begin();
+ p != var_gc.end();
+ ++p, ++i)
+ {
+ Expression_list* init = new Expression_list();
+
+ Location no_loc = (*p)->location();
+ Expression* decl = Expression::make_var_reference(*p, no_loc);
+ Expression* decl_addr =
+ Expression::make_unary(OPERATOR_AND, decl, no_loc);
+ init->push_back(decl_addr);
+
+ Expression* decl_size =
+ Expression::make_type_info(decl->type(), Expression::TYPE_INFO_SIZE);
+ init->push_back(decl_size);
+
+ Expression* root_ctor =
+ Expression::make_struct_composite_literal(root_type, init, no_loc);
+ roots_init->push_back(root_ctor);
+ }
+
+ // The list ends with a NULL entry.
+
+ Expression_list* null_init = new Expression_list();
+ Expression* nil = Expression::make_nil(builtin_loc);
+ null_init->push_back(nil);
+
+ mpz_t zval;
+ mpz_init_set_ui(zval, 0UL);
+ Expression* zero = Expression::make_integer(&zval, NULL, builtin_loc);
+ mpz_clear(zval);
+ null_init->push_back(zero);
+
+ Expression* null_root_ctor =
+ Expression::make_struct_composite_literal(root_type, null_init,
+ builtin_loc);
+ roots_init->push_back(null_root_ctor);
+
+ // Build a constructor for the struct.
+
+ Expression_list* root_list_init = new Expression_list();
+ root_list_init->push_back(nil);
+
+ Expression* roots_ctor =
+ Expression::make_array_composite_literal(root_array_type, roots_init,
+ builtin_loc);
+ root_list_init->push_back(roots_ctor);
+
+ Expression* root_list_ctor =
+ Expression::make_struct_composite_literal(root_list_type, root_list_init,
+ builtin_loc);
+
+ Expression* root_addr = Expression::make_unary(OPERATOR_AND, root_list_ctor,
+ builtin_loc);
+ root_addr->unary_expression()->set_is_gc_root();
+ Expression* register_roots = Runtime::make_call(Runtime::REGISTER_GC_ROOTS,
+ builtin_loc, 1, root_addr);
+
+ Translate_context context(this, NULL, NULL, NULL);
+ Bexpression* bcall = tree_to_expr(register_roots->get_tree(&context));
+ init_stmts.push_back(this->backend()->expression_statement(bcall));
+}
+
// Get the name to use for the import control function. If there is a
// global function or variable, then we know that that name must be
// unique in the link, and we use it as the basis for our name.
@@ -614,6 +772,521 @@ Gogo::initialization_function_decl()
return Named_object::make_function(name, NULL, initfn);
}
+// Create the magic initialization function. CODE_STMT is the
+// code that it needs to run.
+
+Named_object*
+Gogo::create_initialization_function(Named_object* initfn,
+ Bstatement* code_stmt)
+{
+ // Make sure that we thought we needed an initialization function,
+ // as otherwise we will not have reported it in the export data.
+ go_assert(this->is_main_package() || this->need_init_fn_);
+
+ if (initfn == NULL)
+ initfn = this->initialization_function_decl();
+
+ // Bind the initialization function code to a block.
+ Bfunction* fndecl = initfn->func_value()->get_or_make_decl(this, initfn);
+ Location pkg_loc = this->package_->location();
+ std::vector<Bvariable*> vars;
+ this->backend()->block(fndecl, NULL, vars, pkg_loc, pkg_loc);
+
+ if (!this->backend()->function_set_body(fndecl, code_stmt))
+ {
+ go_assert(saw_errors());
+ return NULL;
+ }
+ return initfn;
+}
+
+// Search for references to VAR in any statements or called functions.
+
+class Find_var : public Traverse
+{
+ public:
+ // A hash table we use to avoid looping. The index is the name of a
+ // named object. We only look through objects defined in this
+ // package.
+ typedef Unordered_set(const void*) Seen_objects;
+
+ Find_var(Named_object* var, Seen_objects* seen_objects)
+ : Traverse(traverse_expressions),
+ var_(var), seen_objects_(seen_objects), found_(false)
+ { }
+
+ // Whether the variable was found.
+ bool
+ found() const
+ { return this->found_; }
+
+ int
+ expression(Expression**);
+
+ private:
+ // The variable we are looking for.
+ Named_object* var_;
+ // Names of objects we have already seen.
+ Seen_objects* seen_objects_;
+ // True if the variable was found.
+ bool found_;
+};
+
+// See if EXPR refers to VAR, looking through function calls and
+// variable initializations.
+
+int
+Find_var::expression(Expression** pexpr)
+{
+ Expression* e = *pexpr;
+
+ Var_expression* ve = e->var_expression();
+ if (ve != NULL)
+ {
+ Named_object* v = ve->named_object();
+ if (v == this->var_)
+ {
+ this->found_ = true;
+ return TRAVERSE_EXIT;
+ }
+
+ if (v->is_variable() && v->package() == NULL)
+ {
+ Expression* init = v->var_value()->init();
+ if (init != NULL)
+ {
+ std::pair<Seen_objects::iterator, bool> ins =
+ this->seen_objects_->insert(v);
+ if (ins.second)
+ {
+ // This is the first time we have seen this name.
+ if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ }
+ }
+ }
+ }
+
+ // We traverse the code of any function we see. Note that this
+ // means that we will traverse the code of a function whose address
+ // is taken even if it is not called.
+ Func_expression* fe = e->func_expression();
+ if (fe != NULL)
+ {
+ const Named_object* f = fe->named_object();
+ if (f->is_function() && f->package() == NULL)
+ {
+ std::pair<Seen_objects::iterator, bool> ins =
+ this->seen_objects_->insert(f);
+ if (ins.second)
+ {
+ // This is the first time we have seen this name.
+ if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ }
+ }
+ }
+
+ Temporary_reference_expression* tre = e->temporary_reference_expression();
+ if (tre != NULL)
+ {
+ Temporary_statement* ts = tre->statement();
+ Expression* init = ts->init();
+ if (init != NULL)
+ {
+ std::pair<Seen_objects::iterator, bool> ins =
+ this->seen_objects_->insert(ts);
+ if (ins.second)
+ {
+ // This is the first time we have seen this temporary
+ // statement.
+ if (Expression::traverse(&init, this) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+ }
+ }
+ }
+
+ return TRAVERSE_CONTINUE;
+}
+
+// Return true if EXPR, PREINIT, or DEP refers to VAR.
+
+static bool
+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);
+ if (expr != NULL)
+ 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();
+}
+
+// Sort variable initializations. If the initialization expression
+// for variable A refers directly or indirectly to the initialization
+// expression for variable B, then we must initialize B before A.
+
+class Var_init
+{
+ public:
+ Var_init()
+ : var_(NULL), init_(NULL)
+ { }
+
+ Var_init(Named_object* var, Bstatement* init)
+ : var_(var), init_(init)
+ { }
+
+ // Return the variable.
+ Named_object*
+ var() const
+ { return this->var_; }
+
+ // Return the initialization expression.
+ Bstatement*
+ init() const
+ { return this->init_; }
+
+ private:
+ // The variable being initialized.
+ Named_object* var_;
+ // The initialization statement.
+ Bstatement* init_;
+};
+
+typedef std::list<Var_init> Var_inits;
+
+// Sort the variable initializations. The rule we follow is that we
+// emit them in the order they appear in the array, except that if the
+// initialization expression for a variable V1 depends upon another
+// variable V2 then we initialize V1 after V2.
+
+static void
+sort_var_inits(Gogo* gogo, Var_inits* var_inits)
+{
+ typedef std::pair<Named_object*, Named_object*> No_no;
+ typedef std::map<No_no, bool> Cache;
+ Cache cache;
+
+ Var_inits ready;
+ while (!var_inits->empty())
+ {
+ Var_inits::iterator p1 = var_inits->begin();
+ 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.
+ Var_inits::iterator p2 = p1;
+ ++p2;
+
+ for (; p2 != var_inits->end(); ++p2)
+ {
+ Named_object* p2var = p2->var();
+ No_no key(var, p2var);
+ std::pair<Cache::iterator, bool> ins =
+ cache.insert(std::make_pair(key, false));
+ if (ins.second)
+ ins.first->second = expression_requires(init, preinit, dep, p2var);
+ if (ins.first->second)
+ {
+ // Check for cycles.
+ key = std::make_pair(p2var, var);
+ ins = cache.insert(std::make_pair(key, false));
+ if (ins.second)
+ ins.first->second =
+ expression_requires(p2var->var_value()->init(),
+ p2var->var_value()->preinit(),
+ gogo->var_depends_on(p2var->var_value()),
+ var);
+ if (ins.first->second)
+ {
+ error_at(var->location(),
+ ("initialization expressions for %qs and "
+ "%qs depend upon each other"),
+ var->message_name().c_str(),
+ p2var->message_name().c_str());
+ inform(p2->var()->location(), "%qs defined here",
+ p2var->message_name().c_str());
+ p2 = var_inits->end();
+ }
+ else
+ {
+ // We can't emit P1 until P2 is emitted. Move P1.
+ Var_inits::iterator p3 = p2;
+ ++p3;
+ var_inits->splice(p3, *var_inits, p1);
+ }
+ break;
+ }
+ }
+
+ if (p2 == var_inits->end())
+ {
+ // 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 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());
+ ready.splice(ready.end(), *var_inits, p1);
+ }
+ }
+
+ // Now READY is the list in the desired initialization order.
+ var_inits->swap(ready);
+}
+
+// Write out the global definitions.
+
+void
+Gogo::write_globals()
+{
+ this->build_interface_method_tables();
+
+ Bindings* bindings = this->current_bindings();
+
+ for (Bindings::const_declarations_iterator p = bindings->begin_declarations();
+ p != bindings->end_declarations();
+ ++p)
+ {
+ // If any function declarations needed a descriptor, make sure
+ // we build it.
+ Named_object* no = p->second;
+ if (no->is_function_declaration())
+ no->func_declaration_value()->build_backend_descriptor(this);
+ }
+
+ // Lists of globally declared types, variables, constants, and functions
+ // that must be defined.
+ std::vector<Btype*> type_decls;
+ std::vector<Bvariable*> var_decls;
+ std::vector<Bexpression*> const_decls;
+ std::vector<Bfunction*> func_decls;
+
+ // The init function declaration, if necessary.
+ Named_object* init_fndecl = NULL;
+
+ std::vector<Bstatement*> init_stmts;
+ std::vector<Bstatement*> var_init_stmts;
+
+ if (this->is_main_package())
+ this->init_imports(init_stmts);
+
+ // A list of variable initializations.
+ Var_inits var_inits;
+
+ // A list of variables which need to be registered with the garbage
+ // collector.
+ size_t count_definitions = bindings->size_definitions();
+ std::vector<Named_object*> var_gc;
+ var_gc.reserve(count_definitions);
+
+ for (Bindings::const_definitions_iterator p = bindings->begin_definitions();
+ p != bindings->end_definitions();
+ ++p)
+ {
+ Named_object* no = *p;
+ go_assert(!no->is_type_declaration() && !no->is_function_declaration());
+
+ // There is nothing to do for a package.
+ if (no->is_package())
+ continue;
+
+ // There is nothing to do for an object which was imported from
+ // a different package into the global scope.
+ if (no->package() != NULL)
+ continue;
+
+ // Skip blank named functions and constants.
+ if ((no->is_function() && no->func_value()->is_sink())
+ || (no->is_const() && no->const_value()->is_sink()))
+ continue;
+
+ // There is nothing useful we can output for constants which
+ // have ideal or non-integral type.
+ if (no->is_const())
+ {
+ Type* type = no->const_value()->type();
+ if (type == NULL)
+ type = no->const_value()->expr()->type();
+ if (type->is_abstract() || !type->is_numeric_type())
+ continue;
+ }
+
+ if (!no->is_variable())
+ no->get_backend(this, const_decls, type_decls, func_decls);
+ else
+ {
+ Variable* var = no->var_value();
+ Bvariable* bvar = no->get_backend_variable(this, NULL);
+ var_decls.push_back(bvar);
+
+ // 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] == '.';
+
+ Bstatement* var_init_stmt = NULL;
+ if (!var->has_pre_init())
+ {
+ Bexpression* var_binit = var->get_init(this, NULL);
+
+ // If the backend representation of the variable initializer is
+ // constant, we can just set the initial value using
+ // global_var_set_init instead of during the init() function.
+ // The initializer is constant if it is the zero-value of the
+ // variable's type or if the initial value is an immutable value
+ // that is not copied to the heap.
+ bool is_constant_initializer = false;
+ if (var->init() == NULL)
+ is_constant_initializer = true;
+ else
+ {
+ Type* var_type = var->type();
+ Expression* init = var->init();
+ Expression* init_cast =
+ Expression::make_cast(var_type, init, var->location());
+ is_constant_initializer =
+ init_cast->is_immutable() && !var_type->has_pointer();
+ }
+
+ if (var_binit == NULL)
+ ;
+ else if (is_constant_initializer)
+ {
+ if (expression_requires(var->init(), NULL,
+ this->var_depends_on(var), no))
+ error_at(no->location(),
+ "initialization expression for %qs depends "
+ "upon itself",
+ no->message_name().c_str());
+ this->backend()->global_variable_set_init(bvar, var_binit);
+ }
+ else if (is_sink)
+ var_init_stmt =
+ this->backend()->expression_statement(var_binit);
+ else
+ {
+ Location loc = var->location();
+ Bexpression* var_expr =
+ this->backend()->var_expression(bvar, loc);
+ var_init_stmt =
+ this->backend()->assignment_statement(var_expr, var_binit,
+ loc);
+ }
+ }
+ else
+ {
+ // We are going to create temporary variables which
+ // means that we need an fndecl.
+ if (init_fndecl == NULL)
+ init_fndecl = this->initialization_function_decl();
+
+ Bvariable* var_decl = is_sink ? NULL : bvar;
+ var_init_stmt = var->get_init_block(this, init_fndecl, var_decl);
+ }
+
+ if (var_init_stmt != NULL)
+ {
+ if (var->init() == NULL && !var->has_pre_init())
+ var_init_stmts.push_back(var_init_stmt);
+ else
+ var_inits.push_back(Var_init(no, var_init_stmt));
+ }
+ else if (this->var_depends_on(var) != 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.
+ Btype* btype = no->var_value()->type()->get_backend(this);
+ Bexpression* zero = this->backend()->zero_expression(btype);
+ Bstatement* zero_stmt =
+ this->backend()->expression_statement(zero);
+ var_inits.push_back(Var_init(no, zero_stmt));
+ }
+
+ if (!is_sink && var->type()->has_pointer())
+ var_gc.push_back(no);
+ }
+ }
+
+ // Register global variables with the garbage collector.
+ this->register_gc_vars(var_gc, init_stmts);
+
+ // Simple variable initializations, after all variables are
+ // registered.
+ init_stmts.push_back(this->backend()->statement_list(var_init_stmts));
+
+ // Complete variable initializations, first sorting them into a
+ // workable order.
+ if (!var_inits.empty())
+ {
+ sort_var_inits(this, &var_inits);
+ for (Var_inits::const_iterator p = var_inits.begin();
+ p != var_inits.end();
+ ++p)
+ init_stmts.push_back(p->init());
+ }
+
+ // After all the variables are initialized, call the init
+ // functions if there are any. Init functions take no arguments, so
+ // we pass in EMPTY_ARGS to call them.
+ std::vector<Bexpression*> empty_args;
+ for (std::vector<Named_object*>::const_iterator p =
+ this->init_functions_.begin();
+ p != this->init_functions_.end();
+ ++p)
+ {
+ Location func_loc = (*p)->location();
+ Function* func = (*p)->func_value();
+ Bfunction* initfn = func->get_or_make_decl(this, *p);
+ Bexpression* func_code =
+ this->backend()->function_code_expression(initfn, func_loc);
+ Bexpression* call = this->backend()->call_expression(func_code,
+ empty_args,
+ func_loc);
+ init_stmts.push_back(this->backend()->expression_statement(call));
+ }
+
+ // Set up a magic function to do all the initialization actions.
+ // This will be called if this package is imported.
+ Bstatement* init_fncode = this->backend()->statement_list(init_stmts);
+ if (this->need_init_fn_ || this->is_main_package())
+ {
+ init_fndecl =
+ this->create_initialization_function(init_fndecl, init_fncode);
+ if (init_fndecl != NULL)
+ func_decls.push_back(init_fndecl->func_value()->get_decl());
+ }
+
+ // We should not have seen any new bindings created during the conversion.
+ go_assert(count_definitions == this->current_bindings()->size_definitions());
+
+ // Define all globally declared values.
+ if (!saw_errors())
+ this->backend()->write_global_definitions(type_decls, const_decls,
+ func_decls, var_decls);
+}
+
// Return the current block.
Block*
@@ -4182,6 +4855,15 @@ Function::get_or_make_decl(Gogo* gogo, N
return this->fndecl_;
}
+// Return the function's decl after it has been built.
+
+Bfunction*
+Function::get_decl() const
+{
+ go_assert(this->fndecl_ != NULL);
+ return this->fndecl_;
+}
+
// Build the backend representation for the function code.
void
@@ -5266,8 +5948,7 @@ Variable::get_init_block(Gogo* gogo, Nam
{
Location loc = this->location();
Expression* val_expr =
- Expression::convert_for_assignment(gogo, this->type(),
- this->init_, this->location());
+ Expression::make_cast(this->type(), this->init_, loc);
Bexpression* val = tree_to_expr(val_expr->get_tree(&context));
Bexpression* var_ref = gogo->backend()->var_expression(var_decl, loc);
decl_init = gogo->backend()->assignment_statement(var_ref, val, loc);
@@ -5353,8 +6034,7 @@ Variable::get_backend_variable(Gogo* gog
}
else
{
- tree fndecl = function->func_value()->get_decl();
- Bfunction* bfunction = tree_to_function(fndecl);
+ Bfunction* bfunction = function->func_value()->get_decl();
bool is_address_taken = (this->is_non_escaping_address_taken_
&& !this->is_in_heap());
if (is_parameter)
@@ -5391,8 +6071,7 @@ Result_variable::get_backend_variable(Go
if (this->is_in_heap())
type = Type::make_pointer_type(type);
Btype* btype = type->get_backend(gogo);
- tree fndecl = function->func_value()->get_decl();
- Bfunction* bfunction = tree_to_function(fndecl);
+ Bfunction* bfunction = function->func_value()->get_decl();
std::string n = Gogo::unpack_hidden_name(name);
bool is_address_taken = (this->is_non_escaping_address_taken_
&& !this->is_in_heap());
@@ -5482,6 +6161,33 @@ Named_constant::import_const(Import* imp
imp->require_c_string(";\n");
}
+// Get the backend representation.
+
+Bexpression*
+Named_constant::get_backend(Gogo* gogo, Named_object* const_no)
+{
+ if (this->bconst_ == NULL)
+ {
+ Translate_context subcontext(gogo, NULL, NULL, NULL);
+ Type* type = this->type();
+ Location loc = this->location();
+
+ Expression* const_ref = Expression::make_const_reference(const_no, loc);
+ Bexpression* const_decl =
+ tree_to_expr(const_ref->get_tree(&subcontext));
+ if (type != NULL && type->is_numeric_type())
+ {
+ Btype* btype = type->get_backend(gogo);
+ std::string name = const_no->get_id(gogo);
+ const_decl =
+ gogo->backend()->named_constant_expression(btype, name,
+ const_decl, loc);
+ }
+ this->bconst_ = const_decl;
+ }
+ return this->bconst_;
+}
+
// Add a method.
Named_object*
@@ -5552,8 +6258,7 @@ Unknown_name::set_real_named_object(Name
Named_object::Named_object(const std::string& name,
const Package* package,
Classification classification)
- : name_(name), package_(package), classification_(classification),
- tree_(NULL)
+ : name_(name), package_(package), classification_(classification)
{
if (Gogo::is_sink_name(name))
go_assert(classification == NAMED_OBJECT_SINK);
@@ -5928,6 +6633,72 @@ Named_object::get_id(Gogo* gogo)
return decl_name;
}
+// Get the backend representation for this named object.
+
+void
+Named_object::get_backend(Gogo* gogo, std::vector<Bexpression*>& const_decls,
+ std::vector<Btype*>& type_decls,
+ std::vector<Bfunction*>& func_decls)
+{
+ switch (this->classification_)
+ {
+ case NAMED_OBJECT_CONST:
+ if (!Gogo::is_erroneous_name(this->name_))
+ const_decls.push_back(this->u_.const_value->get_backend(gogo, this));
+ break;
+
+ case NAMED_OBJECT_TYPE:
+ {
+ Named_type* named_type = this->u_.type_value;
+ if (!Gogo::is_erroneous_name(this->name_))
+ type_decls.push_back(named_type->get_backend(gogo));
+
+ // We need to produce a type descriptor for every named
+ // type, and for a pointer to every named type, since
+ // other files or packages might refer to them. We need
+ // to do this even for hidden types, because they might
+ // still be returned by some function. Simply calling the
+ // type_descriptor method is enough to create the type
+ // descriptor, even though we don't do anything with it.
+ if (this->package_ == NULL)
+ {
+ named_type->
+ type_descriptor_pointer(gogo, Linemap::predeclared_location());
+ Type* pn = Type::make_pointer_type(named_type);
+ pn->type_descriptor_pointer(gogo, Linemap::predeclared_location());
+ }
+ }
+ break;
+
+ case NAMED_OBJECT_TYPE_DECLARATION:
+ error("reference to undefined type %qs",
+ this->message_name().c_str());
+ return;
+
+ case NAMED_OBJECT_VAR:
+ case NAMED_OBJECT_RESULT_VAR:
+ case NAMED_OBJECT_SINK:
+ go_unreachable();
+
+ case NAMED_OBJECT_FUNC:
+ {
+ Function* func = this->u_.func_value;
+ if (!Gogo::is_erroneous_name(this->name_))
+ func_decls.push_back(func->get_or_make_decl(gogo, this));
+
+ if (func->block() != NULL)
+ func->build(gogo, this);
+ }
+ break;
+
+ case NAMED_OBJECT_ERRONEOUS:
+ break;
+
+ default:
+ go_unreachable();
+ }
+}
+
// Class Bindings.
Bindings::Bindings(Bindings* enclosing)
@@ -6400,8 +7171,7 @@ Label::get_backend_label(Translate_conte
if (this->blabel_ == NULL)
{
Function* function = context->function()->func_value();
- tree fndecl = function->get_decl();
- Bfunction* bfunction = tree_to_function(fndecl);
+ Bfunction* bfunction = function->get_decl();
this->blabel_ = context->backend()->label(bfunction, this->name_,
this->location_);
}
@@ -6427,8 +7197,7 @@ Unnamed_label::get_blabel(Translate_cont
if (this->blabel_ == NULL)
{
Function* function = context->function()->func_value();
- tree fndecl = function->get_decl();
- Bfunction* bfunction = tree_to_function(fndecl);
+ Bfunction* bfunction = function->get_decl();
this->blabel_ = context->backend()->label(bfunction, "",
this->location_);
}
===================================================================
@@ -29,9 +29,11 @@
#include "stor-layout.h"
#include "varasm.h"
#include "tree-iterator.h"
+#include "cgraph.h"
#include "convert.h"
#include "basic-block.h"
#include "gimple-expr.h"
+#include "gimplify.h"
#include "toplev.h"
#include "output.h"
#include "real.h"
@@ -317,7 +319,7 @@ class Gcc_backend : public Backend
Location);
Bstatement*
- switch_statement(Bexpression* value,
+ switch_statement(Bfunction* function, Bexpression* value,
const std::vector<std::vector<Bexpression*> >& cases,
const std::vector<Bstatement*>& statements,
Location);
@@ -376,6 +378,9 @@ class Gcc_backend : public Backend
Location, Bstatement**);
Bvariable*
+ gc_root_variable(Btype*, Bexpression*);
+
+ Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location);
void
@@ -420,6 +425,12 @@ class Gcc_backend : public Backend
bool
function_set_body(Bfunction* function, Bstatement* code_stmt);
+ void
+ write_global_definitions(const std::vector<Btype*>&,
+ const std::vector<Bexpression*>&,
+ const std::vector<Bfunction*>&,
+ const std::vector<Bvariable*>&);
+
private:
// Make a Bexpression from a tree.
Bexpression*
@@ -1709,6 +1720,7 @@ Gcc_backend::return_statement(Bfunction*
tree result = DECL_RESULT(fntree);
if (result == error_mark_node)
return this->error_statement();
+
tree ret;
if (vals.empty())
ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node,
@@ -1732,7 +1744,14 @@ Gcc_backend::return_statement(Bfunction*
// statement.
tree stmt_list = NULL_TREE;
tree rettype = TREE_TYPE(result);
+
+ if (DECL_STRUCT_FUNCTION(fntree) == NULL)
+ push_struct_function(fntree);
+ else
+ push_cfun(DECL_STRUCT_FUNCTION(fntree));
tree rettmp = create_tmp_var(rettype, "RESULT");
+ pop_cfun();
+
tree field = TYPE_FIELDS(rettype);
for (std::vector<Bexpression*>::const_iterator p = vals.begin();
p != vals.end();
@@ -1818,6 +1837,7 @@ Gcc_backend::if_statement(Bexpression* c
Bstatement*
Gcc_backend::switch_statement(
+ Bfunction* function,
Bexpression* value,
const std::vector<std::vector<Bexpression*> >& cases,
const std::vector<Bstatement*>& statements,
@@ -1825,6 +1845,12 @@ Gcc_backend::switch_statement(
{
gcc_assert(cases.size() == statements.size());
+ tree decl = function->get_tree();
+ if (DECL_STRUCT_FUNCTION(decl) == NULL)
+ push_struct_function(decl);
+ else
+ push_cfun(DECL_STRUCT_FUNCTION(decl));
+
tree stmt_list = NULL_TREE;
std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin();
for (std::vector<Bstatement*>::const_iterator ps = statements.begin();
@@ -1864,6 +1890,7 @@ Gcc_backend::switch_statement(
append_to_statement_list(t, &stmt_list);
}
}
+ pop_cfun();
tree tv = value->get_tree();
if (tv == error_mark_node)
@@ -1922,13 +1949,7 @@ Gcc_backend::block(Bfunction* function,
tree block_tree = make_node(BLOCK);
if (enclosing == NULL)
{
- // FIXME: Permitting FUNCTION to be NULL is a temporary measure
- // until we have a proper representation of the init function.
- tree fndecl;
- if (function == NULL)
- fndecl = current_function_decl;
- else
- fndecl = function->get_tree();
+ tree fndecl = function->get_tree();
gcc_assert(fndecl != NULL_TREE);
// We may have already created a block for local variables when
@@ -1982,7 +2003,6 @@ Gcc_backend::block(Bfunction* function,
void_type_node, BLOCK_VARS(block_tree),
NULL_TREE, block_tree);
TREE_SIDE_EFFECTS(bind_tree) = 1;
-
return new Bblock(bind_tree);
}
@@ -2214,7 +2234,7 @@ Gcc_backend::temporary_variable(Bfunctio
return this->error_variable();
}
- go_assert(function != NULL);
+ gcc_assert(function != NULL);
tree decl = function->get_tree();
tree var;
@@ -2263,6 +2283,28 @@ Gcc_backend::temporary_variable(Bfunctio
return new Bvariable(var);
}
+// Make a GC root variable.
+
+Bvariable*
+Gcc_backend::gc_root_variable(Btype* type, Bexpression* init)
+{
+ tree type_tree = type->get_tree();
+ tree init_tree = init->get_tree();
+ if (type_tree == error_mark_node || init_tree == error_mark_node)
+ return this->error_variable();
+
+ tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL,
+ create_tmp_var_name("gc"), type_tree);
+ DECL_EXTERNAL(decl) = 0;
+ TREE_PUBLIC(decl) = 0;
+ TREE_STATIC(decl) = 1;
+ DECL_ARTIFICIAL(decl) = 1;
+ DECL_INITIAL(decl) = init_tree;
+ rest_of_decl_compilation(decl, 1, 0);
+
+ return new Bvariable(decl);
+}
+
// Create a named immutable initialized data structure.
Bvariable*
@@ -2277,9 +2319,9 @@ Gcc_backend::immutable_struct(const std:
get_identifier_from_string(name),
build_qualified_type(type_tree, TYPE_QUAL_CONST));
TREE_STATIC(decl) = 1;
+ TREE_USED(decl) = 1;
TREE_READONLY(decl) = 1;
TREE_CONSTANT(decl) = 1;
- TREE_USED(decl) = 1;
DECL_ARTIFICIAL(decl) = 1;
if (!is_hidden)
TREE_PUBLIC(decl) = 1;
@@ -2369,7 +2411,17 @@ Gcc_backend::label(Bfunction* function,
{
tree decl;
if (name.empty())
- decl = create_artificial_label(location.gcc_location());
+ {
+ tree func_tree = function->get_tree();
+ if (DECL_STRUCT_FUNCTION(func_tree) == NULL)
+ push_struct_function(func_tree);
+ else
+ push_cfun(DECL_STRUCT_FUNCTION(func_tree));
+
+ decl = create_artificial_label(location.gcc_location());
+
+ pop_cfun();
+ }
else
{
tree id = get_identifier_from_string(name);
@@ -2477,11 +2529,18 @@ Gcc_backend::function_defer_statement(Bf
{
tree undefer_tree = undefer->get_tree();
tree defer_tree = defer->get_tree();
+ tree fntree = function->get_tree();
if (undefer_tree == error_mark_node
- || defer_tree == error_mark_node)
+ || defer_tree == error_mark_node
+ || fntree == error_mark_node)
return this->error_statement();
+ if (DECL_STRUCT_FUNCTION(fntree) == NULL)
+ push_struct_function(fntree);
+ else
+ push_cfun(DECL_STRUCT_FUNCTION(fntree));
+
tree stmt_list = NULL;
Blabel* blabel = this->label(function, "", location);
Bstatement* label_def = this->label_definition_statement(blabel);
@@ -2494,6 +2553,7 @@ Gcc_backend::function_defer_statement(Bf
tree try_catch =
build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body);
append_to_statement_list(try_catch, &stmt_list);
+ pop_cfun();
return this->make_statement(stmt_list);
}
@@ -2538,6 +2598,88 @@ Gcc_backend::function_set_body(Bfunction
return true;
}
+// Write the definitions for all TYPE_DECLS, CONSTANT_DECLS,
+// FUNCTION_DECLS, and VARIABLE_DECLS declared globally.
+
+void
+Gcc_backend::write_global_definitions(
+ const std::vector<Btype*>& type_decls,
+ const std::vector<Bexpression*>& constant_decls,
+ const std::vector<Bfunction*>& function_decls,
+ const std::vector<Bvariable*>& variable_decls)
+{
+ size_t count_definitions = type_decls.size() + constant_decls.size()
+ + function_decls.size() + variable_decls.size();
+
+ tree* defs = new tree[count_definitions];
+
+ // Convert all non-erroneous declarations into Gimple form.
+ size_t i = 0;
+ for (std::vector<Bvariable*>::const_iterator p = variable_decls.begin();
+ p != variable_decls.end();
+ ++p)
+ {
+ if ((*p)->get_tree() != error_mark_node)
+ {
+ defs[i] = (*p)->get_tree();
+ go_preserve_from_gc(defs[i]);
+ ++i;
+ }
+ }
+
+ for (std::vector<Btype*>::const_iterator p = type_decls.begin();
+ p != type_decls.end();
+ ++p)
+ {
+ tree type_tree = (*p)->get_tree();
+ if (type_tree != error_mark_node
+ && IS_TYPE_OR_DECL_P(type_tree))
+ {
+ defs[i] = TYPE_NAME(type_tree);
+ gcc_assert(defs[i] != NULL);
+ go_preserve_from_gc(defs[i]);
+ ++i;
+ }
+ }
+ for (std::vector<Bexpression*>::const_iterator p = constant_decls.begin();
+ p != constant_decls.end();
+ ++p)
+ {
+ if ((*p)->get_tree() != error_mark_node)
+ {
+ defs[i] = (*p)->get_tree();
+ go_preserve_from_gc(defs[i]);
+ ++i;
+ }
+ }
+ for (std::vector<Bfunction*>::const_iterator p = function_decls.begin();
+ p != function_decls.end();
+ ++p)
+ {
+ tree decl = (*p)->get_tree();
+ if (decl != error_mark_node)
+ {
+ go_preserve_from_gc(decl);
+ gimplify_function_tree(decl);
+ cgraph_finalize_function(decl, true);
+
+ defs[i] = decl;
+ ++i;
+ }
+ }
+
+ // Pass everything back to the middle-end.
+
+ wrapup_global_declarations(defs, i);
+
+ finalize_compilation_unit();
+
+ check_global_declarations(defs, i);
+ emit_debug_global_declarations(defs, i);
+
+ delete[] defs;
+}
+
// The single backend.
static Gcc_backend gcc_backend;