Properly assign types in control flow simplifier.

This commit is contained in:
chriseth 2020-02-19 00:36:50 +01:00
parent e728cd76b6
commit e75cace78d
2 changed files with 73 additions and 60 deletions

View File

@ -17,6 +17,7 @@
#include <libyul/optimiser/ControlFlowSimplifier.h>
#include <libyul/optimiser/Semantics.h>
#include <libyul/optimiser/OptimiserStep.h>
#include <libyul/optimiser/TypeInfo.h>
#include <libyul/AsmData.h>
#include <libyul/Utilities.h>
#include <libyul/Dialect.h>
@ -38,14 +39,13 @@ namespace
ExpressionStatement makeDiscardCall(
langutil::SourceLocation const& _location,
Dialect const& _dialect,
BuiltinFunction const& _discardFunction,
Expression&& _expression
)
{
yulAssert(_dialect.discardFunction(), "No discard function available.");
return {_location, FunctionCall{
_location,
Identifier{_location, _dialect.discardFunction()->name},
Identifier{_location, _discardFunction.name},
{std::move(_expression)}
}};
}
@ -74,62 +74,12 @@ void removeEmptyCasesFromSwitch(Switch& _switchStmt)
);
}
OptionalStatements reduceNoCaseSwitch(Dialect const& _dialect, Switch& _switchStmt)
{
yulAssert(_switchStmt.cases.empty(), "Expected no case!");
if (!_dialect.discardFunction())
return {};
auto loc = locationOf(*_switchStmt.expression);
return make_vector<Statement>(makeDiscardCall(
loc,
_dialect,
std::move(*_switchStmt.expression)
));
}
OptionalStatements reduceSingleCaseSwitch(Dialect const& _dialect, Switch& _switchStmt)
{
yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!");
auto& switchCase = _switchStmt.cases.front();
auto loc = locationOf(*_switchStmt.expression);
if (switchCase.value)
{
if (!_dialect.equalityFunction())
return {};
return make_vector<Statement>(If{
std::move(_switchStmt.location),
make_unique<Expression>(FunctionCall{
loc,
Identifier{loc, _dialect.equalityFunction()->name},
{std::move(*switchCase.value), std::move(*_switchStmt.expression)}
}),
std::move(switchCase.body)
});
}
else
{
if (!_dialect.discardFunction())
return {};
return make_vector<Statement>(
makeDiscardCall(
loc,
_dialect,
std::move(*_switchStmt.expression)
),
std::move(switchCase.body)
);
}
}
}
void ControlFlowSimplifier::run(OptimiserStepContext& _context, Block& _ast)
{
ControlFlowSimplifier{_context.dialect}(_ast);
TypeInfo typeInfo(_context.dialect, _ast);
ControlFlowSimplifier{_context.dialect, typeInfo}(_ast);
}
void ControlFlowSimplifier::operator()(Block& _block)
@ -194,12 +144,12 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
GenericVisitor visitor{
VisitorFallback<OptionalStatements>{},
[&](If& _ifStmt) -> OptionalStatements {
if (_ifStmt.body.statements.empty() && m_dialect.discardFunction())
if (_ifStmt.body.statements.empty() && m_dialect.discardFunction(m_dialect.boolType))
{
OptionalStatements s = vector<Statement>{};
s->emplace_back(makeDiscardCall(
_ifStmt.location,
m_dialect,
*m_dialect.discardFunction(m_dialect.boolType),
std::move(*_ifStmt.condition)
));
return s;
@ -211,9 +161,9 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
removeEmptyCasesFromSwitch(_switchStmt);
if (_switchStmt.cases.empty())
return reduceNoCaseSwitch(m_dialect, _switchStmt);
return reduceNoCaseSwitch(_switchStmt);
else if (_switchStmt.cases.size() == 1)
return reduceSingleCaseSwitch(m_dialect, _switchStmt);
return reduceSingleCaseSwitch(_switchStmt);
return {};
}
@ -231,3 +181,58 @@ void ControlFlowSimplifier::simplify(std::vector<yul::Statement>& _statements)
}
);
}
OptionalStatements ControlFlowSimplifier::reduceNoCaseSwitch(Switch& _switchStmt) const
{
yulAssert(_switchStmt.cases.empty(), "Expected no case!");
BuiltinFunction const* discardFunction =
m_dialect.discardFunction(m_typeInfo.typeOf(*_switchStmt.expression));
if (!discardFunction)
return {};
auto loc = locationOf(*_switchStmt.expression);
return make_vector<Statement>(makeDiscardCall(
loc,
*discardFunction,
std::move(*_switchStmt.expression)
));
}
OptionalStatements ControlFlowSimplifier::reduceSingleCaseSwitch(Switch& _switchStmt) const
{
yulAssert(_switchStmt.cases.size() == 1, "Expected only one case!");
auto& switchCase = _switchStmt.cases.front();
auto loc = locationOf(*_switchStmt.expression);
YulString type = m_typeInfo.typeOf(*_switchStmt.expression);
if (switchCase.value)
{
if (!m_dialect.equalityFunction(type))
return {};
return make_vector<Statement>(If{
std::move(_switchStmt.location),
make_unique<Expression>(FunctionCall{
loc,
Identifier{loc, m_dialect.equalityFunction(type)->name},
{std::move(*switchCase.value), std::move(*_switchStmt.expression)}
}),
std::move(switchCase.body)
});
}
else
{
if (!m_dialect.discardFunction(type))
return {};
return make_vector<Statement>(
makeDiscardCall(
loc,
*m_dialect.discardFunction(type),
std::move(*_switchStmt.expression)
),
std::move(switchCase.body)
);
}
}

View File

@ -23,6 +23,7 @@ namespace solidity::yul
{
struct Dialect;
struct OptimiserStepContext;
class TypeInfo;
/**
* Simplifies several control-flow structures:
@ -61,11 +62,18 @@ public:
void visit(Statement& _st) override;
private:
ControlFlowSimplifier(Dialect const& _dialect): m_dialect(_dialect) {}
ControlFlowSimplifier(Dialect const& _dialect, TypeInfo const& _typeInfo):
m_dialect(_dialect),
m_typeInfo(_typeInfo)
{}
void simplify(std::vector<Statement>& _statements);
std::optional<std::vector<Statement>> reduceNoCaseSwitch(Switch& _switchStmt) const;
std::optional<std::vector<Statement>> reduceSingleCaseSwitch(Switch& _switchStmt) const;
Dialect const& m_dialect;
TypeInfo const& m_typeInfo;
size_t m_numBreakStatements = 0;
size_t m_numContinueStatements = 0;
};