* go-gcc.cc: Include "go-c.h".
(class Bvariable): Define.
(Gcc_backend::init_statement): New function.
(Gcc_backend::global_variable): New function.
(Gcc_backend::global_variable_set_init): New function.
(Gcc_backend::local_variable): New function.
(Gcc_backend::parameter_variable): New function.
(tree_to_type, var_to_tree): New functions.
* Make-lang.in (go/go-gcc.o): Depend on $(GO_C_H).
* (go/gogo-tree.o): Depend on go/gofrontend/backend.h.
From-SVN: r172693
+2011-04-18 Ian Lance Taylor <iant@google.com>
+
+ * go-gcc.cc: Include "go-c.h".
+ (class Bvariable): Define.
+ (Gcc_backend::init_statement): New function.
+ (Gcc_backend::global_variable): New function.
+ (Gcc_backend::global_variable_set_init): New function.
+ (Gcc_backend::local_variable): New function.
+ (Gcc_backend::parameter_variable): New function.
+ (tree_to_type, var_to_tree): New functions.
+ * Make-lang.in (go/go-gcc.o): Depend on $(GO_C_H).
+ * (go/gogo-tree.o): Depend on go/gofrontend/backend.h.
+
2011-04-15 Ian Lance Taylor <iant@google.com>
* go-gcc.cc (Gcc_backend::compound_statement): New function.
GOINCLUDES = -I $(srcdir)/go -I $(srcdir)/go/gofrontend
go/go-gcc.o: go/go-gcc.cc $(GO_SYSTEM_H) $(TREE_H) tree-iterator.h \
- $(GIMPLE_H) $(GO_GOGO_H) go/gofrontend/backend.h
+ $(GIMPLE_H) $(GO_C_H) $(GO_GOGO_H) go/gofrontend/backend.h
$(CXX) -c $(GOINCLUDES) $(ALL_CPPFLAGS) $(ALL_CXXFLAGS) $< $(OUTPUT_OPTION)
go/%.o: go/gofrontend/%.cc
go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TOPLEV_H) \
$(TREE_H) $(GIMPLE_H) tree-iterator.h $(CGRAPH_H) langhooks.h \
convert.h output.h $(DIAGNOSTIC_H) $(GO_TYPES_H) \
- $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_RUNTIME_H) $(GO_GOGO_H)
+ $(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_RUNTIME_H) \
+ go/gofrontend/backend.h $(GO_GOGO_H)
go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) $(GO_C_H) \
go/gofrontend/go-dump.h $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) \
$(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_RUNTIME_H) \
}
#endif
+#include "go-c.h"
+
#include "gogo.h"
#include "backend.h"
{ }
};
+class Bvariable : public Gcc_tree
+{
+ public:
+ Bvariable(tree t)
+ : Gcc_tree(t)
+ { }
+};
+
class Blabel : public Gcc_tree
{
public:
Bstatement*
expression_statement(Bexpression*);
+ Bstatement*
+ init_statement(Bvariable* var, Bexpression* init);
+
Bstatement*
assignment_statement(Bexpression* lhs, Bexpression* rhs, source_location);
Bstatement*
statement_list(const std::vector<Bstatement*>&);
+ // Variables.
+
+ Bvariable*
+ error_variable()
+ { return new Bvariable(error_mark_node); }
+
+ Bvariable*
+ global_variable(const std::string& package_name,
+ const std::string& unique_prefix,
+ const std::string& name,
+ Btype* btype,
+ bool is_external,
+ bool is_hidden,
+ source_location location);
+
+ void
+ global_variable_set_init(Bvariable*, Bexpression*);
+
+ Bvariable*
+ local_variable(Bfunction*, const std::string& name, Btype* type,
+ source_location);
+
+ Bvariable*
+ parameter_variable(Bfunction*, const std::string& name, Btype* type,
+ source_location);
+
// Labels.
Blabel*
return this->make_statement(expr->get_tree());
}
+// Variable initialization.
+
+Bstatement*
+Gcc_backend::init_statement(Bvariable* var, Bexpression* init)
+{
+ tree var_tree = var->get_tree();
+ tree init_tree = init->get_tree();
+ if (var_tree == error_mark_node || init_tree == error_mark_node)
+ return this->error_statement();
+ gcc_assert(TREE_CODE(var_tree) == VAR_DECL);
+ DECL_INITIAL(var_tree) = init_tree;
+ return this->make_statement(build1_loc(DECL_SOURCE_LOCATION(var_tree),
+ DECL_EXPR, void_type_node, var_tree));
+}
+
// Assignment.
Bstatement*
return this->make_statement(stmt_list);
}
+// Make a global variable.
+
+Bvariable*
+Gcc_backend::global_variable(const std::string& package_name,
+ const std::string& unique_prefix,
+ const std::string& name,
+ Btype* btype,
+ bool is_external,
+ bool is_hidden,
+ source_location location)
+{
+ tree type_tree = btype->get_tree();
+ if (type_tree == error_mark_node)
+ return this->error_variable();
+
+ std::string var_name(package_name);
+ var_name.push_back('.');
+ var_name.append(name);
+ tree decl = build_decl(location, VAR_DECL,
+ get_identifier_from_string(var_name),
+ type_tree);
+ if (is_external)
+ DECL_EXTERNAL(decl) = 1;
+ else
+ TREE_STATIC(decl) = 1;
+ if (!is_hidden)
+ {
+ TREE_PUBLIC(decl) = 1;
+
+ std::string asm_name(unique_prefix);
+ asm_name.push_back('.');
+ asm_name.append(var_name);
+ SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name));
+ }
+ TREE_USED(decl) = 1;
+
+ go_preserve_from_gc(decl);
+
+ return new Bvariable(decl);
+}
+
+// Set the initial value of a global variable.
+
+void
+Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr)
+{
+ tree expr_tree = expr->get_tree();
+ if (expr_tree == error_mark_node)
+ return;
+ gcc_assert(TREE_CONSTANT(expr_tree));
+ tree var_decl = var->get_tree();
+ if (var_decl == error_mark_node)
+ return;
+ DECL_INITIAL(var_decl) = expr_tree;
+}
+
+// Make a local variable.
+
+Bvariable*
+Gcc_backend::local_variable(Bfunction* function, const std::string& name,
+ Btype* btype, source_location location)
+{
+ tree type_tree = btype->get_tree();
+ if (type_tree == error_mark_node)
+ return this->error_variable();
+ tree decl = build_decl(location, VAR_DECL,
+ get_identifier_from_string(name),
+ type_tree);
+ DECL_CONTEXT(decl) = function->get_tree();
+ TREE_USED(decl) = 1;
+ go_preserve_from_gc(decl);
+ return new Bvariable(decl);
+}
+
+// Make a function parameter variable.
+
+Bvariable*
+Gcc_backend::parameter_variable(Bfunction* function, const std::string& name,
+ Btype* btype, source_location location)
+{
+ tree type_tree = btype->get_tree();
+ if (type_tree == error_mark_node)
+ return this->error_variable();
+ tree decl = build_decl(location, PARM_DECL,
+ get_identifier_from_string(name),
+ type_tree);
+ DECL_CONTEXT(decl) = function->get_tree();
+ DECL_ARG_TYPE(decl) = type_tree;
+ TREE_USED(decl) = 1;
+ go_preserve_from_gc(decl);
+ return new Bvariable(decl);
+}
+
// Make a label.
Blabel*
// FIXME: Temporary functions while converting to the new backend
// interface.
+Btype*
+tree_to_type(tree t)
+{
+ return new Btype(t);
+}
+
Bexpression*
tree_to_expr(tree t)
{
{
return bs->get_tree();
}
+
+tree
+var_to_tree(Bvariable* bv)
+{
+ return bv->get_tree();
+}
// The backend representation of a function definition.
class Bfunction;
+// The backend representation of a variable.
+class Bvariable;
+
// The backend representation of a label.
class Blabel;
virtual Bstatement*
expression_statement(Bexpression*) = 0;
+ // Create a variable initialization statement. This initializes a
+ // local variable at the point in the program flow where it is
+ // declared.
+ virtual Bstatement*
+ init_statement(Bvariable* var, Bexpression* init) = 0;
+
// Create an assignment statement.
virtual Bstatement*
assignment_statement(Bexpression* lhs, Bexpression* rhs,
virtual Bstatement*
statement_list(const std::vector<Bstatement*>&) = 0;
+ // Variables.
+
+ // Create an error variable. This is used for cases which should
+ // not occur in a correct program, in order to keep the compilation
+ // going without crashing.
+ virtual Bvariable*
+ error_variable() = 0;
+
+ // Create a global variable. PACKAGE_NAME is the name of the
+ // package where the variable is defined. UNIQUE_PREFIX is the
+ // prefix for that package, from the -fgo-prefix option. NAME is
+ // the name of the variable. BTYPE is the type of the variable.
+ // IS_EXTERNAL is true if the variable is defined in some other
+ // package. IS_HIDDEN is true if the variable is not exported (name
+ // begins with a lower case letter). LOCATION is where the variable
+ // was defined.
+ virtual Bvariable*
+ global_variable(const std::string& package_name,
+ const std::string& unique_prefix,
+ const std::string& name,
+ Btype* btype,
+ bool is_external,
+ bool is_hidden,
+ source_location location) = 0;
+
+ // A global variable will 1) be initialized to zero, or 2) be
+ // initialized to a constant value, or 3) be initialized in the init
+ // function. In case 2, the frontend will call
+ // global_variable_set_init to set the initial value. If this is
+ // not called, the backend should initialize a global variable to 0.
+ // The init function may then assign a value to it.
+ virtual void
+ global_variable_set_init(Bvariable*, Bexpression*) = 0;
+
+ // Create a local variable. The frontend will create the local
+ // variables first, and then create the block which contains them.
+ // FUNCTION is the function in which the variable is defined. NAME
+ // is the name of the variable. TYPE is the type. LOCATION is
+ // where the variable is defined. For each local variable the
+ // frontend will call init_statement to set the initial value.
+ virtual Bvariable*
+ local_variable(Bfunction* function, const std::string& name, Btype* type,
+ source_location location) = 0;
+
+ // Create a function parameter. This is an incoming parameter, not
+ // a result parameter (result parameters are treated as local
+ // variables). The arguments are as for local_variable.
+ virtual Bvariable*
+ parameter_variable(Bfunction* function, const std::string& name,
+ Btype* type, source_location location) = 0;
+
// Labels.
// Create a new label. NAME will be empty if this is a label
// FIXME: Temporary helper functions while converting to new backend
// interface.
+extern Btype* tree_to_type(tree);
extern Bexpression* tree_to_expr(tree);
extern Bstatement* tree_to_stat(tree);
extern Bfunction* tree_to_function(tree);
extern tree expr_to_tree(Bexpression*);
extern tree stat_to_tree(Bstatement*);
+extern tree var_to_tree(Bvariable*);
#endif // !defined(GO_BACKEND_H)
tree
Var_expression::do_get_tree(Translate_context* context)
{
- return this->variable_->get_tree(context->gogo(), context->function());
+ Bvariable* bvar = this->variable_->get_backend_variable(context->gogo(),
+ context->function());
+ tree ret = var_to_tree(bvar);
+ if (ret == error_mark_node)
+ return error_mark_node;
+ bool is_in_heap;
+ if (this->variable_->is_variable())
+ is_in_heap = this->variable_->var_value()->is_in_heap();
+ else if (this->variable_->is_result_variable())
+ is_in_heap = this->variable_->result_var_value()->is_in_heap();
+ else
+ gcc_unreachable();
+ if (is_in_heap)
+ {
+ ret = build_fold_indirect_ref_loc(this->location(), ret);
+ TREE_THIS_NOTRAP(ret) = 1;
+ }
+ return ret;
}
// Make a reference to a variable in an expression.
#include "expressions.h"
#include "statements.h"
#include "runtime.h"
+#include "backend.h"
#include "gogo.h"
// Whether we have seen any errors.
constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL);
tree field = TYPE_FIELDS(root_type);
elt->index = field;
- tree decl = (*p)->get_tree(this, NULL);
+ Bvariable* bvar = (*p)->get_backend_variable(this, NULL);
+ tree decl = var_to_tree(bvar);
gcc_assert(TREE_CODE(decl) == VAR_DECL);
elt->value = build_fold_addr_expr(decl);
}
}
- vec[i] = no->get_tree(this, NULL);
-
- if (vec[i] == error_mark_node)
+ if (!no->is_variable())
{
- gcc_assert(saw_errors());
- --i;
- --count;
- continue;
+ vec[i] = no->get_tree(this, NULL);
+ if (vec[i] == error_mark_node)
+ {
+ gcc_assert(saw_errors());
+ --i;
+ --count;
+ continue;
+ }
}
-
- // If a variable is initialized to a non-constant value, do the
- // initialization in an initialization function.
- if (TREE_CODE(vec[i]) == VAR_DECL)
+ else
{
- gcc_assert(no->is_variable());
+ Bvariable* var = no->get_backend_variable(this, NULL);
+ vec[i] = var_to_tree(var);
+ if (vec[i] == error_mark_node)
+ {
+ gcc_assert(saw_errors());
+ --i;
+ --count;
+ continue;
+ }
- // Check for a sink variable, which may be used to run
- // an initializer purely for its side effects.
+ // Check for a sink variable, which may be used to run an
+ // initializer purely for its side effects.
bool is_sink = no->name()[0] == '_' && no->name()[1] == '.';
tree var_init_tree = NULL_TREE;
else if (init == NULL_TREE)
;
else if (TREE_CONSTANT(init))
- DECL_INITIAL(vec[i]) = init;
+ this->backend()->global_variable_set_init(var,
+ tree_to_expr(init));
else if (is_sink)
var_init_tree = init;
else
tree
Named_object::get_id(Gogo* gogo)
{
+ gcc_assert(!this->is_variable() && !this->is_result_variable());
std::string decl_name;
if (this->is_function_declaration()
&& !this->func_declaration_value()->asm_name().empty())
decl_name = this->func_declaration_value()->asm_name();
- else if ((this->is_variable() && !this->var_value()->is_global())
- || (this->is_type()
- && this->type_value()->location() == BUILTINS_LOCATION))
+ else if (this->is_type()
+ && this->type_value()->location() == BUILTINS_LOCATION)
{
- // We don't need the package name for local variables or builtin
- // types.
+ // We don't need the package name for builtin types.
decl_name = Gogo::unpack_hidden_name(this->name_);
}
else
Named_object::get_tree(Gogo* gogo, Named_object* function)
{
if (this->tree_ != NULL_TREE)
- {
- // If this is a variable whose address is taken, we must rebuild
- // the INDIRECT_REF each time to avoid invalid sharing.
- tree ret = this->tree_;
- if (((this->classification_ == NAMED_OBJECT_VAR
- && this->var_value()->is_in_heap())
- || (this->classification_ == NAMED_OBJECT_RESULT_VAR
- && this->result_var_value()->is_in_heap()))
- && ret != error_mark_node)
- {
- gcc_assert(TREE_CODE(ret) == INDIRECT_REF);
- ret = build_fold_indirect_ref(TREE_OPERAND(ret, 0));
- TREE_THIS_NOTRAP(ret) = 1;
- }
- return ret;
- }
+ return this->tree_;
tree name;
if (this->classification_ == NAMED_OBJECT_TYPE)
return error_mark_node;
case NAMED_OBJECT_VAR:
- {
- Variable* var = this->u_.var_value;
- Type* type = var->type();
- if (type->is_error_type()
- || (type->is_undefined()
- && (!var->is_global() || this->package() == NULL)))
- {
- // Force the error for an undefined type, just in case.
- type->base();
- decl = error_mark_node;
- }
- else
- {
- tree var_type = type->get_tree(gogo);
- bool is_parameter = var->is_parameter();
- if (var->is_receiver() && type->points_to() == NULL)
- is_parameter = false;
- if (var->is_in_heap())
- {
- is_parameter = false;
- var_type = build_pointer_type(var_type);
- }
- decl = build_decl(var->location(),
- is_parameter ? PARM_DECL : VAR_DECL,
- name, var_type);
- if (!var->is_global())
- {
- tree fnid = function->get_id(gogo);
- tree fndecl = function->func_value()->get_or_make_decl(gogo,
- function,
- fnid);
- DECL_CONTEXT(decl) = fndecl;
- }
- if (is_parameter)
- DECL_ARG_TYPE(decl) = TREE_TYPE(decl);
-
- if (var->is_global())
- {
- const Package* package = this->package();
- if (package == NULL)
- TREE_STATIC(decl) = 1;
- else
- DECL_EXTERNAL(decl) = 1;
- if (!Gogo::is_hidden_name(this->name_))
- {
- TREE_PUBLIC(decl) = 1;
- std::string asm_name = (package == NULL
- ? gogo->unique_prefix()
- : package->unique_prefix());
- asm_name.append(1, '.');
- asm_name.append(IDENTIFIER_POINTER(name),
- IDENTIFIER_LENGTH(name));
- tree asm_id = get_identifier_from_string(asm_name);
- SET_DECL_ASSEMBLER_NAME(decl, asm_id);
- }
- }
-
- // FIXME: We should only set this for variables which are
- // actually used somewhere.
- TREE_USED(decl) = 1;
- }
- }
- break;
-
case NAMED_OBJECT_RESULT_VAR:
- {
- Result_variable* result = this->u_.result_var_value;
- Type* type = result->type();
- if (type->is_error())
- decl = error_mark_node;
- else
- {
- gcc_assert(result->function() == function->func_value());
- source_location loc = function->location();
- tree result_type = type->get_tree(gogo);
- tree init;
- if (!result->is_in_heap())
- init = type->get_init_tree(gogo, false);
- else
- {
- tree space = gogo->allocate_memory(type,
- TYPE_SIZE_UNIT(result_type),
- loc);
- result_type = build_pointer_type(result_type);
- tree subinit = type->get_init_tree(gogo, true);
- if (subinit == NULL_TREE)
- init = fold_convert_loc(loc, result_type, space);
- else
- {
- space = save_expr(space);
- space = fold_convert_loc(loc, result_type, space);
- tree spaceref = build_fold_indirect_ref_loc(loc, space);
- TREE_THIS_NOTRAP(spaceref) = 1;
- tree set = fold_build2_loc(loc, MODIFY_EXPR, void_type_node,
- spaceref, subinit);
- init = fold_build2_loc(loc, COMPOUND_EXPR, TREE_TYPE(space),
- set, space);
- }
- }
- decl = build_decl(loc, VAR_DECL, name, result_type);
- tree fnid = function->get_id(gogo);
- tree fndecl = function->func_value()->get_or_make_decl(gogo,
- function,
- fnid);
- DECL_CONTEXT(decl) = fndecl;
- DECL_INITIAL(decl) = init;
- TREE_USED(decl) = 1;
- }
- }
- break;
-
case NAMED_OBJECT_SINK:
gcc_unreachable();
tree ret = decl;
- // If this is a local variable whose address is taken, then we
- // actually store it in the heap. For uses of the variable we need
- // to return a reference to that heap location.
- if (((this->classification_ == NAMED_OBJECT_VAR
- && this->var_value()->is_in_heap())
- || (this->classification_ == NAMED_OBJECT_RESULT_VAR
- && this->result_var_value()->is_in_heap()))
- && ret != error_mark_node)
- {
- gcc_assert(POINTER_TYPE_P(TREE_TYPE(ret)));
- ret = build_fold_indirect_ref(ret);
- TREE_THIS_NOTRAP(ret) = 1;
- }
-
this->tree_ = ret;
if (ret != error_mark_node)
if (this->init_ == NULL)
{
gcc_assert(!this->is_parameter_);
- return this->type_->get_init_tree(gogo, this->is_global_);
+ return this->type_->get_init_tree(gogo,
+ (this->is_global_
+ || this->is_in_heap()));
}
else
{
{
push_struct_function(decl);
- tree closure_decl = this->closure_var_->get_tree(gogo, no);
+ Bvariable* bvar = this->closure_var_->get_backend_variable(gogo,
+ no);
+ tree closure_decl = var_to_tree(bvar);
if (closure_decl == error_mark_node)
this->fndecl_ = error_mark_node;
else
{
if (var_decl == error_mark_node)
return error_mark_node;
- // If the function takes the address of a receiver which is passed
- // by value, then we will have an INDIRECT_REF here. We need to get
- // the real variable.
+ gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+ tree val_type = TREE_TYPE(var_decl);
bool is_in_heap = no->var_value()->is_in_heap();
- tree val_type;
- if (TREE_CODE(var_decl) != INDIRECT_REF)
- {
- gcc_assert(!is_in_heap);
- val_type = TREE_TYPE(var_decl);
- }
- else
+ if (is_in_heap)
{
- gcc_assert(is_in_heap);
- var_decl = TREE_OPERAND(var_decl, 0);
- if (var_decl == error_mark_node)
- return error_mark_node;
- gcc_assert(POINTER_TYPE_P(TREE_TYPE(var_decl)));
- val_type = TREE_TYPE(TREE_TYPE(var_decl));
+ gcc_assert(POINTER_TYPE_P(val_type));
+ val_type = TREE_TYPE(val_type);
}
- gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+
source_location loc = DECL_SOURCE_LOCATION(var_decl);
std::string name = IDENTIFIER_POINTER(DECL_NAME(var_decl));
name += ".pointer";
// indirection.
tree
-Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree ref)
+Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl)
{
- if (ref == error_mark_node)
- return error_mark_node;
-
- gcc_assert(TREE_CODE(ref) == INDIRECT_REF);
-
- tree var_decl = TREE_OPERAND(ref, 0);
if (var_decl == error_mark_node)
return error_mark_node;
gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
{
if ((*p)->is_variable() && (*p)->var_value()->is_parameter())
{
- *pp = (*p)->get_tree(gogo, named_function);
+ Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
+ *pp = var_to_tree(bvar);
// We always pass the receiver to a method as a pointer. If
// the receiver is declared as a non-pointer type, then we
{
tree parm_decl = this->make_receiver_parm_decl(gogo, *p, *pp);
tree var = *pp;
- if (TREE_CODE(var) == INDIRECT_REF)
- var = TREE_OPERAND(var, 0);
if (var != error_mark_node)
{
gcc_assert(TREE_CODE(var) == VAR_DECL);
// If we take the address of a parameter, then we need
// to copy it into the heap.
tree parm_decl = this->copy_parm_to_heap(gogo, *p, *pp);
- if (*pp != error_mark_node)
+ tree var = *pp;
+ if (var != error_mark_node)
{
- gcc_assert(TREE_CODE(*pp) == INDIRECT_REF);
- tree var_decl = TREE_OPERAND(*pp, 0);
- if (var_decl != error_mark_node)
- {
- gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
- DECL_CHAIN(var_decl) = declare_vars;
- declare_vars = var_decl;
- }
+ gcc_assert(TREE_CODE(var) == VAR_DECL);
+ DECL_CHAIN(var) = declare_vars;
+ declare_vars = var;
}
*pp = parm_decl;
}
}
else if ((*p)->is_result_variable())
{
- tree var_decl = (*p)->get_tree(gogo, named_function);
- if (var_decl != error_mark_node
- && (*p)->result_var_value()->is_in_heap())
+ Bvariable* bvar = (*p)->get_backend_variable(gogo, named_function);
+ tree var_decl = var_to_tree(bvar);
+
+ Type* type = (*p)->result_var_value()->type();
+ tree init;
+ if (!(*p)->result_var_value()->is_in_heap())
+ init = type->get_init_tree(gogo, false);
+ else
{
- gcc_assert(TREE_CODE(var_decl) == INDIRECT_REF);
- var_decl = TREE_OPERAND(var_decl, 0);
+ source_location loc = (*p)->location();
+ tree type_tree = type->get_tree(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);
+ }
}
+
if (var_decl != error_mark_node)
{
gcc_assert(TREE_CODE(var_decl) == VAR_DECL);
+ DECL_INITIAL(var_decl) = init;
DECL_CHAIN(var_decl) = declare_vars;
declare_vars = var_decl;
}
tree retval;
if (results->size() == 1)
- return this->results_->front()->get_tree(gogo, named_function);
+ {
+ Bvariable* bvar =
+ this->results_->front()->get_backend_variable(gogo,
+ named_function);
+ tree ret = var_to_tree(bvar);
+ if (this->results_->front()->result_var_value()->is_in_heap())
+ ret = build_fold_indirect_ref_loc(location, ret);
+ return ret;
+ }
else
{
tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_));
++pr, ++index, field = DECL_CHAIN(field))
{
gcc_assert(field != NULL);
- tree val;
- val = (*this->results_)[index]->get_tree(gogo, named_function);
+ Named_object* no = (*this->results_)[index];
+ Bvariable* bvar = no->get_backend_variable(gogo, named_function);
+ tree val = var_to_tree(bvar);
+ if (no->result_var_value()->is_in_heap())
+ val = build_fold_indirect_ref_loc(location, val);
tree set = fold_build2_loc(location, MODIFY_EXPR, void_type_node,
build3(COMPONENT_REF, TREE_TYPE(field),
retval, field, NULL_TREE),
pv != this->bindings_->end_definitions();
++pv)
{
- if ((!(*pv)->is_variable() || !(*pv)->var_value()->is_parameter())
- && !(*pv)->is_result_variable()
- && !(*pv)->is_const())
+ if ((*pv)->is_variable() && !(*pv)->var_value()->is_parameter())
{
- tree var = (*pv)->get_tree(gogo, context->function());
- if (var != error_mark_node && TREE_TYPE(var) != error_mark_node)
- {
- if ((*pv)->is_variable() && (*pv)->var_value()->is_in_heap())
- {
- gcc_assert(TREE_CODE(var) == INDIRECT_REF);
- var = TREE_OPERAND(var, 0);
- gcc_assert(TREE_CODE(var) == VAR_DECL);
- }
- *pp = var;
- pp = &DECL_CHAIN(*pp);
- }
+ Bvariable* var = (*pv)->get_backend_variable(gogo,
+ context->function());
+ *pp = var_to_tree(var);
+ if (*pp != error_mark_node)
+ pp = &DECL_CHAIN(*pp);
}
}
*pp = NULL_TREE;
- Translate_context subcontext(context->gogo(), context->function(),
- this, block);
+ Translate_context subcontext(gogo, context->function(), this, block);
tree statements = NULL_TREE;
++result_counter;
name = gogo->pack_hidden_name(buf, false);
}
- Result_variable* result = new Result_variable(p->type(), this, index);
+ Result_variable* result = new Result_variable(p->type(), this, index,
+ p->location());
Named_object* no = block->bindings()->add_result_variable(name, result);
if (no->is_result_variable())
this->results_->push_back(no);
bool is_parameter, bool is_receiver,
source_location location)
: type_(type), init_(init), preinit_(NULL), location_(location),
- is_global_(is_global), is_parameter_(is_parameter),
+ backend_(NULL), is_global_(is_global), is_parameter_(is_parameter),
is_receiver_(is_receiver), is_varargs_parameter_(false),
is_address_taken_(false), seen_(false), init_is_lowered_(false),
type_from_init_tuple_(false), type_from_range_index_(false),
imp->require_c_string(";\n");
}
+// Convert a variable to the backend representation.
+
+Bvariable*
+Variable::get_backend_variable(Gogo* gogo, Named_object* function,
+ const Package* package, const std::string& name)
+{
+ if (this->backend_ == NULL)
+ {
+ Backend* backend = gogo->backend();
+ Type* type = this->type_;
+ if (type->is_error_type()
+ || (type->is_undefined()
+ && (!this->is_global_ || package == NULL)))
+ this->backend_ = backend->error_variable();
+ else
+ {
+ bool is_parameter = this->is_parameter_;
+ if (this->is_receiver_ && type->points_to() == NULL)
+ is_parameter = false;
+ if (this->is_in_heap())
+ {
+ is_parameter = false;
+ type = Type::make_pointer_type(type);
+ }
+
+ std::string n = Gogo::unpack_hidden_name(name);
+ Btype* btype = tree_to_type(type->get_tree(gogo));
+
+ Bvariable* bvar;
+ if (this->is_global_)
+ bvar = backend->global_variable((package == NULL
+ ? gogo->package_name()
+ : package->name()),
+ (package == NULL
+ ? gogo->unique_prefix()
+ : package->unique_prefix()),
+ n,
+ btype,
+ package != NULL,
+ Gogo::is_hidden_name(name),
+ this->location_);
+ else
+ {
+ tree fndecl = function->func_value()->get_decl();
+ Bfunction* bfunction = tree_to_function(fndecl);
+ if (is_parameter)
+ bvar = backend->parameter_variable(bfunction, n, btype,
+ this->location_);
+ else
+ bvar = backend->local_variable(bfunction, n, btype,
+ this->location_);
+ }
+ this->backend_ = bvar;
+ }
+ }
+ return this->backend_;
+}
+
+// Class Result_variable.
+
+// Convert a result variable to the backend representation.
+
+Bvariable*
+Result_variable::get_backend_variable(Gogo* gogo, Named_object* function,
+ const std::string& name)
+{
+ if (this->backend_ == NULL)
+ {
+ Backend* backend = gogo->backend();
+ Type* type = this->type_;
+ if (type->is_error())
+ this->backend_ = backend->error_variable();
+ else
+ {
+ if (this->is_in_heap())
+ type = Type::make_pointer_type(type);
+ Btype* btype = tree_to_type(type->get_tree(gogo));
+ tree fndecl = function->func_value()->get_decl();
+ Bfunction* bfunction = tree_to_function(fndecl);
+ std::string n = Gogo::unpack_hidden_name(name);
+ this->backend_ = backend->local_variable(bfunction, n, btype,
+ this->location_);
+ }
+ }
+ return this->backend_;
+}
+
// Class Named_constant.
// Traverse the initializer expression.
return this->var_value()->location();
case NAMED_OBJECT_RESULT_VAR:
- return this->result_var_value()->function()->location();
+ return this->result_var_value()->location();
case NAMED_OBJECT_SINK:
gcc_unreachable();
}
}
+// Convert a variable to the backend representation.
+
+Bvariable*
+Named_object::get_backend_variable(Gogo* gogo, Named_object* function)
+{
+ if (this->classification_ == NAMED_OBJECT_VAR)
+ return this->var_value()->get_backend_variable(gogo, function,
+ this->package_, this->name_);
+ else if (this->classification_ == NAMED_OBJECT_RESULT_VAR)
+ return this->result_var_value()->get_backend_variable(gogo, function,
+ this->name_);
+ else
+ gcc_unreachable();
+}
+
// Class Bindings.
Bindings::Bindings(Bindings* enclosing)
class Import;
class Bexpression;
class Bstatement;
+class Bvariable;
class Blabel;
// This file declares the basic classes used to hold the internal
set_address_taken()
{ this->is_address_taken_ = true; }
+ // Get the backend representation of the variable.
+ Bvariable*
+ get_backend_variable(Gogo*, Named_object*, const Package*,
+ const std::string&);
+
// Get the initial value of the variable as a tree. This may only
// be called if has_pre_init() returns false.
tree
Block* preinit_;
// Location of variable definition.
source_location location_;
+ // Backend representation.
+ Bvariable* backend_;
// Whether this is a global variable.
bool is_global_ : 1;
// Whether this is a function parameter.
class Result_variable
{
public:
- Result_variable(Type* type, Function* function, int index)
- : type_(type), function_(function), index_(index),
- is_address_taken_(false)
+ Result_variable(Type* type, Function* function, int index,
+ source_location location)
+ : type_(type), function_(function), index_(index), location_(location),
+ backend_(NULL), is_address_taken_(false)
{ }
// Get the type of the result variable.
index() const
{ return this->index_; }
+ // The location of the variable definition.
+ source_location
+ location() const
+ { return this->location_; }
+
// Whether this variable's address is taken.
bool
is_address_taken() const
set_function(Function* function)
{ this->function_ = function; }
+ // Get the backend representation of the variable.
+ Bvariable*
+ get_backend_variable(Gogo*, Named_object*, const std::string&);
+
private:
// Type of result variable.
Type* type_;
Function* function_;
// Index in list of results.
int index_;
+ // Where the result variable is defined.
+ source_location location_;
+ // Backend representation.
+ Bvariable* backend_;
// Whether something takes the address of this variable.
bool is_address_taken_;
};
source_location
location() const;
+ // Convert a variable to the backend representation.
+ Bvariable*
+ get_backend_variable(Gogo*, Named_object* function);
+
// Return a tree for the external identifier for this object.
tree
get_id(Gogo*);
tree
Variable_declaration_statement::do_get_tree(Translate_context* context)
{
- tree val = this->var_->get_tree(context->gogo(), context->function());
- if (val == error_mark_node || TREE_TYPE(val) == error_mark_node)
- return error_mark_node;
- Variable* variable = this->var_->var_value();
-
- tree init = variable->get_init_tree(context->gogo(), context->function());
- if (init == error_mark_node)
- return error_mark_node;
-
- // If this variable lives on the heap, we need to allocate it now.
- if (!variable->is_in_heap())
+ Variable* var = this->var_->var_value();
+ Bvariable* bvar = this->var_->get_backend_variable(context->gogo(),
+ context->function());
+ tree init = var->get_init_tree(context->gogo(), context->function());
+ Bexpression* binit = init == NULL_TREE ? NULL : tree_to_expr(init);
+ Bstatement* ret;
+ if (!var->is_in_heap())
{
- DECL_INITIAL(val) = init;
- return this->build_stmt_1(DECL_EXPR, val);
+ gcc_assert(binit != NULL);
+ ret = context->backend()->init_statement(bvar, binit);
}
else
{
- gcc_assert(TREE_CODE(val) == INDIRECT_REF);
- tree decl = TREE_OPERAND(val, 0);
- gcc_assert(TREE_CODE(decl) == VAR_DECL);
- tree type = TREE_TYPE(decl);
- gcc_assert(POINTER_TYPE_P(type));
- tree size = TYPE_SIZE_UNIT(TREE_TYPE(type));
- tree space = context->gogo()->allocate_memory(variable->type(), size,
- this->location());
- space = fold_convert(TREE_TYPE(decl), space);
- DECL_INITIAL(decl) = space;
- return build2(COMPOUND_EXPR, void_type_node,
- this->build_stmt_1(DECL_EXPR, decl),
- build2(MODIFY_EXPR, void_type_node, val, init));
+ // Something takes the address of this variable, so the value is
+ // stored in the heap. Initialize it to newly allocated memory
+ // space, and assign the initial value to the new space.
+ source_location loc = this->location();
+ tree decl = var_to_tree(bvar);
+ tree decl_type = TREE_TYPE(decl);
+ gcc_assert(POINTER_TYPE_P(decl_type));
+ tree size = TYPE_SIZE_UNIT(TREE_TYPE(decl_type));
+ tree space = context->gogo()->allocate_memory(var->type(), size, loc);
+ if (binit != NULL)
+ space = save_expr(space);
+ space = fold_convert_loc(loc, decl_type, space);
+ Bstatement* s1 = context->backend()->init_statement(bvar,
+ tree_to_expr(space));
+ if (binit == NULL)
+ ret = s1;
+ else
+ {
+ tree indir = build_fold_indirect_ref_loc(loc, space);
+ Bexpression* bindir = tree_to_expr(indir);
+ Bstatement* s2 = context->backend()->assignment_statement(bindir,
+ binit,
+ loc);
+ ret = context->backend()->compound_statement(s1, s2);
+ }
}
+ return stat_to_tree(ret);
}
// Make a variable declaration.
tree
Return_statement::do_get_tree(Translate_context* context)
{
+ source_location loc = this->location();
+
Function* function = context->function()->func_value();
tree fndecl = function->get_decl();
p != results->end();
p++)
{
- tree rv = (*p)->get_tree(context->gogo(), context->function());
- retvals.push_back(tree_to_expr(rv));
+ Expression* vr = Expression::make_var_reference(*p, loc);
+ retvals.push_back(tree_to_expr(vr->get_tree(context)));
}
}
Bstatement* ret;
ret = context->backend()->return_statement(tree_to_function(fndecl),
- retvals, this->location());
+ retvals, loc);
return stat_to_tree(ret);
}