diff mbox series

Go patch committed: Do simple deadcode elimination

Message ID CAOyqgcXFKngFzAbKohWRrWeEQzSg7QCpn1hcvz2DXbZyehyLVw@mail.gmail.com
State New
Headers show
Series Go patch committed: Do simple deadcode elimination | expand

Commit Message

Ian Lance Taylor June 7, 2019, 1:40 p.m. UTC
This patch by Cherry Zhang adds simple deadcode elimination to the Go
frontend.  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 patch adds a simple deadcode elimination, run before the
escape analysis.  Bootstrapped and ran Go testsuite on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian
diff mbox series

Patch

Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE	(revision 272023)
+++ gcc/go/gofrontend/MERGE	(working copy)
@@ -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: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc	(revision 272022)
+++ gcc/go/gofrontend/expressions.cc	(working copy)
@@ -1764,6 +1764,13 @@  class Boolean_expression : public Expres
   { 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 Expressi
   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_val
   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_co
   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_va
 					 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_v
 					  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: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h	(revision 272022)
+++ gcc/go/gofrontend/expressions.h	(working copy)
@@ -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 : publi
   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 Expressi
   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 Express
   do_numeric_constant_value(Numeric_constant*) const;
 
   bool
+  do_boolean_constant_value(bool*) const;
+
+  bool
   do_discarding_value();
 
   Type*
Index: gcc/go/gofrontend/go.cc
===================================================================
--- gcc/go/gofrontend/go.cc	(revision 271669)
+++ gcc/go/gofrontend/go.cc	(working copy)
@@ -142,6 +142,9 @@  go_parse_input_files(const char** filena
   if (only_check_syntax)
     return;
 
+  // Do simple deadcode elimination.
+  ::gogo->remove_deadcode();
+
   // Make implicit type conversions explicit.
   ::gogo->add_conversions();
 
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc	(revision 271976)
+++ gcc/go/gofrontend/gogo.cc	(working copy)
@@ -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: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h	(revision 271976)
+++ gcc/go/gofrontend/gogo.h	(working copy)
@@ -688,6 +688,10 @@  class Gogo
   void
   check_return_statements();
 
+  // Remove deadcode.
+  void
+  remove_deadcode();
+
   // Make implicit type conversions explicit.
   void
   add_conversions();
Index: gcc/go/gofrontend/statements.h
===================================================================
--- gcc/go/gofrontend/statements.h	(revision 272022)
+++ gcc/go/gofrontend/statements.h	(working copy)
@@ -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*);