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