compiler: do simple deadcode elimination
authorIan Lance Taylor <ian@gcc.gnu.org>
Fri, 7 Jun 2019 13:40:26 +0000 (13:40 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Fri, 7 Jun 2019 13:40:26 +0000 (13:40 +0000)
    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

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/go.cc
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/statements.h

index 7f687c8cc00c9cafa45be5b845289656f90cb59b..428b59a08fedaff5b8dbef71c6b5a45b79e135b9 100644 (file)
@@ -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.
index 273c8f074c790ad217b67776d6556a5c8e027e2d..3481d0008682bb4751f24d2c23e71bd40e830eab 100644 (file)
@@ -1763,6 +1763,13 @@ class Boolean_expression : public Expression
   do_is_zero_value() const
   { 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
index 09c71adbd315bfa04b0f08c3de9a27013a0a6da5..6ba7fe1ee7cfd0f6946391e9a9b0265d57bb0167 100644 (file)
@@ -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();
 
@@ -2119,6 +2137,9 @@ class Binary_expression : public Expression
   bool
   do_numeric_constant_value(Numeric_constant*) const;
 
+  bool
+  do_boolean_constant_value(bool*) const;
+
   bool
   do_discarding_value();
 
index 5106e8d043464109615f2d5961143e89f23c4368..23acaa54f5636ce0c6be9214bafe2463647b27b1 100644 (file)
@@ -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();
 
index 6e8ccbba226a3e611d22a5aa31d3e18947f6cc6d..480077823d1ade7e92b3c628cb3ba8261c83cbb7 100644 (file)
@@ -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
index 11974764c4ef63dee7c3b0469b6ab5824306dd37..7f0cfc52ae7b2a718b18d9a951ea704ad63a3ea1 100644 (file)
@@ -688,6 +688,10 @@ class Gogo
   void
   check_return_statements();
 
+  // Remove deadcode.
+  void
+  remove_deadcode();
+
   // Make implicit type conversions explicit.
   void
   add_conversions();
index bb7150164338e9c4c84b0ad8c75f3ef51c6030e9..3743d44bb4362eeef7f8646c9779a1b3cc334050 100644 (file)
@@ -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*);