aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIan Lance Taylor <ian@gcc.gnu.org>2019-06-07 13:40:26 +0000
committerIan Lance Taylor <ian@gcc.gnu.org>2019-06-07 13:40:26 +0000
commitab658f56a56ea548b1f293a4a3ada68feb11b417 (patch)
tree41e7bd6de969ae9edea1bea87de7ab39d4829475
parente733243a3693142bd9c9486451c38d2dc20270ac (diff)
downloadgcc-ab658f56a56ea548b1f293a4a3ada68feb11b417.zip
gcc-ab658f56a56ea548b1f293a4a3ada68feb11b417.tar.gz
gcc-ab658f56a56ea548b1f293a4a3ada68feb11b417.tar.bz2
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
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/expressions.cc129
-rw-r--r--gcc/go/gofrontend/expressions.h21
-rw-r--r--gcc/go/gofrontend/go.cc3
-rw-r--r--gcc/go/gofrontend/gogo.cc74
-rw-r--r--gcc/go/gofrontend/gogo.h4
-rw-r--r--gcc/go/gofrontend/statements.h8
7 files changed, 240 insertions, 1 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 7f687c8..428b59a 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-e76c26059585433ce44e50cd7f8f504c6676f453
+46329dd9e6473fff46df6b310c11116d1558e470
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 273c8f0..3481d00 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -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
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 09c71ad..6ba7fe1 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -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*
diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc
index 5106e8d..23acaa5 100644
--- a/gcc/go/gofrontend/go.cc
+++ b/gcc/go/gofrontend/go.cc
@@ -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();
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 6e8ccbb..4800778 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -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
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 1197476..7f0cfc5 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -688,6 +688,10 @@ class Gogo
void
check_return_statements();
+ // Remove deadcode.
+ void
+ remove_deadcode();
+
// Make implicit type conversions explicit.
void
add_conversions();
diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h
index bb71501..3743d44 100644
--- a/gcc/go/gofrontend/statements.h
+++ b/gcc/go/gofrontend/statements.h
@@ -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*);