mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Optimize in case this is SSA.
This commit is contained in:
parent
96e2a6d3fe
commit
6bbef64034
@ -33,6 +33,11 @@ using namespace std;
|
||||
using namespace solidity;
|
||||
using namespace solidity::yul;
|
||||
|
||||
KnowledgeBase::KnowledgeBase(map<YulString, AssignedValue> const& _ssaValues):
|
||||
m_valuesAreSSA(true),
|
||||
m_variableValues([_ssaValues](YulString _var) { return util::valueOrNullptr(_ssaValues, _var); })
|
||||
{}
|
||||
|
||||
bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b)
|
||||
{
|
||||
if (optional<u256> difference = differenceIfKnownConstant(_a, _b))
|
||||
@ -85,11 +90,23 @@ optional<u256> KnowledgeBase::valueIfKnownConstant(Expression const& _expression
|
||||
|
||||
KnowledgeBase::VariableOffset KnowledgeBase::explore(YulString _var)
|
||||
{
|
||||
// We query the value first so that the variable is reset if it has changed
|
||||
// since the last call.
|
||||
Expression const* value = valueOf(_var);
|
||||
if (VariableOffset const* varOff = util::valueOrNullptr(m_offsets, _var))
|
||||
return *varOff;
|
||||
Expression const* value = nullptr;
|
||||
if (m_valuesAreSSA)
|
||||
{
|
||||
// In SSA, a once determined offset is always valid, so we first see
|
||||
// if we already computed it.
|
||||
if (VariableOffset const* varOff = util::valueOrNullptr(m_offsets, _var))
|
||||
return *varOff;
|
||||
value = valueOf(_var);
|
||||
}
|
||||
else
|
||||
{
|
||||
// For non-SSA, we query the value first so that the variable is reset if it has changed
|
||||
// since the last call.
|
||||
value = valueOf(_var);
|
||||
if (VariableOffset const* varOff = util::valueOrNullptr(m_offsets, _var))
|
||||
return *varOff;
|
||||
}
|
||||
|
||||
if (value)
|
||||
if (optional<VariableOffset> offset = explore(*value))
|
||||
@ -129,9 +146,12 @@ optional<KnowledgeBase::VariableOffset> KnowledgeBase::explore(Expression const&
|
||||
|
||||
Expression const* KnowledgeBase::valueOf(YulString _var)
|
||||
{
|
||||
Expression const* lastValue = m_lastKnownValue[_var];
|
||||
AssignedValue const* assignedValue = m_variableValues(_var);
|
||||
Expression const* currentValue = assignedValue ? assignedValue->value : nullptr;
|
||||
if (m_valuesAreSSA)
|
||||
return currentValue;
|
||||
|
||||
Expression const* lastValue = m_lastKnownValue[_var];
|
||||
if (lastValue != currentValue)
|
||||
reset(_var);
|
||||
m_lastKnownValue[_var] = currentValue;
|
||||
@ -140,6 +160,8 @@ Expression const* KnowledgeBase::valueOf(YulString _var)
|
||||
|
||||
void KnowledgeBase::reset(YulString _var)
|
||||
{
|
||||
yulAssert(!m_valuesAreSSA);
|
||||
|
||||
m_lastKnownValue.erase(_var);
|
||||
if (VariableOffset const* offset = util::valueOrNullptr(m_offsets, _var))
|
||||
{
|
||||
|
@ -47,6 +47,9 @@ struct AssignedValue;
|
||||
* form.
|
||||
* The only requirement is that the assigned values are movable expressions.
|
||||
*
|
||||
* There is a constructor to provide all SSA values right at the beginning.
|
||||
* If you use this, the KnowledgeBase will be slightly more efficient.
|
||||
*
|
||||
* Internally, tries to find groups of variables that have a mutual constant
|
||||
* difference and stores these differences always relative to a specific
|
||||
* representative variable of the group.
|
||||
@ -57,9 +60,13 @@ struct AssignedValue;
|
||||
class KnowledgeBase
|
||||
{
|
||||
public:
|
||||
/// Constructor for arbitrary value callback that allows for variable values
|
||||
/// to change in between calls to functions of this class.
|
||||
KnowledgeBase(std::function<AssignedValue const*(YulString)> _variableValues):
|
||||
m_variableValues(std::move(_variableValues))
|
||||
{}
|
||||
/// Constructor to use if source code is in SSA form and values are constant.
|
||||
KnowledgeBase(std::map<YulString, AssignedValue> const& _ssaValues);
|
||||
|
||||
bool knownToBeDifferent(YulString _a, YulString _b);
|
||||
std::optional<u256> differenceIfKnownConstant(YulString _a, YulString _b);
|
||||
@ -91,6 +98,8 @@ private:
|
||||
|
||||
VariableOffset setOffset(YulString _variable, VariableOffset _value);
|
||||
|
||||
/// If true, we can assume that variable values never change and skip some steps.
|
||||
bool m_valuesAreSSA = false;
|
||||
/// Callback to retrieve the current value of a variable.
|
||||
std::function<AssignedValue const*(YulString)> m_variableValues;
|
||||
|
||||
|
@ -104,7 +104,7 @@ UnusedStoreEliminator::UnusedStoreEliminator(
|
||||
m_functionSideEffects(_functionSideEffects),
|
||||
m_controlFlowSideEffects(_controlFlowSideEffects),
|
||||
m_ssaValues(_ssaValues),
|
||||
m_knowledgeBase([this](YulString _var) { return util::valueOrNullptr(m_ssaValues, _var); })
|
||||
m_knowledgeBase(_ssaValues)
|
||||
{}
|
||||
|
||||
void UnusedStoreEliminator::operator()(FunctionCall const& _functionCall)
|
||||
|
Loading…
Reference in New Issue
Block a user