diff options
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 129 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 21 | ||||
-rw-r--r-- | gcc/go/gofrontend/go.cc | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 74 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 8 |
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*); |