#define GO_GOGO_H
class Traverse;
+class Statement_inserter;
class Type;
class Type_hash_identical;
class Type_equal;
class Function_type;
class Expression;
class Statement;
+class Temporary_statement;
class Block;
class Function;
class Bindings;
class Named_object;
class Label;
class Translate_context;
+class Backend;
class Export;
class Import;
+class Bexpression;
+class Bstatement;
+class Bblock;
+class Bvariable;
+class Blabel;
// This file declares the basic classes used to hold the internal
// representation of Go which is built by the parser.
public:
// Create the IR, passing in the sizes of the types "int" and
// "uintptr" in bits.
- Gogo(int int_type_size, int pointer_size);
+ Gogo(Backend* backend, int int_type_size, int pointer_size);
+
+ // Get the backend generator.
+ Backend*
+ backend()
+ { return this->backend_; }
// Get the package name.
const std::string&
static std::string
hidden_name_prefix(const std::string& name)
{
- gcc_assert(Gogo::is_hidden_name(name));
+ go_assert(Gogo::is_hidden_name(name));
return name.substr(1, name.rfind('.') - 1);
}
void
lower_parse_tree();
+ // Lower all the statements in a block.
+ void
+ lower_block(Named_object* function, Block*);
+
// Lower an expression.
void
- lower_expression(Named_object* function, Expression**);
+ lower_expression(Named_object* function, Statement_inserter*, Expression**);
// Lower a constant.
void
void
simplify_thunk_statements();
+ // Dump AST if -fgo-dump-ast is set
+ void
+ dump_ast(const char* basename);
+
// Convert named types to the backend representation.
void
convert_named_types();
void
write_globals();
+ // Create trees for implicit builtin functions.
+ void
+ define_builtin_function_trees();
+
// Build a call to a builtin function. PDECL should point to a NULL
// initialized static pointer which will hold the fndecl. NAME is
// the name of the function. NARGS is the number of arguments.
static void
mark_fndecl_as_builtin_library(tree fndecl);
- // Build the type of the struct that holds a slice for the given
- // element type.
- tree
- slice_type_tree(tree element_type_tree);
-
- // Given a tree for a slice type, return the tree for the element
- // type.
- static tree
- slice_element_type_tree(tree slice_type_tree);
-
// Build a constructor for a slice. SLICE_TYPE_TREE is the type of
// the slice. VALUES points to the values. COUNT is the size,
// CAPACITY is the capacity. If CAPACITY is NULL, it is set to
slice_constructor(tree slice_type_tree, tree values, tree count,
tree capacity);
- // Build a constructor for an empty slice. SLICE_TYPE_TREE is the
- // type of the slice.
- static tree
- empty_slice_constructor(tree slice_type_tree);
-
- // Build a map descriptor.
- tree
- map_descriptor(Map_type*);
-
- // Return a tree for the type of a map descriptor. This is struct
- // __go_map_descriptor in libgo/runtime/map.h. This is the same for
- // all map types.
- tree
- map_descriptor_type();
-
- // Build a type descriptor for TYPE using INITIALIZER as the type
- // descriptor. This builds a new decl stored in *PDECL.
- void
- build_type_descriptor_decl(const Type*, Expression* initializer,
- tree* pdecl);
-
// Build required interface method tables.
void
build_interface_method_tables();
tree
go_string_constant_tree(const std::string&);
- // Send a value on a channel.
- static tree
- send_on_channel(tree channel, tree val, bool blocking, bool for_select,
- source_location);
-
// Receive a value from a channel.
static tree
receive_from_channel(tree type_tree, tree channel, bool for_select,
receive_as_64bit_integer(tree type, tree channel, bool blocking,
bool for_select);
-
// Make a trampoline which calls FNADDR passing CLOSURE.
tree
make_trampoline(tree fnaddr, tree closure, source_location);
// The stack of functions.
typedef std::vector<Open_function> Open_functions;
- // Create trees for implicit builtin functions.
- void
- define_builtin_function_trees();
-
// Set up the built-in unsafe package.
void
import_unsafe(const std::string&, bool is_exported, source_location);
tree
ptr_go_string_constant_tree(const std::string&);
- // Return the name to use for a type descriptor decl for an unnamed
- // type.
- std::string
- unnamed_type_descriptor_decl_name(const Type* type);
-
- // Return the name to use for a type descriptor decl for a type
- // named NO, defined in IN_FUNCTION.
- std::string
- type_descriptor_decl_name(const Named_object* no,
- const Named_object* in_function);
-
- // Where a type descriptor should be defined.
- enum Type_descriptor_location
- {
- // Defined in this file.
- TYPE_DESCRIPTOR_DEFINED,
- // Defined in some other file.
- TYPE_DESCRIPTOR_UNDEFINED,
- // Common definition which may occur in multiple files.
- TYPE_DESCRIPTOR_COMMON
- };
-
- // Return where the decl for TYPE should be defined.
- Type_descriptor_location
- type_descriptor_location(const Type* type);
-
// Return the type of a trampoline.
static tree
trampoline_type_tree();
// Type used to map special names in the sys package.
typedef std::map<std::string, std::string> Sys_names;
- // Hash table mapping map types to map descriptor decls.
- typedef Unordered_map_hash(const Map_type*, tree, Type_hash_identical,
- Type_identical) Map_descriptors;
-
- // Map unnamed types to type descriptor decls.
- typedef Unordered_map_hash(const Type*, tree, Type_hash_identical,
- Type_identical) Type_descriptor_decls;
-
+ // The backend generator.
+ Backend* backend_;
// The package we are compiling.
Package* package_;
// The list of currently open functions during parsing.
// Mapping from package names we have seen to packages. This does
// not include the package we are compiling.
Packages packages_;
- // Mapping from map types to map descriptors.
- Map_descriptors* map_descriptors_;
- // Mapping from unnamed types to type descriptor decls.
- Type_descriptor_decls* type_descriptor_decls_;
// The functions named "init", if there are any.
std::vector<Named_object*> init_functions_;
// Whether we need a magic initialization function.
bool
may_fall_through() const;
- // Return a tree of the code in this block.
- tree
- get_tree(Translate_context*);
+ // Convert the block to the backend representation.
+ Bblock*
+ get_backend(Translate_context*);
// Iterate over statements.
void
set_enclosing(Function* enclosing)
{
- gcc_assert(this->enclosing_ == NULL);
+ go_assert(this->enclosing_ == NULL);
this->enclosing_ = enclosing;
}
- // Create the named result variables in the outer block.
+ // The result variables.
+ typedef std::vector<Named_object*> Results;
+
+ // Create the result variables in the outer block.
void
- create_named_result_variables(Gogo*);
+ create_result_variables(Gogo*);
// Update the named result variables when cloning a function which
// calls recover.
void
- update_named_result_variables();
+ update_result_variables();
+
+ // Return the result variables.
+ Results*
+ result_variables()
+ { return this->results_; }
+
+ // Whether the result variables have names.
+ bool
+ results_are_named() const
+ { return this->results_are_named_; }
// Add a new field to the closure variable.
void
void
set_closure_var(Named_object* v)
{
- gcc_assert(this->closure_var_ == NULL);
+ go_assert(this->closure_var_ == NULL);
this->closure_var_ = v;
}
Named_object*
enclosing_var(unsigned int index)
{
- gcc_assert(index < this->closure_fields_.size());
+ go_assert(index < this->closure_fields_.size());
return closure_fields_[index].first;
}
Label*
add_label_reference(const std::string& label_name);
+ // Warn about labels that are defined but not used.
+ void
+ check_labels() const;
+
// Whether this function calls the predeclared recover function.
bool
calls_recover() const
tree
get_decl() const
{
- gcc_assert(this->fndecl_ != NULL);
+ go_assert(this->fndecl_ != NULL);
return this->fndecl_;
}
return_value(Gogo*, Named_object*, source_location, tree* stmt_list) const;
// Get a tree for the variable holding the defer stack.
- tree
+ Expression*
defer_stack(source_location);
// Export the function.
void
build_defer_wrapper(Gogo*, Named_object*, tree*, tree*);
- typedef std::vector<Named_object*> Named_results;
-
typedef std::vector<std::pair<Named_object*,
source_location> > Closure_fields;
// The enclosing function. This is NULL when there isn't one, which
// is the normal case.
Function* enclosing_;
- // The named result variables, if any.
- Named_results* named_results_;
+ // The result variables, if any.
+ Results* results_;
// If there is a closure, this is the list of variables which appear
// in the closure. This is created by the parser, and then resolved
// to a real type when we lower parse trees.
Labels labels_;
// The function decl.
tree fndecl_;
- // A variable holding the defer stack variable. This is NULL unless
- // we actually need a defer stack.
- tree defer_stack_;
+ // The defer stack variable. A pointer to this variable is used to
+ // distinguish the defer stack for one function from another. This
+ // is NULL unless we actually need a defer stack.
+ Temporary_statement* defer_stack_;
+ // True if the result variables are named.
+ bool results_are_named_;
// True if this function calls the predeclared recover function.
bool calls_recover_;
// True if this a thunk built for a function which calls recover.
void
set_is_receiver()
{
- gcc_assert(this->is_parameter_);
+ go_assert(this->is_parameter_);
this->is_receiver_ = true;
}
void
set_is_not_receiver()
{
- gcc_assert(this->is_parameter_);
+ go_assert(this->is_parameter_);
this->is_receiver_ = false;
}
is_in_heap() const
{ return this->is_address_taken_ && !this->is_global_; }
+ // Note that something takes the address of this variable.
+ void
+ set_address_taken()
+ { this->is_address_taken_ = true; }
+
+ // Return whether the address is taken but does not escape.
+ bool
+ is_non_escaping_address_taken() const
+ { return this->is_non_escaping_address_taken_; }
+
+ // Note that something takes the address of this variable such that
+ // the address does not escape the function.
+ void
+ set_non_escaping_address_taken()
+ { this->is_non_escaping_address_taken_ = true; }
+
// Get the source location of the variable's declaration.
source_location
location() const
void
set_is_varargs_parameter()
{
- gcc_assert(this->is_parameter_);
+ go_assert(this->is_parameter_);
this->is_varargs_parameter_ = true;
}
// Lower the initialization expression after parsing is complete.
void
- lower_init_expression(Gogo*, Named_object*);
+ lower_init_expression(Gogo*, Named_object*, Statement_inserter*);
// A special case: the init value is used only to determine the
// type. This is used if the variable is defined using := with the
void
clear_type_from_chan_element()
{
- gcc_assert(this->type_from_chan_element_);
+ go_assert(this->type_from_chan_element_);
this->type_from_chan_element_ = false;
}
// Traverse the initializer expression.
int
- traverse_expression(Traverse*);
+ traverse_expression(Traverse*, unsigned int traverse_mask);
// Determine the type of the variable if necessary.
void
determine_type();
- // Note that something takes the address of this variable.
- void
- 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.
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.
bool is_receiver_ : 1;
// Whether this is the varargs parameter of a function.
bool is_varargs_parameter_ : 1;
- // Whether something takes the address of this variable.
+ // Whether something takes the address of this variable. For a
+ // local variable this implies that the variable has to be on the
+ // heap.
bool is_address_taken_ : 1;
+ // Whether something takes the address of this variable such that
+ // the address does not escape the function.
+ bool is_non_escaping_address_taken_ : 1;
// True if we have seen this variable in a traversal.
bool seen_ : 1;
// True if we have lowered the initialization expression.
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),
+ is_non_escaping_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_address_taken()
{ this->is_address_taken_ = true; }
+ // Return whether the address is taken but does not escape.
+ bool
+ is_non_escaping_address_taken() const
+ { return this->is_non_escaping_address_taken_; }
+
+ // Note that something takes the address of this variable such that
+ // the address does not escape the function.
+ void
+ set_non_escaping_address_taken()
+ { this->is_non_escaping_address_taken_ = true; }
+
// Whether this variable should live in the heap.
bool
is_in_heap() 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_;
+ // Whether something takes the address of this variable such that
+ // the address does not escape the function.
+ bool is_non_escaping_address_taken_;
};
// The value we keep for a named constant. This lets us hold a type
Unknown_name*
unknown_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
+ go_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
return this->u_.unknown_value;
}
const Unknown_name*
unknown_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
+ go_assert(this->classification_ == NAMED_OBJECT_UNKNOWN);
return this->u_.unknown_value;
}
Named_constant*
const_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_CONST);
+ go_assert(this->classification_ == NAMED_OBJECT_CONST);
return this->u_.const_value;
}
const Named_constant*
const_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_CONST);
+ go_assert(this->classification_ == NAMED_OBJECT_CONST);
return this->u_.const_value;
}
Named_type*
type_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_TYPE);
+ go_assert(this->classification_ == NAMED_OBJECT_TYPE);
return this->u_.type_value;
}
const Named_type*
type_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_TYPE);
+ go_assert(this->classification_ == NAMED_OBJECT_TYPE);
return this->u_.type_value;
}
Type_declaration*
type_declaration_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
+ go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
return this->u_.type_declaration;
}
const Type_declaration*
type_declaration_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
+ go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
return this->u_.type_declaration;
}
Variable*
var_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_VAR);
+ go_assert(this->classification_ == NAMED_OBJECT_VAR);
return this->u_.var_value;
}
const Variable*
var_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_VAR);
+ go_assert(this->classification_ == NAMED_OBJECT_VAR);
return this->u_.var_value;
}
Result_variable*
result_var_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR);
+ go_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR);
return this->u_.result_var_value;
}
const Result_variable*
result_var_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR);
+ go_assert(this->classification_ == NAMED_OBJECT_RESULT_VAR);
return this->u_.result_var_value;
}
Function*
func_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_FUNC);
+ go_assert(this->classification_ == NAMED_OBJECT_FUNC);
return this->u_.func_value;
}
const Function*
func_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_FUNC);
+ go_assert(this->classification_ == NAMED_OBJECT_FUNC);
return this->u_.func_value;
}
Function_declaration*
func_declaration_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
+ go_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
return this->u_.func_declaration_value;
}
const Function_declaration*
func_declaration_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
+ go_assert(this->classification_ == NAMED_OBJECT_FUNC_DECLARATION);
return this->u_.func_declaration_value;
}
Package*
package_value()
{
- gcc_assert(this->classification_ == NAMED_OBJECT_PACKAGE);
+ go_assert(this->classification_ == NAMED_OBJECT_PACKAGE);
return this->u_.package_value;
}
const Package*
package_value() const
{
- gcc_assert(this->classification_ == NAMED_OBJECT_PACKAGE);
+ go_assert(this->classification_ == NAMED_OBJECT_PACKAGE);
return this->u_.package_value;
}
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*);
{
public:
Label(const std::string& name)
- : name_(name), location_(0), decl_(NULL)
+ : name_(name), location_(0), is_used_(false), blabel_(NULL)
{ }
// Return the label's name.
is_defined() const
{ return this->location_ != 0; }
+ // Return whether the label has been used.
+ bool
+ is_used() const
+ { return this->is_used_; }
+
+ // Record that the label is used.
+ void
+ set_is_used()
+ { this->is_used_ = true; }
+
// Return the location of the definition.
source_location
location() const
void
define(source_location location)
{
- gcc_assert(this->location_ == 0);
+ go_assert(this->location_ == 0);
this->location_ = location;
}
- // Return the LABEL_DECL for this decl.
- tree
- get_decl();
+ // Return the backend representation for this label.
+ Blabel*
+ get_backend_label(Translate_context*);
- // Return an expression for the address of this label.
- tree
- get_addr(source_location location);
+ // Return an expression for the address of this label. This is used
+ // to get the return address of a deferred function to see whether
+ // the function may call recover.
+ Bexpression*
+ get_addr(Translate_context*, source_location location);
private:
// The name of the label.
// The location of the definition. This is 0 if the label has not
// yet been defined.
source_location location_;
- // The LABEL_DECL.
- tree decl_;
+ // Whether the label has been used.
+ bool is_used_;
+ // The backend representation.
+ Blabel* blabel_;
};
// An unnamed label. These are used when lowering loops.
{
public:
Unnamed_label(source_location location)
- : location_(location), decl_(NULL)
+ : location_(location), blabel_(NULL)
{ }
// Get the location where the label is defined.
{ this->location_ = location; }
// Return a statement which defines this label.
- tree
- get_definition();
+ Bstatement*
+ get_definition(Translate_context*);
// Return a goto to this label from LOCATION.
- tree
- get_goto(source_location location);
+ Bstatement*
+ get_goto(Translate_context*, source_location location);
private:
- // Return the LABEL_DECL to use with GOTO_EXPR.
- tree
- get_decl();
+ // Return the backend representation.
+ Blabel*
+ get_blabel(Translate_context*);
// The location where the label is defined.
source_location location_;
- // The LABEL_DECL.
- tree decl_;
+ // The backend representation of this label.
+ Blabel* blabel_;
};
// An imported package.
const std::string&
unique_prefix() const
{
- gcc_assert(!this->unique_prefix_.empty());
+ go_assert(!this->unique_prefix_.empty());
return this->unique_prefix_;
}
Expressions_seen* expressions_seen_;
};
-// When translating the gogo IR into trees, this is the context we
-// pass down the blocks and statements.
+// A class which makes it easier to insert new statements before the
+// current statement during a traversal.
+
+class Statement_inserter
+{
+ public:
+ // Empty constructor.
+ Statement_inserter()
+ : block_(NULL), pindex_(NULL), gogo_(NULL), var_(NULL)
+ { }
+
+ // Constructor for a statement in a block.
+ Statement_inserter(Block* block, size_t *pindex)
+ : block_(block), pindex_(pindex), gogo_(NULL), var_(NULL)
+ { }
+
+ // Constructor for a global variable.
+ Statement_inserter(Gogo* gogo, Variable* var)
+ : block_(NULL), pindex_(NULL), gogo_(gogo), var_(var)
+ { go_assert(var->is_global()); }
+
+ // We use the default copy constructor and assignment operator.
+
+ // Insert S before the statement we are traversing, or before the
+ // initialization expression of a global variable.
+ void
+ insert(Statement* s);
+
+ private:
+ // The block that the statement is in.
+ Block* block_;
+ // The index of the statement that we are traversing.
+ size_t* pindex_;
+ // The IR, needed when looking at an initializer expression for a
+ // global variable.
+ Gogo* gogo_;
+ // The global variable, when looking at an initializer expression.
+ Variable* var_;
+};
+
+// When translating the gogo IR into the backend data structure, this
+// is the context we pass down the blocks and statements.
class Translate_context
{
public:
Translate_context(Gogo* gogo, Named_object* function, Block* block,
- tree block_tree)
- : gogo_(gogo), function_(function), block_(block), block_tree_(block_tree),
- is_const_(false)
+ Bblock* bblock)
+ : gogo_(gogo), backend_(gogo->backend()), function_(function),
+ block_(block), bblock_(bblock), is_const_(false)
{ }
// Accessors.
gogo()
{ return this->gogo_; }
+ Backend*
+ backend()
+ { return this->backend_; }
+
Named_object*
function()
{ return this->function_; }
block()
{ return this->block_; }
- tree
- block_tree()
- { return this->block_tree_; }
+ Bblock*
+ bblock()
+ { return this->bblock_; }
bool
is_const()
private:
// The IR for the entire compilation unit.
Gogo* gogo_;
- // The function we are currently translating.
+ // The generator for the backend data structures.
+ Backend* backend_;
+ // The function we are currently translating. NULL if not in a
+ // function, e.g., the initializer of a global variable.
Named_object* function_;
- // The block we are currently translating.
+ // The block we are currently translating. NULL if not in a
+ // function.
Block *block_;
- // The BLOCK node for the current block.
- tree block_tree_;
+ // The backend representation of the current block. NULL if block_
+ // is NULL.
+ Bblock* bblock_;
// Whether this is being evaluated in a constant context. This is
// used for type descriptor initializers.
bool is_const_;