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;
|
||||||
using namespace solidity::yul;
|
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)
|
bool KnowledgeBase::knownToBeDifferent(YulString _a, YulString _b)
|
||||||
{
|
{
|
||||||
if (optional<u256> difference = differenceIfKnownConstant(_a, _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)
|
KnowledgeBase::VariableOffset KnowledgeBase::explore(YulString _var)
|
||||||
{
|
{
|
||||||
// We query the value first so that the variable is reset if it has changed
|
Expression const* value = nullptr;
|
||||||
// since the last call.
|
if (m_valuesAreSSA)
|
||||||
Expression const* value = valueOf(_var);
|
{
|
||||||
if (VariableOffset const* varOff = util::valueOrNullptr(m_offsets, _var))
|
// In SSA, a once determined offset is always valid, so we first see
|
||||||
return *varOff;
|
// 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 (value)
|
||||||
if (optional<VariableOffset> offset = explore(*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* KnowledgeBase::valueOf(YulString _var)
|
||||||
{
|
{
|
||||||
Expression const* lastValue = m_lastKnownValue[_var];
|
|
||||||
AssignedValue const* assignedValue = m_variableValues(_var);
|
AssignedValue const* assignedValue = m_variableValues(_var);
|
||||||
Expression const* currentValue = assignedValue ? assignedValue->value : nullptr;
|
Expression const* currentValue = assignedValue ? assignedValue->value : nullptr;
|
||||||
|
if (m_valuesAreSSA)
|
||||||
|
return currentValue;
|
||||||
|
|
||||||
|
Expression const* lastValue = m_lastKnownValue[_var];
|
||||||
if (lastValue != currentValue)
|
if (lastValue != currentValue)
|
||||||
reset(_var);
|
reset(_var);
|
||||||
m_lastKnownValue[_var] = currentValue;
|
m_lastKnownValue[_var] = currentValue;
|
||||||
@ -140,6 +160,8 @@ Expression const* KnowledgeBase::valueOf(YulString _var)
|
|||||||
|
|
||||||
void KnowledgeBase::reset(YulString _var)
|
void KnowledgeBase::reset(YulString _var)
|
||||||
{
|
{
|
||||||
|
yulAssert(!m_valuesAreSSA);
|
||||||
|
|
||||||
m_lastKnownValue.erase(_var);
|
m_lastKnownValue.erase(_var);
|
||||||
if (VariableOffset const* offset = util::valueOrNullptr(m_offsets, _var))
|
if (VariableOffset const* offset = util::valueOrNullptr(m_offsets, _var))
|
||||||
{
|
{
|
||||||
|
@ -47,6 +47,9 @@ struct AssignedValue;
|
|||||||
* form.
|
* form.
|
||||||
* The only requirement is that the assigned values are movable expressions.
|
* 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
|
* Internally, tries to find groups of variables that have a mutual constant
|
||||||
* difference and stores these differences always relative to a specific
|
* difference and stores these differences always relative to a specific
|
||||||
* representative variable of the group.
|
* representative variable of the group.
|
||||||
@ -57,9 +60,13 @@ struct AssignedValue;
|
|||||||
class KnowledgeBase
|
class KnowledgeBase
|
||||||
{
|
{
|
||||||
public:
|
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):
|
KnowledgeBase(std::function<AssignedValue const*(YulString)> _variableValues):
|
||||||
m_variableValues(std::move(_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);
|
bool knownToBeDifferent(YulString _a, YulString _b);
|
||||||
std::optional<u256> differenceIfKnownConstant(YulString _a, YulString _b);
|
std::optional<u256> differenceIfKnownConstant(YulString _a, YulString _b);
|
||||||
@ -91,6 +98,8 @@ private:
|
|||||||
|
|
||||||
VariableOffset setOffset(YulString _variable, VariableOffset _value);
|
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.
|
/// Callback to retrieve the current value of a variable.
|
||||||
std::function<AssignedValue const*(YulString)> m_variableValues;
|
std::function<AssignedValue const*(YulString)> m_variableValues;
|
||||||
|
|
||||||
|
@ -104,7 +104,7 @@ UnusedStoreEliminator::UnusedStoreEliminator(
|
|||||||
m_functionSideEffects(_functionSideEffects),
|
m_functionSideEffects(_functionSideEffects),
|
||||||
m_controlFlowSideEffects(_controlFlowSideEffects),
|
m_controlFlowSideEffects(_controlFlowSideEffects),
|
||||||
m_ssaValues(_ssaValues),
|
m_ssaValues(_ssaValues),
|
||||||
m_knowledgeBase([this](YulString _var) { return util::valueOrNullptr(m_ssaValues, _var); })
|
m_knowledgeBase(_ssaValues)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void UnusedStoreEliminator::operator()(FunctionCall const& _functionCall)
|
void UnusedStoreEliminator::operator()(FunctionCall const& _functionCall)
|
||||||
|
Loading…
Reference in New Issue
Block a user