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
merge done from the gofrontend repository.
......@@ -1764,6 +1764,13 @@ class Boolean_expression : public Expression
{ return this->val_ == false; }
bool
do_boolean_constant_value(bool* val) const
{
*val = this->val_;
return true;
}
bool
do_is_static_initializer() const
{ return true; }
......@@ -3132,6 +3139,9 @@ class Const_expression : public Expression
bool
do_string_constant_value(std::string* val) const;
bool
do_boolean_constant_value(bool* val) const;
Type*
do_type();
......@@ -3250,6 +3260,21 @@ Const_expression::do_string_constant_value(std::string* val) const
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.
Type*
......@@ -3841,6 +3866,16 @@ Type_conversion_expression::do_string_constant_value(std::string* val) const
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.
void
......@@ -4710,6 +4745,20 @@ Unary_expression::do_numeric_constant_value(Numeric_constant* nc) const
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.
Type*
......@@ -6187,6 +6236,86 @@ Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const
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.
bool
......
......@@ -581,6 +581,12 @@ class Expression
string_constant_value(std::string* val) const
{ 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
// discarded. This issues warnings about computed values being
// unused. This returns true if all is well, false if it issued an
......@@ -1125,6 +1131,12 @@ class Expression
do_string_constant_value(std::string*) const
{ 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.
virtual bool
do_discarding_value();
......@@ -1771,6 +1783,9 @@ class Type_conversion_expression : public Expression
bool
do_string_constant_value(std::string*) const;
bool
do_boolean_constant_value(bool*) const;
Type*
do_type()
{ return this->type_; }
......@@ -1965,6 +1980,9 @@ class Unary_expression : public Expression
bool
do_numeric_constant_value(Numeric_constant*) const;
bool
do_boolean_constant_value(bool*) const;
Type*
do_type();
......@@ -2120,6 +2138,9 @@ class Binary_expression : public Expression
do_numeric_constant_value(Numeric_constant*) const;
bool
do_boolean_constant_value(bool*) const;
bool
do_discarding_value();
Type*
......
......@@ -142,6 +142,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
if (only_check_syntax)
return;
// Do simple deadcode elimination.
::gogo->remove_deadcode();
// Make implicit type conversions explicit.
::gogo->add_conversions();
......
......@@ -3196,6 +3196,80 @@ Gogo::add_conversions_in_block(Block *b)
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.
class Create_function_descriptors : public Traverse
......
......@@ -688,6 +688,10 @@ class Gogo
void
check_return_statements();
// Remove deadcode.
void
remove_deadcode();
// Make implicit type conversions explicit.
void
add_conversions();
......
......@@ -1521,6 +1521,14 @@ class If_statement : public Statement
condition() const
{ return this->cond_; }
Block*
then_block() const
{ return this->then_block_; }
Block*
else_block() const
{ return this->else_block_; }
protected:
int
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