Commit 036165d8 by Chris Manghane Committed by Ian Lance Taylor

compiler: Use backend interface for defining global declarations.

	* go-gcc.cc: Include "cgraph.h" and "gimplify.h".
	(Gcc_backend::return_statement): Push and pop function.
	(Gcc_backend::label): Likewise.
	(Gcc_backend::function_defer_statement): Likewise.
	(Gcc_backend::switch_statement): Add function parameter.
	(Gcc_backend::block): Don't permit function to be NULL.
	(Gcc_backend::temporary_variable): Change go_assert to
	gcc_assert.
	(Gcc_backend::gc_root_variable): New function.
	(Gcc_backend::write_global_definitions): New function.

From-SVN: r209819
parent 10695c6a
2014-04-25 Chris Manghane <cmang@google.com>
* go-gcc.cc: Include "cgraph.h" and "gimplify.h".
(Gcc_backend::return_statement): Push and pop function.
(Gcc_backend::label): Likewise.
(Gcc_backend::function_defer_statement): Likewise.
(Gcc_backend::switch_statement): Add function parameter.
(Gcc_backend::block): Don't permit function to be NULL.
(Gcc_backend::temporary_variable): Change go_assert to
gcc_assert.
(Gcc_backend::gc_root_variable): New function.
(Gcc_backend::write_global_definitions): New function.
2014-04-22 Chris Manghane <cmang@google.com> 2014-04-22 Chris Manghane <cmang@google.com>
* go-gcc.cc (Gcc_backend::temporary_variable): Push cfun around * go-gcc.cc (Gcc_backend::temporary_variable): Push cfun around
......
...@@ -29,9 +29,11 @@ ...@@ -29,9 +29,11 @@
#include "stor-layout.h" #include "stor-layout.h"
#include "varasm.h" #include "varasm.h"
#include "tree-iterator.h" #include "tree-iterator.h"
#include "cgraph.h"
#include "convert.h" #include "convert.h"
#include "basic-block.h" #include "basic-block.h"
#include "gimple-expr.h" #include "gimple-expr.h"
#include "gimplify.h"
#include "toplev.h" #include "toplev.h"
#include "output.h" #include "output.h"
#include "real.h" #include "real.h"
...@@ -317,7 +319,7 @@ class Gcc_backend : public Backend ...@@ -317,7 +319,7 @@ class Gcc_backend : public Backend
Location); Location);
Bstatement* Bstatement*
switch_statement(Bexpression* value, switch_statement(Bfunction* function, Bexpression* value,
const std::vector<std::vector<Bexpression*> >& cases, const std::vector<std::vector<Bexpression*> >& cases,
const std::vector<Bstatement*>& statements, const std::vector<Bstatement*>& statements,
Location); Location);
...@@ -376,6 +378,9 @@ class Gcc_backend : public Backend ...@@ -376,6 +378,9 @@ class Gcc_backend : public Backend
Location, Bstatement**); Location, Bstatement**);
Bvariable* Bvariable*
gc_root_variable(Btype*, Bexpression*);
Bvariable*
immutable_struct(const std::string&, bool, bool, Btype*, Location); immutable_struct(const std::string&, bool, bool, Btype*, Location);
void void
...@@ -420,6 +425,12 @@ class Gcc_backend : public Backend ...@@ -420,6 +425,12 @@ class Gcc_backend : public Backend
bool bool
function_set_body(Bfunction* function, Bstatement* code_stmt); 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: private:
// Make a Bexpression from a tree. // Make a Bexpression from a tree.
Bexpression* Bexpression*
...@@ -1709,6 +1720,7 @@ Gcc_backend::return_statement(Bfunction* bfunction, ...@@ -1709,6 +1720,7 @@ Gcc_backend::return_statement(Bfunction* bfunction,
tree result = DECL_RESULT(fntree); tree result = DECL_RESULT(fntree);
if (result == error_mark_node) if (result == error_mark_node)
return this->error_statement(); return this->error_statement();
tree ret; tree ret;
if (vals.empty()) if (vals.empty())
ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node, ret = fold_build1_loc(location.gcc_location(), RETURN_EXPR, void_type_node,
...@@ -1732,7 +1744,14 @@ Gcc_backend::return_statement(Bfunction* bfunction, ...@@ -1732,7 +1744,14 @@ Gcc_backend::return_statement(Bfunction* bfunction,
// statement. // statement.
tree stmt_list = NULL_TREE; tree stmt_list = NULL_TREE;
tree rettype = TREE_TYPE(result); 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"); tree rettmp = create_tmp_var(rettype, "RESULT");
pop_cfun();
tree field = TYPE_FIELDS(rettype); tree field = TYPE_FIELDS(rettype);
for (std::vector<Bexpression*>::const_iterator p = vals.begin(); for (std::vector<Bexpression*>::const_iterator p = vals.begin();
p != vals.end(); p != vals.end();
...@@ -1818,6 +1837,7 @@ Gcc_backend::if_statement(Bexpression* condition, Bblock* then_block, ...@@ -1818,6 +1837,7 @@ Gcc_backend::if_statement(Bexpression* condition, Bblock* then_block,
Bstatement* Bstatement*
Gcc_backend::switch_statement( Gcc_backend::switch_statement(
Bfunction* function,
Bexpression* value, Bexpression* value,
const std::vector<std::vector<Bexpression*> >& cases, const std::vector<std::vector<Bexpression*> >& cases,
const std::vector<Bstatement*>& statements, const std::vector<Bstatement*>& statements,
...@@ -1825,6 +1845,12 @@ Gcc_backend::switch_statement( ...@@ -1825,6 +1845,12 @@ Gcc_backend::switch_statement(
{ {
gcc_assert(cases.size() == statements.size()); 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; tree stmt_list = NULL_TREE;
std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin(); std::vector<std::vector<Bexpression*> >::const_iterator pc = cases.begin();
for (std::vector<Bstatement*>::const_iterator ps = statements.begin(); for (std::vector<Bstatement*>::const_iterator ps = statements.begin();
...@@ -1864,6 +1890,7 @@ Gcc_backend::switch_statement( ...@@ -1864,6 +1890,7 @@ Gcc_backend::switch_statement(
append_to_statement_list(t, &stmt_list); append_to_statement_list(t, &stmt_list);
} }
} }
pop_cfun();
tree tv = value->get_tree(); tree tv = value->get_tree();
if (tv == error_mark_node) if (tv == error_mark_node)
...@@ -1922,13 +1949,7 @@ Gcc_backend::block(Bfunction* function, Bblock* enclosing, ...@@ -1922,13 +1949,7 @@ Gcc_backend::block(Bfunction* function, Bblock* enclosing,
tree block_tree = make_node(BLOCK); tree block_tree = make_node(BLOCK);
if (enclosing == NULL) if (enclosing == NULL)
{ {
// FIXME: Permitting FUNCTION to be NULL is a temporary measure tree fndecl = function->get_tree();
// until we have a proper representation of the init function.
tree fndecl;
if (function == NULL)
fndecl = current_function_decl;
else
fndecl = function->get_tree();
gcc_assert(fndecl != NULL_TREE); gcc_assert(fndecl != NULL_TREE);
// We may have already created a block for local variables when // We may have already created a block for local variables when
...@@ -1982,7 +2003,6 @@ Gcc_backend::block(Bfunction* function, Bblock* enclosing, ...@@ -1982,7 +2003,6 @@ Gcc_backend::block(Bfunction* function, Bblock* enclosing,
void_type_node, BLOCK_VARS(block_tree), void_type_node, BLOCK_VARS(block_tree),
NULL_TREE, block_tree); NULL_TREE, block_tree);
TREE_SIDE_EFFECTS(bind_tree) = 1; TREE_SIDE_EFFECTS(bind_tree) = 1;
return new Bblock(bind_tree); return new Bblock(bind_tree);
} }
...@@ -2214,7 +2234,7 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, ...@@ -2214,7 +2234,7 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
return this->error_variable(); return this->error_variable();
} }
go_assert(function != NULL); gcc_assert(function != NULL);
tree decl = function->get_tree(); tree decl = function->get_tree();
tree var; tree var;
...@@ -2263,6 +2283,28 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock, ...@@ -2263,6 +2283,28 @@ Gcc_backend::temporary_variable(Bfunction* function, Bblock* bblock,
return new Bvariable(var); 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. // Create a named immutable initialized data structure.
Bvariable* Bvariable*
...@@ -2277,9 +2319,9 @@ Gcc_backend::immutable_struct(const std::string& name, bool is_hidden, ...@@ -2277,9 +2319,9 @@ Gcc_backend::immutable_struct(const std::string& name, bool is_hidden,
get_identifier_from_string(name), get_identifier_from_string(name),
build_qualified_type(type_tree, TYPE_QUAL_CONST)); build_qualified_type(type_tree, TYPE_QUAL_CONST));
TREE_STATIC(decl) = 1; TREE_STATIC(decl) = 1;
TREE_USED(decl) = 1;
TREE_READONLY(decl) = 1; TREE_READONLY(decl) = 1;
TREE_CONSTANT(decl) = 1; TREE_CONSTANT(decl) = 1;
TREE_USED(decl) = 1;
DECL_ARTIFICIAL(decl) = 1; DECL_ARTIFICIAL(decl) = 1;
if (!is_hidden) if (!is_hidden)
TREE_PUBLIC(decl) = 1; TREE_PUBLIC(decl) = 1;
...@@ -2369,7 +2411,17 @@ Gcc_backend::label(Bfunction* function, const std::string& name, ...@@ -2369,7 +2411,17 @@ Gcc_backend::label(Bfunction* function, const std::string& name,
{ {
tree decl; tree decl;
if (name.empty()) 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 else
{ {
tree id = get_identifier_from_string(name); tree id = get_identifier_from_string(name);
...@@ -2477,11 +2529,18 @@ Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer, ...@@ -2477,11 +2529,18 @@ Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer,
{ {
tree undefer_tree = undefer->get_tree(); tree undefer_tree = undefer->get_tree();
tree defer_tree = defer->get_tree(); tree defer_tree = defer->get_tree();
tree fntree = function->get_tree();
if (undefer_tree == error_mark_node if (undefer_tree == error_mark_node
|| defer_tree == error_mark_node) || defer_tree == error_mark_node
|| fntree == error_mark_node)
return this->error_statement(); 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; tree stmt_list = NULL;
Blabel* blabel = this->label(function, "", location); Blabel* blabel = this->label(function, "", location);
Bstatement* label_def = this->label_definition_statement(blabel); Bstatement* label_def = this->label_definition_statement(blabel);
...@@ -2494,6 +2553,7 @@ Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer, ...@@ -2494,6 +2553,7 @@ Gcc_backend::function_defer_statement(Bfunction* function, Bexpression* undefer,
tree try_catch = tree try_catch =
build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body); build2(TRY_CATCH_EXPR, void_type_node, undefer_tree, catch_body);
append_to_statement_list(try_catch, &stmt_list); append_to_statement_list(try_catch, &stmt_list);
pop_cfun();
return this->make_statement(stmt_list); return this->make_statement(stmt_list);
} }
...@@ -2538,6 +2598,88 @@ Gcc_backend::function_set_body(Bfunction* function, Bstatement* code_stmt) ...@@ -2538,6 +2598,88 @@ Gcc_backend::function_set_body(Bfunction* function, Bstatement* code_stmt)
return true; 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. // The single backend.
static Gcc_backend gcc_backend; static Gcc_backend gcc_backend;
......
...@@ -406,9 +406,9 @@ class Backend ...@@ -406,9 +406,9 @@ class Backend
// integers, then STATEMENTS[i] is executed. STATEMENTS[i] will // integers, then STATEMENTS[i] is executed. STATEMENTS[i] will
// either end with a goto statement or will fall through into // either end with a goto statement or will fall through into
// STATEMENTS[i + 1]. CASES[i] is empty for the default clause, // 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* virtual Bstatement*
switch_statement(Bexpression* value, switch_statement(Bfunction* function, Bexpression* value,
const std::vector<std::vector<Bexpression*> >& cases, const std::vector<std::vector<Bexpression*> >& cases,
const std::vector<Bstatement*>& statements, const std::vector<Bstatement*>& statements,
Location) = 0; Location) = 0;
...@@ -534,6 +534,12 @@ class Backend ...@@ -534,6 +534,12 @@ class Backend
bool address_is_taken, Location location, bool address_is_taken, Location location,
Bstatement** pstatement) = 0; 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 // Create a named immutable initialized data structure. This is
// used for type descriptors, map descriptors, and function // used for type descriptors, map descriptors, and function
// descriptors. This returns a Bvariable because it corresponds to // descriptors. This returns a Bvariable because it corresponds to
...@@ -653,6 +659,16 @@ class Backend ...@@ -653,6 +659,16 @@ class Backend
// true on success, false on failure. // true on success, false on failure.
virtual bool virtual bool
function_set_body(Bfunction* function, Bstatement* code_stmt) = 0; 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. // The backend interface has to define this function.
......
...@@ -3578,127 +3578,7 @@ Expression::make_unsafe_cast(Type* type, Expression* expr, ...@@ -3578,127 +3578,7 @@ Expression::make_unsafe_cast(Type* type, Expression* expr,
return new Unsafe_type_conversion_expression(type, expr, location); return new Unsafe_type_conversion_expression(type, expr, location);
} }
// Unary expressions. // Class 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), 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_;
};
// If we are taking the address of a composite literal, and the // If we are taking the address of a composite literal, and the
// contents are not constant, then we want to make a heap expression // contents are not constant, then we want to make a heap expression
...@@ -4214,11 +4094,18 @@ Unary_expression::do_get_tree(Translate_context* context) ...@@ -4214,11 +4094,18 @@ Unary_expression::do_get_tree(Translate_context* context)
} }
} }
// Build a decl for a constant constructor. if (this->is_gc_root_)
if ((this->expr_->is_composite_literal() {
// 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_->string_expression() != NULL)
&& this->expr_->is_immutable()) && this->expr_->is_immutable())
{ {
// Build a decl for a constant constructor.
static unsigned int counter; static unsigned int counter;
char buf[100]; char buf[100];
snprintf(buf, sizeof buf, "C%u", counter); snprintf(buf, sizeof buf, "C%u", counter);
...@@ -12508,6 +12395,14 @@ Fixed_array_construction_expression::do_get_tree(Translate_context* context) ...@@ -12508,6 +12395,14 @@ Fixed_array_construction_expression::do_get_tree(Translate_context* context)
return expr_to_tree(this->get_constructor(context, btype)); 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. // Construct a slice.
class Slice_construction_expression : public Array_construction_expression class Slice_construction_expression : public Array_construction_expression
......
...@@ -30,6 +30,7 @@ class Var_expression; ...@@ -30,6 +30,7 @@ class Var_expression;
class Temporary_reference_expression; class Temporary_reference_expression;
class Set_and_use_temporary_expression; class Set_and_use_temporary_expression;
class String_expression; class String_expression;
class Unary_expression;
class Binary_expression; class Binary_expression;
class Call_expression; class Call_expression;
class Func_expression; class Func_expression;
...@@ -327,6 +328,10 @@ class Expression ...@@ -327,6 +328,10 @@ class Expression
static Expression* static Expression*
make_struct_composite_literal(Type*, Expression_list*, Location); 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. // Make a slice composite literal.
static Expression* static Expression*
make_slice_composite_literal(Type*, Expression_list*, Location); make_slice_composite_literal(Type*, Expression_list*, Location);
...@@ -533,6 +538,12 @@ class Expression ...@@ -533,6 +538,12 @@ class Expression
Expression* Expression*
deref(); 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 // If this is a binary expression, return the Binary_expression
// structure. Otherwise return NULL. // structure. Otherwise return NULL.
Binary_expression* Binary_expression*
...@@ -1286,6 +1297,143 @@ class String_expression : public Expression ...@@ -1286,6 +1297,143 @@ class String_expression : public Expression
Type* type_; 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. // A binary expression.
class Binary_expression : public Expression class Binary_expression : public Expression
......
...@@ -44,6 +44,7 @@ class Backend; ...@@ -44,6 +44,7 @@ class Backend;
class Export; class Export;
class Import; class Import;
class Bexpression; class Bexpression;
class Btype;
class Bstatement; class Bstatement;
class Bblock; class Bblock;
class Bvariable; class Bvariable;
...@@ -591,11 +592,6 @@ class Gogo ...@@ -591,11 +592,6 @@ class Gogo
Expression* Expression*
runtime_error(int code, Location); 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. // Mark a function declaration as a builtin library function.
static void static void
mark_fndecl_as_builtin_library(tree fndecl); mark_fndecl_as_builtin_library(tree fndecl);
...@@ -650,17 +646,18 @@ class Gogo ...@@ -650,17 +646,18 @@ class Gogo
Named_object* Named_object*
initialization_function_decl(); initialization_function_decl();
// Write the magic initialization function. // Create the magic initialization function.
void Named_object*
write_initialization_function(Named_object* fndecl, tree init_stmt_list); create_initialization_function(Named_object* fndecl, Bstatement* code_stmt);
// Initialize imported packages. // Initialize imported packages.
void void
init_imports(tree*); init_imports(std::vector<Bstatement*>&);
// Register variables with the garbage collector. // Register variables with the garbage collector.
void 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. // Type used to map import names to packages.
typedef std::map<std::string, Package*> Imports; typedef std::map<std::string, Package*> Imports;
...@@ -1086,7 +1083,7 @@ class Function ...@@ -1086,7 +1083,7 @@ class Function
get_or_make_decl(Gogo*, Named_object*); get_or_make_decl(Gogo*, Named_object*);
// Return the function's decl after it has been built. // Return the function's decl after it has been built.
tree Bfunction*
get_decl() const; get_decl() const;
// Set the function decl to hold a backend representation of the function // Set the function decl to hold a backend representation of the function
...@@ -1675,7 +1672,7 @@ class Named_constant ...@@ -1675,7 +1672,7 @@ class Named_constant
Named_constant(Type* type, Expression* expr, int iota_value, Named_constant(Type* type, Expression* expr, int iota_value,
Location location) Location location)
: type_(type), expr_(expr), iota_value_(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* Type*
...@@ -1737,6 +1734,10 @@ class Named_constant ...@@ -1737,6 +1734,10 @@ class Named_constant
static void static void
import_const(Import*, std::string*, Type**, Expression**); import_const(Import*, std::string*, Type**, Expression**);
// Get the backend representation of the constant value.
Bexpression*
get_backend(Gogo*, Named_object*);
private: private:
// The type of the constant. // The type of the constant.
Type* type_; Type* type_;
...@@ -1754,6 +1755,8 @@ class Named_constant ...@@ -1754,6 +1755,8 @@ class Named_constant
bool lowering_; bool lowering_;
// Whether this constant is blank named and needs only type checking. // Whether this constant is blank named and needs only type checking.
bool is_sink_; bool is_sink_;
// The backend representation of the constant value.
Bexpression* bconst_;
}; };
// A type declaration. // A type declaration.
...@@ -2176,9 +2179,10 @@ class Named_object ...@@ -2176,9 +2179,10 @@ class Named_object
std::string std::string
get_id(Gogo*); get_id(Gogo*);
// Return a tree representing this object. // Get the backend representation of this object.
tree void
get_tree(Gogo*, Named_object* function); get_backend(Gogo*, std::vector<Bexpression*>&, std::vector<Btype*>&,
std::vector<Bfunction*>&);
// Define a type declaration. // Define a type declaration.
void void
...@@ -2219,8 +2223,6 @@ class Named_object ...@@ -2219,8 +2223,6 @@ class Named_object
Function_declaration* func_declaration_value; Function_declaration* func_declaration_value;
Package* package_value; Package* package_value;
} u_; } u_;
// The DECL tree for this object if we have already converted it.
tree tree_;
}; };
// A binding contour. This binds names to objects. // A binding contour. This binds names to objects.
......
...@@ -434,15 +434,9 @@ Temporary_statement::do_get_backend(Translate_context* context) ...@@ -434,15 +434,9 @@ Temporary_statement::do_get_backend(Translate_context* context)
{ {
go_assert(this->bvariable_ == NULL); 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(); Named_object* function = context->function();
Bfunction* bfunction; go_assert(function != NULL);
if (function == NULL) Bfunction* bfunction = function->func_value()->get_decl();
bfunction = NULL;
else
bfunction = tree_to_function(function->func_value()->get_decl());
Btype* btype = this->type()->get_backend(context->gogo()); Btype* btype = this->type()->get_backend(context->gogo());
Bexpression* binit; Bexpression* binit;
...@@ -2781,8 +2775,6 @@ Return_statement::do_get_backend(Translate_context* context) ...@@ -2781,8 +2775,6 @@ Return_statement::do_get_backend(Translate_context* context)
Location loc = this->location(); Location loc = this->location();
Function* function = context->function()->func_value(); Function* function = context->function()->func_value();
tree fndecl = function->get_decl();
Function::Results* results = function->result_variables(); Function::Results* results = function->result_variables();
std::vector<Bexpression*> retvals; std::vector<Bexpression*> retvals;
if (results != NULL && !results->empty()) if (results != NULL && !results->empty())
...@@ -2797,7 +2789,7 @@ Return_statement::do_get_backend(Translate_context* context) ...@@ -2797,7 +2789,7 @@ Return_statement::do_get_backend(Translate_context* context)
} }
} }
return context->backend()->return_statement(tree_to_function(fndecl), return context->backend()->return_statement(function->get_decl(),
retvals, loc); retvals, loc);
} }
...@@ -3803,8 +3795,10 @@ Constant_switch_statement::do_get_backend(Translate_context* context) ...@@ -3803,8 +3795,10 @@ Constant_switch_statement::do_get_backend(Translate_context* context)
this->clauses_->get_backend(context, break_label, &all_cases, this->clauses_->get_backend(context, break_label, &all_cases,
&all_statements); &all_statements);
Bfunction* bfunction = context->function()->func_value()->get_decl();
Bstatement* switch_statement; 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_cases,
all_statements, all_statements,
this->location()); this->location());
...@@ -4980,7 +4974,9 @@ Select_clauses::get_backend(Translate_context* context, ...@@ -4980,7 +4974,9 @@ Select_clauses::get_backend(Translate_context* context,
std::vector<Bstatement*> statements; std::vector<Bstatement*> statements;
statements.reserve(2); 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, cases,
clauses, clauses,
location); location);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment