Commit 8586635c by Ian Lance Taylor

Use temporary variables for calls with multiple results.

From-SVN: r176998
parent c469244e
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
class Gogo; class Gogo;
class Translate_context; class Translate_context;
class Traverse; class Traverse;
class Statement_inserter;
class Type; class Type;
struct Type_context; struct Type_context;
class Function_type; class Function_type;
...@@ -128,7 +129,7 @@ class Expression ...@@ -128,7 +129,7 @@ class Expression
// Make a reference to a temporary variable. Temporary variables // Make a reference to a temporary variable. Temporary variables
// are always created by a single statement, which is what we use to // are always created by a single statement, which is what we use to
// refer to them. // refer to them.
static Expression* static Temporary_reference_expression*
make_temporary_reference(Temporary_statement*, source_location); make_temporary_reference(Temporary_statement*, source_location);
// Make a sink expression--a reference to the blank identifier _. // Make a sink expression--a reference to the blank identifier _.
...@@ -521,13 +522,18 @@ class Expression ...@@ -521,13 +522,18 @@ class Expression
traverse_subexpressions(Traverse*); traverse_subexpressions(Traverse*);
// Lower an expression. This is called immediately after parsing. // Lower an expression. This is called immediately after parsing.
// IOTA_VALUE is the value that we should give to any iota // FUNCTION is the function we are in; it will be NULL for an
// expressions. This function must resolve expressions which could // expression initializing a global variable. INSERTER may be used
// not be fully parsed into their final form. It returns the same // to insert statements before the statement or initializer
// Expression or a new one. // containing this expression; it is normally used to create
// temporary variables. IOTA_VALUE is the value that we should give
// to any iota expressions. 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* Expression*
lower(Gogo* gogo, Named_object* function, int iota_value) lower(Gogo* gogo, Named_object* function, Statement_inserter* inserter,
{ return this->do_lower(gogo, function, iota_value); } int iota_value)
{ return this->do_lower(gogo, function, inserter, iota_value); }
// Determine the real type of an expression with abstract integer, // Determine the real type of an expression with abstract integer,
// floating point, or complex type. TYPE_CONTEXT describes the // floating point, or complex type. TYPE_CONTEXT describes the
...@@ -636,7 +642,7 @@ class Expression ...@@ -636,7 +642,7 @@ class Expression
// Return a lowered expression. // Return a lowered expression.
virtual Expression* virtual Expression*
do_lower(Gogo*, Named_object*, int) do_lower(Gogo*, Named_object*, Statement_inserter*, int)
{ return this; } { return this; }
// Return whether this is a constant expression. // Return whether this is a constant expression.
...@@ -871,7 +877,7 @@ class Parser_expression : public Expression ...@@ -871,7 +877,7 @@ class Parser_expression : public Expression
protected: protected:
virtual Expression* virtual Expression*
do_lower(Gogo*, Named_object*, int) = 0; do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0;
Type* Type*
do_type(); do_type();
...@@ -906,7 +912,7 @@ class Var_expression : public Expression ...@@ -906,7 +912,7 @@ class Var_expression : public Expression
protected: protected:
Expression* Expression*
do_lower(Gogo*, Named_object*, int); do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Type* Type*
do_type(); do_type();
...@@ -941,9 +947,15 @@ class Temporary_reference_expression : public Expression ...@@ -941,9 +947,15 @@ class Temporary_reference_expression : public Expression
Temporary_reference_expression(Temporary_statement* statement, Temporary_reference_expression(Temporary_statement* statement,
source_location location) source_location location)
: Expression(EXPRESSION_TEMPORARY_REFERENCE, location), : Expression(EXPRESSION_TEMPORARY_REFERENCE, location),
statement_(statement) statement_(statement), is_lvalue_(false)
{ } { }
// Indicate that this reference appears on the left hand side of an
// assignment statement.
void
set_is_lvalue()
{ this->is_lvalue_ = true; }
protected: protected:
Type* Type*
do_type(); do_type();
...@@ -969,6 +981,9 @@ class Temporary_reference_expression : public Expression ...@@ -969,6 +981,9 @@ class Temporary_reference_expression : public Expression
private: private:
// The statement where the temporary variable is defined. // The statement where the temporary variable is defined.
Temporary_statement* statement_; Temporary_statement* statement_;
// Whether this reference appears on the left hand side of an
// assignment statement.
bool is_lvalue_;
}; };
// A string expression. // A string expression.
...@@ -1099,7 +1114,7 @@ class Binary_expression : public Expression ...@@ -1099,7 +1114,7 @@ class Binary_expression : public Expression
do_traverse(Traverse* traverse); do_traverse(Traverse* traverse);
Expression* Expression*
do_lower(Gogo*, Named_object*, int); do_lower(Gogo*, Named_object*, Statement_inserter*, int);
bool bool
do_is_constant() const do_is_constant() const
...@@ -1156,9 +1171,9 @@ class Call_expression : public Expression ...@@ -1156,9 +1171,9 @@ class Call_expression : public Expression
Call_expression(Expression* fn, Expression_list* args, bool is_varargs, Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
source_location location) source_location location)
: Expression(EXPRESSION_CALL, location), : Expression(EXPRESSION_CALL, location),
fn_(fn), args_(args), type_(NULL), tree_(NULL), is_varargs_(is_varargs), fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL),
varargs_are_lowered_(false), types_are_determined_(false), is_varargs_(is_varargs), varargs_are_lowered_(false),
is_deferred_(false) types_are_determined_(false), is_deferred_(false), issued_error_(false)
{ } { }
// The function to call. // The function to call.
...@@ -1183,6 +1198,12 @@ class Call_expression : public Expression ...@@ -1183,6 +1198,12 @@ class Call_expression : public Expression
size_t size_t
result_count() const; result_count() const;
// Return the temporary variable which holds result I. This is only
// valid after the expression has been lowered, and is only valid
// for calls which return multiple results.
Temporary_statement*
result(size_t i) const;
// Return whether this is a call to the predeclared function // Return whether this is a call to the predeclared function
// recover. // recover.
bool bool
...@@ -1207,12 +1228,17 @@ class Call_expression : public Expression ...@@ -1207,12 +1228,17 @@ class Call_expression : public Expression
set_is_deferred() set_is_deferred()
{ this->is_deferred_ = true; } { this->is_deferred_ = true; }
// We have found an error with this call expression; return true if
// we should report it.
bool
issue_error();
protected: protected:
int int
do_traverse(Traverse*); do_traverse(Traverse*);
virtual Expression* virtual Expression*
do_lower(Gogo*, Named_object*, int); do_lower(Gogo*, Named_object*, Statement_inserter*, int);
void void
do_discarding_value() do_discarding_value()
...@@ -1256,8 +1282,8 @@ class Call_expression : public Expression ...@@ -1256,8 +1282,8 @@ class Call_expression : public Expression
// Let a builtin expression lower varargs. // Let a builtin expression lower varargs.
Expression* Expression*
lower_varargs(Gogo*, Named_object* function, Type* varargs_type, lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
size_t param_count); Type* varargs_type, size_t param_count);
// Let a builtin expression check whether types have been // Let a builtin expression check whether types have been
// determined. // determined.
...@@ -1276,6 +1302,9 @@ class Call_expression : public Expression ...@@ -1276,6 +1302,9 @@ class Call_expression : public Expression
Interface_field_reference_expression*, Interface_field_reference_expression*,
tree*); tree*);
tree
set_results(Translate_context*, tree);
// The function to call. // The function to call.
Expression* fn_; Expression* fn_;
// The arguments to pass. This may be NULL if there are no // The arguments to pass. This may be NULL if there are no
...@@ -1283,6 +1312,9 @@ class Call_expression : public Expression ...@@ -1283,6 +1312,9 @@ class Call_expression : public Expression
Expression_list* args_; Expression_list* args_;
// The type of the expression, to avoid recomputing it. // The type of the expression, to avoid recomputing it.
Type* type_; Type* type_;
// The list of temporaries which will hold the results if the
// function returns a tuple.
std::vector<Temporary_statement*>* results_;
// The tree for the call, used for a call which returns a tuple. // The tree for the call, used for a call which returns a tuple.
tree tree_; tree tree_;
// True if the last argument is a varargs argument (f(a...)). // True if the last argument is a varargs argument (f(a...)).
...@@ -1293,6 +1325,10 @@ class Call_expression : public Expression ...@@ -1293,6 +1325,10 @@ class Call_expression : public Expression
bool types_are_determined_; bool types_are_determined_;
// True if the call is an argument to a defer statement. // True if the call is an argument to a defer statement.
bool is_deferred_; bool is_deferred_;
// True if we reported an error about a mismatch between call
// results and uses. This is to avoid producing multiple errors
// when there are multiple Call_result_expressions.
bool issued_error_;
}; };
// An expression which represents a pointer to a function. // An expression which represents a pointer to a function.
...@@ -1390,7 +1426,7 @@ class Unknown_expression : public Parser_expression ...@@ -1390,7 +1426,7 @@ class Unknown_expression : public Parser_expression
protected: protected:
Expression* Expression*
do_lower(Gogo*, Named_object*, int); do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Expression* Expression*
do_copy() do_copy()
...@@ -1425,7 +1461,7 @@ class Index_expression : public Parser_expression ...@@ -1425,7 +1461,7 @@ class Index_expression : public Parser_expression
do_traverse(Traverse*); do_traverse(Traverse*);
Expression* Expression*
do_lower(Gogo*, Named_object*, int); do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Expression* Expression*
do_copy() do_copy()
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#define GO_GOGO_H #define GO_GOGO_H
class Traverse; class Traverse;
class Statement_inserter;
class Type; class Type;
class Type_hash_identical; class Type_hash_identical;
class Type_equal; class Type_equal;
...@@ -366,7 +367,7 @@ class Gogo ...@@ -366,7 +367,7 @@ class Gogo
// Lower an expression. // Lower an expression.
void void
lower_expression(Named_object* function, Expression**); lower_expression(Named_object* function, Statement_inserter*, Expression**);
// Lower a constant. // Lower a constant.
void void
...@@ -1157,7 +1158,7 @@ class Variable ...@@ -1157,7 +1158,7 @@ class Variable
// Lower the initialization expression after parsing is complete. // Lower the initialization expression after parsing is complete.
void 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 // A special case: the init value is used only to determine the
// type. This is used if the variable is defined using := with the // type. This is used if the variable is defined using := with the
...@@ -1208,7 +1209,7 @@ class Variable ...@@ -1208,7 +1209,7 @@ class Variable
// Traverse the initializer expression. // Traverse the initializer expression.
int int
traverse_expression(Traverse*); traverse_expression(Traverse*, unsigned int traverse_mask);
// Determine the type of the variable if necessary. // Determine the type of the variable if necessary.
void void
...@@ -2463,6 +2464,46 @@ class Traverse ...@@ -2463,6 +2464,46 @@ class Traverse
Expressions_seen* expressions_seen_; Expressions_seen* expressions_seen_;
}; };
// 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 // When translating the gogo IR into the backend data structure, this
// is the context we pass down the blocks and statements. // is the context we pass down the blocks and statements.
......
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
class Gogo; class Gogo;
class Traverse; class Traverse;
class Statement_inserter;
class Block; class Block;
class Function; class Function;
class Unnamed_label; class Unnamed_label;
...@@ -290,9 +291,11 @@ class Statement ...@@ -290,9 +291,11 @@ class Statement
// simplify statements for further processing. It returns the same // simplify statements for further processing. It returns the same
// Statement or a new one. FUNCTION is the function containing this // Statement or a new one. FUNCTION is the function containing this
// statement. BLOCK is the block containing this statement. // statement. BLOCK is the block containing this statement.
// INSERTER can be used to insert new statements before this one.
Statement* Statement*
lower(Gogo* gogo, Named_object* function, Block* block) lower(Gogo* gogo, Named_object* function, Block* block,
{ return this->do_lower(gogo, function, block); } Statement_inserter* inserter)
{ return this->do_lower(gogo, function, block, inserter); }
// Set type information for unnamed constants. // Set type information for unnamed constants.
void void
...@@ -385,7 +388,7 @@ class Statement ...@@ -385,7 +388,7 @@ class Statement
// Implemented by the child class: lower this statement to a simpler // Implemented by the child class: lower this statement to a simpler
// one. // one.
virtual Statement* virtual Statement*
do_lower(Gogo*, Named_object*, Block*) do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
{ return this; } { return this; }
// Implemented by child class: set type information for unnamed // Implemented by child class: set type information for unnamed
...@@ -535,6 +538,9 @@ class Variable_declaration_statement : public Statement ...@@ -535,6 +538,9 @@ class Variable_declaration_statement : public Statement
bool bool
do_traverse_assignments(Traverse_assignments*); do_traverse_assignments(Traverse_assignments*);
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement* Bstatement*
do_get_backend(Translate_context*); do_get_backend(Translate_context*);
...@@ -566,7 +572,7 @@ class Return_statement : public Statement ...@@ -566,7 +572,7 @@ class Return_statement : public Statement
do_traverse_assignments(Traverse_assignments*); do_traverse_assignments(Traverse_assignments*);
Statement* Statement*
do_lower(Gogo*, Named_object*, Block*); do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
bool bool
do_may_fall_through() const do_may_fall_through() const
...@@ -806,7 +812,7 @@ class Select_statement : public Statement ...@@ -806,7 +812,7 @@ class Select_statement : public Statement
{ return this->clauses_->traverse(traverse); } { return this->clauses_->traverse(traverse); }
Statement* Statement*
do_lower(Gogo*, Named_object*, Block*); do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
void void
do_determine_types() do_determine_types()
...@@ -993,7 +999,7 @@ class For_statement : public Statement ...@@ -993,7 +999,7 @@ class For_statement : public Statement
{ go_unreachable(); } { go_unreachable(); }
Statement* Statement*
do_lower(Gogo*, Named_object*, Block*); do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement* Bstatement*
do_get_backend(Translate_context*) do_get_backend(Translate_context*)
...@@ -1051,7 +1057,7 @@ class For_range_statement : public Statement ...@@ -1051,7 +1057,7 @@ class For_range_statement : public Statement
{ go_unreachable(); } { go_unreachable(); }
Statement* Statement*
do_lower(Gogo*, Named_object*, Block*); do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement* Bstatement*
do_get_backend(Translate_context*) do_get_backend(Translate_context*)
...@@ -1280,7 +1286,7 @@ class Switch_statement : public Statement ...@@ -1280,7 +1286,7 @@ class Switch_statement : public Statement
do_traverse(Traverse*); do_traverse(Traverse*);
Statement* Statement*
do_lower(Gogo*, Named_object*, Block*); do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement* Bstatement*
do_get_backend(Translate_context*) do_get_backend(Translate_context*)
...@@ -1426,7 +1432,7 @@ class Type_switch_statement : public Statement ...@@ -1426,7 +1432,7 @@ class Type_switch_statement : public Statement
do_traverse(Traverse*); do_traverse(Traverse*);
Statement* Statement*
do_lower(Gogo*, Named_object*, Block*); do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement* Bstatement*
do_get_backend(Translate_context*) do_get_backend(Translate_context*)
......
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