Introduce LiteralRematerializer and thus simplify StructuralSimplifier.

This commit is contained in:
chriseth
2019-09-11 19:50:24 +02:00
parent a064e0fc97
commit fcfe829534
10 changed files with 152 additions and 145 deletions
+19 -2
View File
@@ -71,9 +71,9 @@ void Rematerialiser::visit(Expression& _e)
if (_e.type() == typeid(Identifier))
{
Identifier& identifier = boost::get<Identifier>(_e);
if (m_value.count(identifier.name))
YulString name = identifier.name;
if (m_value.count(name))
{
YulString name = identifier.name;
assertThrow(m_value.at(name), OptimizerException, "");
auto const& value = *m_value.at(name);
size_t refs = m_referenceCounts[name];
@@ -93,3 +93,20 @@ void Rematerialiser::visit(Expression& _e)
}
DataFlowAnalyzer::visit(_e);
}
void LiteralRematerialiser::visit(Expression& _e)
{
if (_e.type() == typeid(Identifier))
{
Identifier& identifier = boost::get<Identifier>(_e);
YulString name = identifier.name;
if (m_value.count(name))
{
Expression const* value = m_value.at(name);
assertThrow(value, OptimizerException, "");
if (value->type() == typeid(Literal))
_e = *value;
}
}
DataFlowAnalyzer::visit(_e);
}
+21
View File
@@ -68,4 +68,25 @@ protected:
std::set<YulString> m_varsToAlwaysRematerialize;
};
/**
* If a variable is referenced that is known to have a literal
* value at that point, replace it by a literal.
*
* This is mostly used so that other components do not have to rely
* on the data flow analyzer.
*
* Prerequisite: Disambiguator, ForLoopInitRewriter.
*/
class LiteralRematerialiser: public DataFlowAnalyzer
{
public:
LiteralRematerialiser(Dialect const& _dialect):
DataFlowAnalyzer(_dialect)
{}
using ASTModifier::visit;
void visit(Expression& _e) override;
};
}
+16 -48
View File
@@ -61,29 +61,7 @@ OptionalStatements replaceConstArgSwitch(Switch& _switchStmt, u256 const& _const
void StructuralSimplifier::operator()(Block& _block)
{
pushScope(false);
simplify(_block.statements);
popScope();
}
boost::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const
{
Expression const* expr = &_expression;
if (expr->type() == typeid(Identifier))
{
Identifier const& ident = boost::get<Identifier>(*expr);
if (m_value.count(ident.name))
expr = m_value.at(ident.name);
}
if (expr && expr->type() == typeid(Literal))
{
Literal const& literal = boost::get<Literal>(*expr);
return valueOfLiteral(literal);
}
return boost::optional<u256>();
}
void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
@@ -124,34 +102,24 @@ void StructuralSimplifier::simplify(std::vector<yul::Statement>& _statements)
bool StructuralSimplifier::expressionAlwaysTrue(Expression const& _expression)
{
return boost::apply_visitor(GenericFallbackReturnsVisitor<bool, Identifier const, Literal const>(
[&](Identifier const& _identifier) -> bool {
if (auto expr = m_value[_identifier.name])
return expressionAlwaysTrue(*expr);
return false;
},
[](Literal const& _literal) -> bool {
return
(_literal.kind == LiteralKind::Boolean && _literal.value == "true"_yulstring) ||
(_literal.kind == LiteralKind::Number && valueOfNumberLiteral(_literal) != u256(0))
;
}
), _expression);
if (boost::optional<u256> value = hasLiteralValue(_expression))
return *value != 0;
else
return false;
}
bool StructuralSimplifier::expressionAlwaysFalse(Expression const& _expression)
{
return boost::apply_visitor(GenericFallbackReturnsVisitor<bool, Identifier const, Literal const>(
[&](Identifier const& _identifier) -> bool {
if (auto expr = m_value[_identifier.name])
return expressionAlwaysFalse(*expr);
return false;
},
[](Literal const& _literal) -> bool {
return
(_literal.kind == LiteralKind::Boolean && _literal.value == "false"_yulstring) ||
(_literal.kind == LiteralKind::Number && valueOfNumberLiteral(_literal) == u256(0))
;
}
), _expression);
if (boost::optional<u256> value = hasLiteralValue(_expression))
return *value == 0;
else
return false;
}
boost::optional<dev::u256> StructuralSimplifier::hasLiteralValue(Expression const& _expression) const
{
if (_expression.type() == typeid(Literal))
return valueOfLiteral(boost::get<Literal>(_expression));
else
return boost::optional<u256>();
}
+5 -5
View File
@@ -30,16 +30,16 @@ namespace yul
* - replace switch with const expr with matching case body
* - replace for with false condition by its initialization part
*
* Prerequisite: Disambiguator, ForLoopInitRewriter.
* The LiteralRematerialiser should be run before this.
*
* Prerequisite: Disambiguator.
*
* Important: Can only be used on EVM code.
*/
class StructuralSimplifier: public DataFlowAnalyzer
class StructuralSimplifier: public ASTModifier
{
public:
explicit StructuralSimplifier(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
using DataFlowAnalyzer::operator();
using ASTModifier::operator();
void operator()(Block& _block) override;
private:
void simplify(std::vector<Statement>& _statements);
+6 -3
View File
@@ -91,7 +91,8 @@ void OptimiserSuite::run(
UnusedPruner::runUntilStabilisedOnFullAST(_dialect, ast, reservedIdentifiers);
BlockFlattener{}(ast);
ControlFlowSimplifier{_dialect}(ast);
StructuralSimplifier{_dialect}(ast);
LiteralRematerialiser{_dialect}(ast);
StructuralSimplifier{}(ast);
ControlFlowSimplifier{_dialect}(ast);
BlockFlattener{}(ast);
@@ -125,7 +126,8 @@ void OptimiserSuite::run(
{
// still in SSA, perform structural simplification
ControlFlowSimplifier{_dialect}(ast);
StructuralSimplifier{_dialect}(ast);
LiteralRematerialiser{_dialect}(ast);
StructuralSimplifier{}(ast);
ControlFlowSimplifier{_dialect}(ast);
BlockFlattener{}(ast);
DeadCodeEliminator{_dialect}(ast);
@@ -182,7 +184,8 @@ void OptimiserSuite::run(
RedundantAssignEliminator::run(_dialect, ast);
LoadResolver::run(_dialect, ast);
ExpressionSimplifier::run(_dialect, ast);
StructuralSimplifier{_dialect}(ast);
LiteralRematerialiser{_dialect}(ast);
StructuralSimplifier{}(ast);
BlockFlattener{}(ast);
DeadCodeEliminator{_dialect}(ast);
ControlFlowSimplifier{_dialect}(ast);