Commit ab658f56 by Ian Lance Taylor

compiler: do simple deadcode elimination

    
    Normally the backend will do deadcode elimination and this is
    sufficient. However, the escape analysis operates on the AST that
    may have deadcode, and may cause things to escape that otherwise
    do not.
    
    This CL adds a simple deadcode elimination, run before the escape
    analysis.
    
    Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/181080

From-SVN: r272043
parent e733243a
e76c26059585433ce44e50cd7f8f504c6676f453 46329dd9e6473fff46df6b310c11116d1558e470
The first line of this file holds the git revision number of the last The first line of this file holds the git revision number of the last
merge done from the gofrontend repository. merge done from the gofrontend repository.
...@@ -1764,6 +1764,13 @@ class Boolean_expression : public Expression ...@@ -1764,6 +1764,13 @@ class Boolean_expression : public Expression
{ return this->val_ == false; } { return this->val_ == false; }
bool bool
do_boolean_constant_value(bool* val) const
{
*val = this->val_;
return true;
}
bool
do_is_static_initializer() const do_is_static_initializer() const
{ return true; } { return true; }
...@@ -3132,6 +3139,9 @@ class Const_expression : public Expression ...@@ -3132,6 +3139,9 @@ class Const_expression : public Expression
bool bool
do_string_constant_value(std::string* val) const; do_string_constant_value(std::string* val) const;
bool
do_boolean_constant_value(bool* val) const;
Type* Type*
do_type(); do_type();
...@@ -3250,6 +3260,21 @@ Const_expression::do_string_constant_value(std::string* val) const ...@@ -3250,6 +3260,21 @@ Const_expression::do_string_constant_value(std::string* val) const
return ok; return ok;
} }
bool
Const_expression::do_boolean_constant_value(bool* val) const
{
if (this->seen_)
return false;
Expression* e = this->constant_->const_value()->expr();
this->seen_ = true;
bool ok = e->boolean_constant_value(val);
this->seen_ = false;
return ok;
}
// Return the type of the const reference. // Return the type of the const reference.
Type* Type*
...@@ -3841,6 +3866,16 @@ Type_conversion_expression::do_string_constant_value(std::string* val) const ...@@ -3841,6 +3866,16 @@ Type_conversion_expression::do_string_constant_value(std::string* val) const
return false; return false;
} }
// Return the constant boolean value if there is one.
bool
Type_conversion_expression::do_boolean_constant_value(bool* val) const
{
if (!this->type_->is_boolean_type())
return false;
return this->expr_->boolean_constant_value(val);
}
// Determine the resulting type of the conversion. // Determine the resulting type of the conversion.
void void
...@@ -4710,6 +4745,20 @@ Unary_expression::do_numeric_constant_value(Numeric_constant* nc) const ...@@ -4710,6 +4745,20 @@ Unary_expression::do_numeric_constant_value(Numeric_constant* nc) const
nc, &issued_error); nc, &issued_error);
} }
// Return the boolean constant value of a unary expression, if it has one.
bool
Unary_expression::do_boolean_constant_value(bool* val) const
{
if (this->op_ == OPERATOR_NOT
&& this->expr_->boolean_constant_value(val))
{
*val = !*val;
return true;
}
return false;
}
// Return the type of a unary expression. // Return the type of a unary expression.
Type* Type*
...@@ -6187,6 +6236,86 @@ Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const ...@@ -6187,6 +6236,86 @@ Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const
this->location(), nc, &issued_error); this->location(), nc, &issued_error);
} }
// Return the boolean constant value, if it has one.
bool
Binary_expression::do_boolean_constant_value(bool* val) const
{
bool is_comparison = false;
switch (this->op_)
{
case OPERATOR_EQEQ:
case OPERATOR_NOTEQ:
case OPERATOR_LT:
case OPERATOR_LE:
case OPERATOR_GT:
case OPERATOR_GE:
is_comparison = true;
break;
case OPERATOR_ANDAND:
case OPERATOR_OROR:
break;
default:
return false;
}
Numeric_constant left_nc, right_nc;
if (is_comparison
&& this->left_->numeric_constant_value(&left_nc)
&& this->right_->numeric_constant_value(&right_nc))
return Binary_expression::compare_constant(this->op_, &left_nc,
&right_nc,
this->location(),
val);
std::string left_str, right_str;
if (is_comparison
&& this->left_->string_constant_value(&left_str)
&& this->right_->string_constant_value(&right_str))
{
*val = Binary_expression::cmp_to_bool(this->op_,
left_str.compare(right_str));
return true;
}
bool left_bval;
if (this->left_->boolean_constant_value(&left_bval))
{
if (this->op_ == OPERATOR_ANDAND && !left_bval)
{
*val = false;
return true;
}
else if (this->op_ == OPERATOR_OROR && left_bval)
{
*val = true;
return true;
}
bool right_bval;
if (this->right_->boolean_constant_value(&right_bval))
{
switch (this->op_)
{
case OPERATOR_EQEQ:
*val = (left_bval == right_bval);
return true;
case OPERATOR_NOTEQ:
*val = (left_bval != right_bval);
return true;
case OPERATOR_ANDAND:
case OPERATOR_OROR:
*val = right_bval;
return true;
default:
go_unreachable();
}
}
}
return false;
}
// Note that the value is being discarded. // Note that the value is being discarded.
bool bool
......
...@@ -581,6 +581,12 @@ class Expression ...@@ -581,6 +581,12 @@ class Expression
string_constant_value(std::string* val) const string_constant_value(std::string* val) const
{ return this->do_string_constant_value(val); } { return this->do_string_constant_value(val); }
// If this is not a constant expression with boolean type, return
// false. If it is one, return true, and set VAL to the value.
bool
boolean_constant_value(bool* val) const
{ return this->do_boolean_constant_value(val); }
// This is called if the value of this expression is being // This is called if the value of this expression is being
// discarded. This issues warnings about computed values being // discarded. This issues warnings about computed values being
// unused. This returns true if all is well, false if it issued an // unused. This returns true if all is well, false if it issued an
...@@ -1125,6 +1131,12 @@ class Expression ...@@ -1125,6 +1131,12 @@ class Expression
do_string_constant_value(std::string*) const do_string_constant_value(std::string*) const
{ return false; } { return false; }
// Return whether this is a constant expression of boolean type, and
// set VAL to the value.
virtual bool
do_boolean_constant_value(bool*) const
{ return false; }
// Called by the parser if the value is being discarded. // Called by the parser if the value is being discarded.
virtual bool virtual bool
do_discarding_value(); do_discarding_value();
...@@ -1771,6 +1783,9 @@ class Type_conversion_expression : public Expression ...@@ -1771,6 +1783,9 @@ class Type_conversion_expression : public Expression
bool bool
do_string_constant_value(std::string*) const; do_string_constant_value(std::string*) const;
bool
do_boolean_constant_value(bool*) const;
Type* Type*
do_type() do_type()
{ return this->type_; } { return this->type_; }
...@@ -1965,6 +1980,9 @@ class Unary_expression : public Expression ...@@ -1965,6 +1980,9 @@ class Unary_expression : public Expression
bool bool
do_numeric_constant_value(Numeric_constant*) const; do_numeric_constant_value(Numeric_constant*) const;
bool
do_boolean_constant_value(bool*) const;
Type* Type*
do_type(); do_type();
...@@ -2120,6 +2138,9 @@ class Binary_expression : public Expression ...@@ -2120,6 +2138,9 @@ class Binary_expression : public Expression
do_numeric_constant_value(Numeric_constant*) const; do_numeric_constant_value(Numeric_constant*) const;
bool bool
do_boolean_constant_value(bool*) const;
bool
do_discarding_value(); do_discarding_value();
Type* Type*
......
...@@ -142,6 +142,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count, ...@@ -142,6 +142,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
if (only_check_syntax) if (only_check_syntax)
return; return;
// Do simple deadcode elimination.
::gogo->remove_deadcode();
// Make implicit type conversions explicit. // Make implicit type conversions explicit.
::gogo->add_conversions(); ::gogo->add_conversions();
......
...@@ -3196,6 +3196,80 @@ Gogo::add_conversions_in_block(Block *b) ...@@ -3196,6 +3196,80 @@ Gogo::add_conversions_in_block(Block *b)
b->traverse(&add_conversions); b->traverse(&add_conversions);
} }
// Traversal class for simple deadcode elimination.
class Remove_deadcode : public Traverse
{
public:
Remove_deadcode()
: Traverse(traverse_statements
| traverse_expressions)
{ }
int
statement(Block*, size_t* pindex, Statement*);
int
expression(Expression**);
};
// Remove deadcode in a statement.
int
Remove_deadcode::statement(Block* block, size_t* pindex, Statement* sorig)
{
Location loc = sorig->location();
If_statement* ifs = sorig->if_statement();
if (ifs != NULL)
{
// Remove the dead branch of an if statement.
bool bval;
if (ifs->condition()->boolean_constant_value(&bval))
{
Statement* s;
if (bval)
s = Statement::make_block_statement(ifs->then_block(),
loc);
else
if (ifs->else_block() != NULL)
s = Statement::make_block_statement(ifs->else_block(),
loc);
else
// Make a dummy statement.
s = Statement::make_statement(Expression::make_boolean(false, loc),
true);
block->replace_statement(*pindex, s);
}
}
return TRAVERSE_CONTINUE;
}
// Remove deadcode in an expression.
int
Remove_deadcode::expression(Expression** pexpr)
{
// Discard the right arm of a shortcut expression of constant value.
Binary_expression* be = (*pexpr)->binary_expression();
bool bval;
if (be != NULL
&& be->boolean_constant_value(&bval)
&& (be->op() == OPERATOR_ANDAND
|| be->op() == OPERATOR_OROR))
*pexpr = Expression::make_boolean(bval, be->location());
return TRAVERSE_CONTINUE;
}
// Remove deadcode.
void
Gogo::remove_deadcode()
{
Remove_deadcode remove_deadcode;
this->traverse(&remove_deadcode);
}
// Traverse the tree to create function descriptors as needed. // Traverse the tree to create function descriptors as needed.
class Create_function_descriptors : public Traverse class Create_function_descriptors : public Traverse
......
...@@ -688,6 +688,10 @@ class Gogo ...@@ -688,6 +688,10 @@ class Gogo
void void
check_return_statements(); check_return_statements();
// Remove deadcode.
void
remove_deadcode();
// Make implicit type conversions explicit. // Make implicit type conversions explicit.
void void
add_conversions(); add_conversions();
......
...@@ -1521,6 +1521,14 @@ class If_statement : public Statement ...@@ -1521,6 +1521,14 @@ class If_statement : public Statement
condition() const condition() const
{ return this->cond_; } { return this->cond_; }
Block*
then_block() const
{ return this->then_block_; }
Block*
else_block() const
{ return this->else_block_; }
protected: protected:
int int
do_traverse(Traverse*); do_traverse(Traverse*);
......
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