Commit 8586635c by Ian Lance Taylor

Use temporary variables for calls with multiple results.

From-SVN: r176998
parent c469244e
......@@ -15,6 +15,7 @@
class Gogo;
class Translate_context;
class Traverse;
class Statement_inserter;
class Type;
struct Type_context;
class Function_type;
......@@ -128,7 +129,7 @@ class Expression
// Make a reference to a temporary variable. Temporary variables
// are always created by a single statement, which is what we use to
// refer to them.
static Expression*
static Temporary_reference_expression*
make_temporary_reference(Temporary_statement*, source_location);
// Make a sink expression--a reference to the blank identifier _.
......@@ -521,13 +522,18 @@ class Expression
traverse_subexpressions(Traverse*);
// Lower an expression. This is called immediately after parsing.
// 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.
// 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. 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*
lower(Gogo* gogo, Named_object* function, int iota_value)
{ return this->do_lower(gogo, function, iota_value); }
lower(Gogo* gogo, Named_object* function, Statement_inserter* inserter,
int iota_value)
{ return this->do_lower(gogo, function, inserter, iota_value); }
// Determine the real type of an expression with abstract integer,
// floating point, or complex type. TYPE_CONTEXT describes the
......@@ -636,7 +642,7 @@ class Expression
// Return a lowered expression.
virtual Expression*
do_lower(Gogo*, Named_object*, int)
do_lower(Gogo*, Named_object*, Statement_inserter*, int)
{ return this; }
// Return whether this is a constant expression.
......@@ -871,7 +877,7 @@ class Parser_expression : public Expression
protected:
virtual Expression*
do_lower(Gogo*, Named_object*, int) = 0;
do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0;
Type*
do_type();
......@@ -906,7 +912,7 @@ class Var_expression : public Expression
protected:
Expression*
do_lower(Gogo*, Named_object*, int);
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Type*
do_type();
......@@ -941,9 +947,15 @@ class Temporary_reference_expression : public Expression
Temporary_reference_expression(Temporary_statement* statement,
source_location 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:
Type*
do_type();
......@@ -969,6 +981,9 @@ class Temporary_reference_expression : public Expression
private:
// The statement where the temporary variable is defined.
Temporary_statement* statement_;
// Whether this reference appears on the left hand side of an
// assignment statement.
bool is_lvalue_;
};
// A string expression.
......@@ -1099,7 +1114,7 @@ class Binary_expression : public Expression
do_traverse(Traverse* traverse);
Expression*
do_lower(Gogo*, Named_object*, int);
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
bool
do_is_constant() const
......@@ -1156,9 +1171,9 @@ class Call_expression : public Expression
Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
source_location location)
: Expression(EXPRESSION_CALL, location),
fn_(fn), args_(args), type_(NULL), tree_(NULL), is_varargs_(is_varargs),
varargs_are_lowered_(false), types_are_determined_(false),
is_deferred_(false)
fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL),
is_varargs_(is_varargs), varargs_are_lowered_(false),
types_are_determined_(false), is_deferred_(false), issued_error_(false)
{ }
// The function to call.
......@@ -1183,6 +1198,12 @@ class Call_expression : public Expression
size_t
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
// recover.
bool
......@@ -1207,12 +1228,17 @@ class Call_expression : public Expression
set_is_deferred()
{ this->is_deferred_ = true; }
// We have found an error with this call expression; return true if
// we should report it.
bool
issue_error();
protected:
int
do_traverse(Traverse*);
virtual Expression*
do_lower(Gogo*, Named_object*, int);
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
void
do_discarding_value()
......@@ -1256,8 +1282,8 @@ class Call_expression : public Expression
// Let a builtin expression lower varargs.
Expression*
lower_varargs(Gogo*, Named_object* function, Type* varargs_type,
size_t param_count);
lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
Type* varargs_type, size_t param_count);
// Let a builtin expression check whether types have been
// determined.
......@@ -1276,6 +1302,9 @@ class Call_expression : public Expression
Interface_field_reference_expression*,
tree*);
tree
set_results(Translate_context*, tree);
// The function to call.
Expression* fn_;
// The arguments to pass. This may be NULL if there are no
......@@ -1283,6 +1312,9 @@ class Call_expression : public Expression
Expression_list* args_;
// The type of the expression, to avoid recomputing it.
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.
tree tree_;
// True if the last argument is a varargs argument (f(a...)).
......@@ -1293,6 +1325,10 @@ class Call_expression : public Expression
bool types_are_determined_;
// True if the call is an argument to a defer statement.
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.
......@@ -1390,7 +1426,7 @@ class Unknown_expression : public Parser_expression
protected:
Expression*
do_lower(Gogo*, Named_object*, int);
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Expression*
do_copy()
......@@ -1425,7 +1461,7 @@ class Index_expression : public Parser_expression
do_traverse(Traverse*);
Expression*
do_lower(Gogo*, Named_object*, int);
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Expression*
do_copy()
......
......@@ -8,6 +8,7 @@
#define GO_GOGO_H
class Traverse;
class Statement_inserter;
class Type;
class Type_hash_identical;
class Type_equal;
......@@ -366,7 +367,7 @@ class Gogo
// Lower an expression.
void
lower_expression(Named_object* function, Expression**);
lower_expression(Named_object* function, Statement_inserter*, Expression**);
// Lower a constant.
void
......@@ -1157,7 +1158,7 @@ class Variable
// 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
......@@ -1208,7 +1209,7 @@ class Variable
// Traverse the initializer expression.
int
traverse_expression(Traverse*);
traverse_expression(Traverse*, unsigned int traverse_mask);
// Determine the type of the variable if necessary.
void
......@@ -2463,6 +2464,46 @@ class Traverse
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
// is the context we pass down the blocks and statements.
......
......@@ -11,6 +11,7 @@
class Gogo;
class Traverse;
class Statement_inserter;
class Block;
class Function;
class Unnamed_label;
......@@ -290,9 +291,11 @@ class Statement
// simplify statements for further processing. 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*
lower(Gogo* gogo, Named_object* function, Block* block)
{ return this->do_lower(gogo, function, block); }
lower(Gogo* gogo, Named_object* function, Block* block,
Statement_inserter* inserter)
{ return this->do_lower(gogo, function, block, inserter); }
// Set type information for unnamed constants.
void
......@@ -385,7 +388,7 @@ class Statement
// Implemented by the child class: lower this statement to a simpler
// one.
virtual Statement*
do_lower(Gogo*, Named_object*, Block*)
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*)
{ return this; }
// Implemented by child class: set type information for unnamed
......@@ -535,6 +538,9 @@ class Variable_declaration_statement : public Statement
bool
do_traverse_assignments(Traverse_assignments*);
Statement*
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*);
......@@ -566,7 +572,7 @@ class Return_statement : public Statement
do_traverse_assignments(Traverse_assignments*);
Statement*
do_lower(Gogo*, Named_object*, Block*);
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
bool
do_may_fall_through() const
......@@ -806,7 +812,7 @@ class Select_statement : public Statement
{ return this->clauses_->traverse(traverse); }
Statement*
do_lower(Gogo*, Named_object*, Block*);
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
void
do_determine_types()
......@@ -993,7 +999,7 @@ class For_statement : public Statement
{ go_unreachable(); }
Statement*
do_lower(Gogo*, Named_object*, Block*);
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
......@@ -1051,7 +1057,7 @@ class For_range_statement : public Statement
{ go_unreachable(); }
Statement*
do_lower(Gogo*, Named_object*, Block*);
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
......@@ -1280,7 +1286,7 @@ class Switch_statement : public Statement
do_traverse(Traverse*);
Statement*
do_lower(Gogo*, Named_object*, Block*);
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
do_get_backend(Translate_context*)
......@@ -1426,7 +1432,7 @@ class Type_switch_statement : public Statement
do_traverse(Traverse*);
Statement*
do_lower(Gogo*, Named_object*, Block*);
do_lower(Gogo*, Named_object*, Block*, Statement_inserter*);
Bstatement*
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