diff options
author | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-01-09 23:28:10 +0000 |
---|---|---|
committer | Ian Lance Taylor <ian@gcc.gnu.org> | 2014-01-09 23:28:10 +0000 |
commit | 4bc44ceb91c0f7ad3250b8b01bdebe4e8b003f86 (patch) | |
tree | c528403ee91166ddae1e31a8413eab3bacb5f12d /gcc/go | |
parent | abd471378cbe20d51cc6a9c8b4f20907ef0f6825 (diff) | |
download | gcc-4bc44ceb91c0f7ad3250b8b01bdebe4e8b003f86.zip gcc-4bc44ceb91c0f7ad3250b8b01bdebe4e8b003f86.tar.gz gcc-4bc44ceb91c0f7ad3250b8b01bdebe4e8b003f86.tar.bz2 |
compiler: Add flattening pass
From-SVN: r206502
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 18 | ||||
-rw-r--r-- | gcc/go/gofrontend/go.cc | 5 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 206 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 14 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 10 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 19 |
6 files changed, 267 insertions, 5 deletions
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index e447418..66fbac3 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -575,6 +575,18 @@ class Expression int iota_value) { return this->do_lower(gogo, function, inserter, iota_value); } + // Flatten an expression. This is called after order_evaluation. + // FUNCTION is the function we are in; it will be NULL for an + // expression initializing a global variable. INSERTER may be used + // to insert statements before the statement or initializer + // containing this expression; it is normally used to create + // temporary variables. This function must resolve expressions + // which could not be fully parsed into their final form. It + // returns the same Expression or a new one. + Expression* + flatten(Gogo* gogo, Named_object* function, Statement_inserter* inserter) + { return this->do_flatten(gogo, function, inserter); } + // Determine the real type of an expression with abstract integer, // floating point, or complex type. TYPE_CONTEXT describes the // expected type. @@ -698,6 +710,12 @@ class Expression do_lower(Gogo*, Named_object*, Statement_inserter*, int) { return this; } + // Return a flattened expression. + virtual Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*) + { return this; } + + // Return whether this is a constant expression. virtual bool do_is_constant() const diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc index 55b4dca..26e83a1 100644 --- a/gcc/go/gofrontend/go.cc +++ b/gcc/go/gofrontend/go.cc @@ -119,12 +119,15 @@ go_parse_input_files(const char** filenames, unsigned int filename_count, // Use temporary variables to force order of evaluation. ::gogo->order_evaluations(); + // Flatten the parse tree. + ::gogo->flatten(); + // Build thunks for functions which call recover. ::gogo->build_recover_thunks(); // Convert complicated go and defer statements into simpler ones. ::gogo->simplify_thunk_statements(); - + // Dump ast, use filename[0] as the base name ::gogo->dump_ast(filenames[0]); } diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index e46bf9c..9e822e6 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -2703,6 +2703,169 @@ Gogo::order_evaluations() this->traverse(&order_eval); } +// Traversal to flatten parse tree after order of evaluation rules are applied. + +class Flatten : public Traverse +{ + public: + Flatten(Gogo* gogo, Named_object* function) + : Traverse(traverse_variables + | traverse_functions + | traverse_statements + | traverse_expressions), + gogo_(gogo), function_(function), inserter_() + { } + + void + set_inserter(const Statement_inserter* inserter) + { this->inserter_ = *inserter; } + + int + variable(Named_object*); + + int + function(Named_object*); + + int + statement(Block*, size_t* pindex, Statement*); + + int + expression(Expression**); + + private: + // General IR. + Gogo* gogo_; + // The function we are traversing. + Named_object* function_; + // Current statement inserter for use by expressions. + Statement_inserter inserter_; +}; + +// Flatten variables. + +int +Flatten::variable(Named_object* no) +{ + if (!no->is_variable()) + return TRAVERSE_CONTINUE; + + if (no->is_variable() && no->var_value()->is_global()) + { + // Global variables can have loops in their initialization + // expressions. This is handled in flatten_init_expression. + no->var_value()->flatten_init_expression(this->gogo_, this->function_, + &this->inserter_); + return TRAVERSE_CONTINUE; + } + + go_assert(!no->var_value()->has_pre_init()); + + return TRAVERSE_SKIP_COMPONENTS; +} + +// Flatten the body of a function. Record the function while flattening it, +// so that we can pass it down when flattening an expression. + +int +Flatten::function(Named_object* no) +{ + go_assert(this->function_ == NULL); + this->function_ = no; + int t = no->func_value()->traverse(this); + this->function_ = NULL; + + if (t == TRAVERSE_EXIT) + return t; + return TRAVERSE_SKIP_COMPONENTS; +} + +// Flatten statement parse trees. + +int +Flatten::statement(Block* block, size_t* pindex, Statement* sorig) +{ + // Because we explicitly traverse the statement's contents + // ourselves, we want to skip block statements here. There is + // nothing to flatten in a block statement. + if (sorig->is_block_statement()) + return TRAVERSE_CONTINUE; + + Statement_inserter hold_inserter(this->inserter_); + this->inserter_ = Statement_inserter(block, pindex); + + // Flatten the expressions first. + int t = sorig->traverse_contents(this); + if (t == TRAVERSE_EXIT) + { + this->inserter_ = hold_inserter; + return t; + } + + // Keep flattening until nothing changes. + Statement* s = sorig; + while (true) + { + Statement* snew = s->flatten(this->gogo_, this->function_, block, + &this->inserter_); + if (snew == s) + break; + s = snew; + t = s->traverse_contents(this); + if (t == TRAVERSE_EXIT) + { + this->inserter_ = hold_inserter; + return t; + } + } + + if (s != sorig) + block->replace_statement(*pindex, s); + + this->inserter_ = hold_inserter; + return TRAVERSE_SKIP_COMPONENTS; +} + +// Flatten expression parse trees. + +int +Flatten::expression(Expression** pexpr) +{ + // Keep flattening until nothing changes. + while (true) + { + Expression* e = *pexpr; + if (e->traverse_subexpressions(this) == TRAVERSE_EXIT) + return TRAVERSE_EXIT; + + Expression* enew = e->flatten(this->gogo_, this->function_, + &this->inserter_); + if (enew == e) + break; + *pexpr = enew; + } + return TRAVERSE_SKIP_COMPONENTS; +} + +// Flatten an expression. INSERTER may be NULL, in which case the +// expression had better not need to create any temporaries. + +void +Gogo::flatten_expression(Named_object* function, Statement_inserter* inserter, + Expression** pexpr) +{ + Flatten flatten(this, function); + if (inserter != NULL) + flatten.set_inserter(inserter); + flatten.expression(pexpr); +} + +void +Gogo::flatten() +{ + Flatten flatten(this, NULL); + this->traverse(&flatten); +} + // Traversal to convert calls to the predeclared recover function to // pass in an argument indicating whether it can recover from a panic // or not. @@ -4286,10 +4449,11 @@ Variable::Variable(Type* type, Expression* init, bool is_global, backend_(NULL), is_global_(is_global), is_parameter_(is_parameter), is_receiver_(is_receiver), is_varargs_parameter_(false), is_used_(false), is_address_taken_(false), is_non_escaping_address_taken_(false), - seen_(false), init_is_lowered_(false), type_from_init_tuple_(false), - type_from_range_index_(false), type_from_range_value_(false), - type_from_chan_element_(false), is_type_switch_var_(false), - determined_type_(false), in_unique_section_(false) + seen_(false), init_is_lowered_(false), init_is_flattened_(false), + type_from_init_tuple_(false), type_from_range_index_(false), + type_from_range_value_(false), type_from_chan_element_(false), + is_type_switch_var_(false), determined_type_(false), + in_unique_section_(false) { go_assert(type != NULL || init != NULL); go_assert(!is_parameter || init == NULL); @@ -4351,6 +4515,40 @@ Variable::lower_init_expression(Gogo* gogo, Named_object* function, } } +// Flatten the initialization expression after ordering evaluations. + +void +Variable::flatten_init_expression(Gogo* gogo, Named_object* function, + Statement_inserter* inserter) +{ + Named_object* dep = gogo->var_depends_on(this); + if (dep != NULL && dep->is_variable()) + dep->var_value()->flatten_init_expression(gogo, function, inserter); + + if (this->init_ != NULL && !this->init_is_flattened_) + { + if (this->seen_) + { + // We will give an error elsewhere, this is just to prevent + // an infinite loop. + return; + } + this->seen_ = true; + + Statement_inserter global_inserter; + if (this->is_global_) + { + global_inserter = Statement_inserter(gogo, this); + inserter = &global_inserter; + } + + gogo->flatten_expression(function, inserter, &this->init_); + + this->seen_ = false; + this->init_is_flattened_ = true; + } +} + // Get the preinit block. Block* diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index a9a5681..285e060 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -487,6 +487,10 @@ class Gogo void lower_constant(Named_object*); + // Flatten an expression. + void + flatten_expression(Named_object* function, Statement_inserter*, Expression**); + // Create all necessary function descriptors. void create_function_descriptors(); @@ -531,6 +535,10 @@ class Gogo void order_evaluations(); + // Flatten parse tree. + void + flatten(); + // Build thunks for functions which call recover. void build_recover_thunks(); @@ -1447,6 +1455,10 @@ class Variable void lower_init_expression(Gogo*, Named_object*, Statement_inserter*); + // Flatten the initialization expression after ordering evaluations. + void + flatten_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 // comma-ok form of a map index or a receive expression. The init @@ -1580,6 +1592,8 @@ class Variable bool seen_ : 1; // True if we have lowered the initialization expression. bool init_is_lowered_ : 1; + // True if we have flattened the initialization expression. + bool init_is_flattened_ : 1; // True if init is a tuple used to set the type. bool type_from_init_tuple_ : 1; // True if init is a range clause and the type is the index type. diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index 3a0bc3b..a28aa3d 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -246,6 +246,16 @@ Variable_declaration_statement::do_lower(Gogo* gogo, Named_object* function, return this; } +// Flatten the variable's initialization expression. + +Statement* +Variable_declaration_statement::do_flatten(Gogo* gogo, Named_object* function, + Block*, Statement_inserter* inserter) +{ + this->var_->var_value()->flatten_init_expression(gogo, function, inserter); + return this; +} + // Convert a variable declaration to the backend representation. Bstatement* diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index b128fa0..7d9bcfd 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -306,6 +306,16 @@ class Statement Statement_inserter* inserter) { return this->do_lower(gogo, function, block, inserter); } + // Flatten a statement. This is called immediately after the order of + // evaluation rules are applied to statements. It returns the same + // Statement or a new one. FUNCTION is the function containing this + // statement. BLOCK is the block containing this statement. + // INSERTER can be used to insert new statements before this one. + Statement* + flatten(Gogo* gogo, Named_object* function, Block* block, + Statement_inserter* inserter) + { return this->do_flatten(gogo, function, block, inserter); } + // Set type information for unnamed constants. void determine_types(); @@ -412,6 +422,12 @@ class Statement do_lower(Gogo*, Named_object*, Block*, Statement_inserter*) { return this; } + // Implemented by the child class: lower this statement to a simpler + // one. + virtual Statement* + do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*) + { return this; } + // Implemented by child class: set type information for unnamed // constants. Any statement which includes an expression needs to // implement this. @@ -583,6 +599,9 @@ class Variable_declaration_statement : public Statement Statement* do_lower(Gogo*, Named_object*, Block*, Statement_inserter*); + Statement* + do_flatten(Gogo*, Named_object*, Block*, Statement_inserter*); + Bstatement* do_get_backend(Translate_context*); |