mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Only analyze memory in DataFlowAnalyzer if it is needed in the optimizer step.
This commit is contained in:
parent
e7c5f04464
commit
c12d151834
@ -48,7 +48,7 @@ CommonSubexpressionEliminator::CommonSubexpressionEliminator(
|
||||
Dialect const& _dialect,
|
||||
map<YulString, SideEffects> _functionSideEffects
|
||||
):
|
||||
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects))
|
||||
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore, std::move(_functionSideEffects))
|
||||
{
|
||||
}
|
||||
|
||||
|
@ -44,47 +44,54 @@ using namespace solidity::yul;
|
||||
|
||||
DataFlowAnalyzer::DataFlowAnalyzer(
|
||||
Dialect const& _dialect,
|
||||
MemoryAndStorage _analyzeStores,
|
||||
map<YulString, SideEffects> _functionSideEffects
|
||||
):
|
||||
m_dialect(_dialect),
|
||||
m_functionSideEffects(std::move(_functionSideEffects)),
|
||||
m_knowledgeBase(_dialect, [this](YulString _var) { return variableValue(_var); })
|
||||
m_knowledgeBase(_dialect, [this](YulString _var) { return variableValue(_var); }),
|
||||
m_analyzeStores(_analyzeStores == MemoryAndStorage::Analyze)
|
||||
{
|
||||
if (auto const* builtin = _dialect.memoryStoreFunction(YulString{}))
|
||||
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
|
||||
if (auto const* builtin = _dialect.memoryLoadFunction(YulString{}))
|
||||
m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
|
||||
if (auto const* builtin = _dialect.storageStoreFunction(YulString{}))
|
||||
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Storage)] = builtin->name;
|
||||
if (auto const* builtin = _dialect.storageLoadFunction(YulString{}))
|
||||
m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Storage)] = builtin->name;
|
||||
if (m_analyzeStores)
|
||||
{
|
||||
if (auto const* builtin = _dialect.memoryStoreFunction(YulString{}))
|
||||
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
|
||||
if (auto const* builtin = _dialect.memoryLoadFunction(YulString{}))
|
||||
m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Memory)] = builtin->name;
|
||||
if (auto const* builtin = _dialect.storageStoreFunction(YulString{}))
|
||||
m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Storage)] = builtin->name;
|
||||
if (auto const* builtin = _dialect.storageLoadFunction(YulString{}))
|
||||
m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Storage)] = builtin->name;
|
||||
}
|
||||
}
|
||||
|
||||
void DataFlowAnalyzer::operator()(ExpressionStatement& _statement)
|
||||
{
|
||||
if (auto vars = isSimpleStore(StoreLoadLocation::Storage, _statement))
|
||||
if (m_analyzeStores)
|
||||
{
|
||||
ASTModifier::operator()(_statement);
|
||||
cxx20::erase_if(m_state.storage, mapTuple([&](auto&& key, auto&& value) {
|
||||
return
|
||||
!m_knowledgeBase.knownToBeDifferent(vars->first, key) &&
|
||||
!m_knowledgeBase.knownToBeEqual(vars->second, value);
|
||||
}));
|
||||
m_state.storage[vars->first] = vars->second;
|
||||
}
|
||||
else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, _statement))
|
||||
{
|
||||
ASTModifier::operator()(_statement);
|
||||
cxx20::erase_if(m_state.memory, mapTuple([&](auto&& key, auto&& /* value */) {
|
||||
return !m_knowledgeBase.knownToBeDifferentByAtLeast32(vars->first, key);
|
||||
}));
|
||||
m_state.memory[vars->first] = vars->second;
|
||||
}
|
||||
else
|
||||
{
|
||||
clearKnowledgeIfInvalidated(_statement.expression);
|
||||
ASTModifier::operator()(_statement);
|
||||
if (auto vars = isSimpleStore(StoreLoadLocation::Storage, _statement))
|
||||
{
|
||||
ASTModifier::operator()(_statement);
|
||||
cxx20::erase_if(m_state.storage, mapTuple([&](auto&& key, auto&& value) {
|
||||
return
|
||||
!m_knowledgeBase.knownToBeDifferent(vars->first, key) &&
|
||||
!m_knowledgeBase.knownToBeEqual(vars->second, value);
|
||||
}));
|
||||
m_state.storage[vars->first] = vars->second;
|
||||
return;
|
||||
}
|
||||
else if (auto vars = isSimpleStore(StoreLoadLocation::Memory, _statement))
|
||||
{
|
||||
ASTModifier::operator()(_statement);
|
||||
cxx20::erase_if(m_state.memory, mapTuple([&](auto&& key, auto&& /* value */) {
|
||||
return !m_knowledgeBase.knownToBeDifferentByAtLeast32(vars->first, key);
|
||||
}));
|
||||
m_state.memory[vars->first] = vars->second;
|
||||
return;
|
||||
}
|
||||
}
|
||||
clearKnowledgeIfInvalidated(_statement.expression);
|
||||
ASTModifier::operator()(_statement);
|
||||
}
|
||||
|
||||
void DataFlowAnalyzer::operator()(Assignment& _assignment)
|
||||
@ -346,6 +353,8 @@ void DataFlowAnalyzer::assignValue(YulString _variable, Expression const* _value
|
||||
|
||||
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
|
||||
{
|
||||
if (!m_analyzeStores)
|
||||
return;
|
||||
SideEffectsCollector sideEffects(m_dialect, _block, &m_functionSideEffects);
|
||||
if (sideEffects.invalidatesStorage())
|
||||
m_state.storage.clear();
|
||||
@ -355,6 +364,8 @@ void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Block const& _block)
|
||||
|
||||
void DataFlowAnalyzer::clearKnowledgeIfInvalidated(Expression const& _expr)
|
||||
{
|
||||
if (!m_analyzeStores)
|
||||
return;
|
||||
SideEffectsCollector sideEffects(m_dialect, _expr, &m_functionSideEffects);
|
||||
if (sideEffects.invalidatesStorage())
|
||||
m_state.storage.clear();
|
||||
@ -367,6 +378,8 @@ void DataFlowAnalyzer::joinKnowledge(
|
||||
unordered_map<YulString, YulString> const& _olderMemory
|
||||
)
|
||||
{
|
||||
if (!m_analyzeStores)
|
||||
return;
|
||||
joinKnowledgeHelper(m_state.storage, _olderStorage);
|
||||
joinKnowledgeHelper(m_state.memory, _olderMemory);
|
||||
}
|
||||
|
@ -81,12 +81,14 @@ struct AssignedValue
|
||||
class DataFlowAnalyzer: public ASTModifier
|
||||
{
|
||||
public:
|
||||
enum class MemoryAndStorage { Analyze, Ignore };
|
||||
/// @param _functionSideEffects
|
||||
/// Side-effects of user-defined functions. Worst-case side-effects are assumed
|
||||
/// if this is not provided or the function is not found.
|
||||
/// The parameter is mostly used to determine movability of expressions.
|
||||
explicit DataFlowAnalyzer(
|
||||
Dialect const& _dialect,
|
||||
MemoryAndStorage _analyzeStores,
|
||||
std::map<YulString, SideEffects> _functionSideEffects = {}
|
||||
);
|
||||
|
||||
@ -189,6 +191,8 @@ private:
|
||||
protected:
|
||||
KnowledgeBase m_knowledgeBase;
|
||||
|
||||
/// If true, analyzes memory and storage content via mload/mstore and sload/sstore.
|
||||
bool m_analyzeStores = true;
|
||||
YulString m_storeFunctionName[static_cast<unsigned>(StoreLoadLocation::Last) + 1];
|
||||
YulString m_loadFunctionName[static_cast<unsigned>(StoreLoadLocation::Last) + 1];
|
||||
|
||||
|
@ -47,7 +47,7 @@ private:
|
||||
Dialect const& _dialect,
|
||||
std::map<YulString, SideEffects> _functionSideEffects
|
||||
):
|
||||
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects))
|
||||
DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects))
|
||||
{}
|
||||
|
||||
protected:
|
||||
|
@ -51,7 +51,9 @@ public:
|
||||
void visit(Expression& _expression) override;
|
||||
|
||||
private:
|
||||
explicit ExpressionSimplifier(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
|
||||
explicit ExpressionSimplifier(Dialect const& _dialect):
|
||||
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore)
|
||||
{}
|
||||
};
|
||||
|
||||
}
|
||||
|
@ -53,7 +53,7 @@ private:
|
||||
bool _containsMSize,
|
||||
std::optional<size_t> _expectedExecutionsPerDeployment
|
||||
):
|
||||
DataFlowAnalyzer(_dialect, std::move(_functionSideEffects)),
|
||||
DataFlowAnalyzer(_dialect, MemoryAndStorage::Analyze, std::move(_functionSideEffects)),
|
||||
m_containsMSize(_containsMSize),
|
||||
m_expectedExecutionsPerDeployment(std::move(_expectedExecutionsPerDeployment))
|
||||
{}
|
||||
|
@ -43,7 +43,7 @@ Rematerialiser::Rematerialiser(
|
||||
set<YulString> _varsToAlwaysRematerialize,
|
||||
bool _onlySelectedVariables
|
||||
):
|
||||
DataFlowAnalyzer(_dialect),
|
||||
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore),
|
||||
m_referenceCounts(ReferencesCounter::countReferences(_ast)),
|
||||
m_varsToAlwaysRematerialize(std::move(_varsToAlwaysRematerialize)),
|
||||
m_onlySelectedVariables(_onlySelectedVariables)
|
||||
|
@ -95,7 +95,7 @@ public:
|
||||
|
||||
private:
|
||||
LiteralRematerialiser(Dialect const& _dialect):
|
||||
DataFlowAnalyzer(_dialect)
|
||||
DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore)
|
||||
{}
|
||||
};
|
||||
|
||||
|
@ -56,7 +56,7 @@ namespace
|
||||
class RematCandidateSelector: public DataFlowAnalyzer
|
||||
{
|
||||
public:
|
||||
explicit RematCandidateSelector(Dialect const& _dialect): DataFlowAnalyzer(_dialect) {}
|
||||
explicit RematCandidateSelector(Dialect const& _dialect): DataFlowAnalyzer(_dialect, MemoryAndStorage::Ignore) {}
|
||||
|
||||
/// @returns a map from function name to rematerialisation costs to a vector of variables to rematerialise
|
||||
/// and variables that occur in their expression.
|
||||
|
Loading…
Reference in New Issue
Block a user