Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions libyul/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,9 @@ add_library(yul
backends/evm/ssa/StackLayoutGenerator.h
backends/evm/ssa/StackShuffler.cpp
backends/evm/ssa/StackShuffler.h
backends/evm/ssa/StackSlotLiveness.h
backends/evm/ssa/StackToMemorySpilling.h
backends/evm/ssa/util/UseCountSet.h
backends/evm/ssa/StackUtils.cpp
backends/evm/ssa/StackUtils.h
backends/evm/ssa/io/DotExporterBase.cpp
Expand Down
8 changes: 4 additions & 4 deletions libyul/backends/evm/ssa/CodeTransform.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,7 @@ void CodeTransform::operator()(SSACFG::BlockId const _blockId)
yulAssert(shuffleResult.status == StackShufflerResult::Status::Admissible);

// handle the block exit
std::visit(util::GenericVisitor{ [this, &_blockId](auto const& exit) { (*this)(_blockId, exit); } }, block.exit);
std::visit(solidity::util::GenericVisitor{ [this, &_blockId](auto const& exit) { (*this)(_blockId, exit); } }, block.exit);
}

void CodeTransform::operator()(SSACFG::InstId _opId, StackData const& _operationInputLayout)
Expand Down Expand Up @@ -259,7 +259,7 @@ void CodeTransform::operator()(SSACFG::InstId _opId, StackData const& _operation
}();

// generate code for the operation
std::visit(util::GenericVisitor{
std::visit(solidity::util::GenericVisitor{
[&](SSACFG::BuiltinCall const& _builtin) {
m_assembly.setSourceLocation(opOriginLocation);
auto const& builtin = m_cfg.evmDialect.builtin(_builtin.builtin);
Expand All @@ -276,7 +276,7 @@ void CodeTransform::operator()(SSACFG::InstId _opId, StackData const& _operation
builtin.generateCode(transient, m_assembly, m_builtinContext);
},
[&](SSACFG::Call const& _call) {
auto const* returnLabel = util::valueOrNullptr(m_returnLabels, _opId);
auto const* returnLabel = solidity::util::valueOrNullptr(m_returnLabels, _opId);
// check that if we have a return label, the call can continue
yulAssert(!!returnLabel == _call.canContinue);
m_assembly.setSourceLocation(opOriginLocation);
Expand Down Expand Up @@ -394,7 +394,7 @@ void CodeTransform::operator()(SSACFG::BlockId const& _blockId, SSACFG::BasicBlo
yulAssert(static_cast<int>(m_stack.size()) == m_assembly.stackHeight());
auto const& block = m_cfg.block(_blockId);
yulAssert(!block.operations.empty(), "Terminated block must have at least one operation.");
std::visit(util::GenericVisitor{
std::visit(solidity::util::GenericVisitor{
[&](SSACFG::BuiltinCall const& _builtin) {
yulAssert(m_cfg.evmDialect.builtin(_builtin.builtin).controlFlowSideEffects.terminatesOrReverts(), "Last operation of Terminated block must terminate or revert.");
},
Expand Down
112 changes: 2 additions & 110 deletions libyul/backends/evm/ssa/LivenessAnalysis.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

#include <libsolutil/Visitor.h>

#include <range/v3/algorithm/find.hpp>
#include <range/v3/algorithm/find_if.hpp>
#include <range/v3/range/conversion.hpp>

#include <range/v3/view/filter.hpp>
Expand All @@ -33,112 +31,17 @@ namespace
{
constexpr auto excludingLiteralsFilter()
{
return [](LivenessAnalysis::LivenessData::Value const& _valueId) -> bool
return [](SSACFG::ValueId const& _valueId) -> bool
{
return !_valueId.isLiteral();
};
}
}

bool LivenessAnalysis::LivenessData::contains(Value const& _valueId) const
{
return findEntry(_valueId) != m_liveCounts.end();
}

LivenessAnalysis::LivenessData::Count LivenessAnalysis::LivenessData::count(Value const& _valueId) const
{
if (
auto const it = findEntry(_valueId);
it != m_liveCounts.end()
)
return it->second;
return 0;
}

LivenessAnalysis::LivenessData::LiveCounts::const_iterator LivenessAnalysis::LivenessData::begin() const
{
return m_liveCounts.begin();
}

LivenessAnalysis::LivenessData::LiveCounts::const_iterator LivenessAnalysis::LivenessData::end() const
{
return m_liveCounts.end();
}

LivenessAnalysis::LivenessData::LiveCounts::size_type LivenessAnalysis::LivenessData::size() const
{
return m_liveCounts.size();
}

bool LivenessAnalysis::LivenessData::empty() const { return m_liveCounts.empty(); }

void LivenessAnalysis::LivenessData::insert(Value const& _value, Count _count)
{
if (_count == 0)
return;

auto it = findEntry(_value);
if (it != m_liveCounts.end())
it->second += _count;
else
m_liveCounts.emplace_back(_value, _count);
}

LivenessAnalysis::LivenessData& LivenessAnalysis::LivenessData::maxUnion(LivenessData const& _other)
{
for (auto const& [value, count]: _other.m_liveCounts)
{
auto it = findEntry(value);
if (it != m_liveCounts.end())
it->second = std::max(it->second, count);
else
m_liveCounts.emplace_back(value, count);
}
return *this;
}

LivenessAnalysis::LivenessData& LivenessAnalysis::LivenessData::operator+=(LivenessData const& _other)
{
for (auto const& [valueId, count]: _other.m_liveCounts)
insert(valueId, count);
return *this;
}

LivenessAnalysis::LivenessData& LivenessAnalysis::LivenessData::operator-=(LivenessData const& _other)
{
std::erase_if(m_liveCounts, [&](auto const& entry) { return _other.contains(entry.first); });
return *this;
}

void LivenessAnalysis::LivenessData::erase(Value const& _value)
{
if (
auto const it = findEntry(_value);
it != m_liveCounts.end()
)
m_liveCounts.erase(it);
}

void LivenessAnalysis::LivenessData::remove(Value const& _value, Count _count)
{
if (_count == 0)
return;

auto it = findEntry(_value);
if (it != m_liveCounts.end())
{
if (it->second <= _count)
m_liveCounts.erase(it);
else
it->second -= _count;
}
}


LivenessAnalysis::LivenessData LivenessAnalysis::blockExitValues(SSACFG::BlockId const& _blockId) const
{
LivenessData result;
util::GenericVisitor exitVisitor{
solidity::util::GenericVisitor exitVisitor{
[](SSACFG::BasicBlock::MainExit const&) {},
[&](SSACFG::BasicBlock::FunctionReturn const& _functionReturn)
{
Expand All @@ -156,17 +59,6 @@ LivenessAnalysis::LivenessData LivenessAnalysis::blockExitValues(SSACFG::BlockId
return result;
}


LivenessAnalysis::LivenessData::LiveCounts::iterator LivenessAnalysis::LivenessData::findEntry(Value const& _value)
{
return ranges::find_if(m_liveCounts, [&](auto const& _entry) { return _entry.first == _value; });
}

LivenessAnalysis::LivenessData::LiveCounts::const_iterator LivenessAnalysis::LivenessData::findEntry(Value const& _value) const
{
return ranges::find_if(m_liveCounts, [&](auto const& _entry) { return _entry.first == _value; });
}

LivenessAnalysis::LivenessAnalysis(SSACFG const& _cfg):
m_cfg(_cfg),
m_topologicalSort(_cfg),
Expand Down
71 changes: 4 additions & 67 deletions libyul/backends/evm/ssa/LivenessAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include <libyul/backends/evm/ssa/traversal/ForwardTopologicalSort.h>
#include <libyul/backends/evm/ssa/SSACFG.h>
#include <libyul/backends/evm/ssa/SSACFGLoopNestingForest.h>
#include <libyul/backends/evm/ssa/util/UseCountSet.h>

#include <vector>

Expand All @@ -33,74 +34,10 @@ namespace solidity::yul::ssa
class LivenessAnalysis
{
public:
class LivenessData
{
public:
using Count = std::uint32_t;
using Value = SSACFG::ValueId;
using LiveCounts = std::vector<std::pair<Value, Count>>;
/// Per-program-point liveness, each value's use count is the max number of times the value will be read along
/// all paths downstream of that point
using LivenessData = util::UseCountSet<SSACFG::ValueId>;

LivenessData() = default;
template<std::input_iterator Iter, std::sentinel_for<Iter> Sentinel>
LivenessData(Iter begin, Sentinel end): m_liveCounts(begin, end) {}
explicit LivenessData(LiveCounts&& _liveCounts): m_liveCounts(std::move(_liveCounts)) {}

bool contains(Value const& _valueId) const;
Count count(Value const& _valueId) const;
LiveCounts::const_iterator begin() const;
LiveCounts::const_iterator end() const;
LiveCounts::size_type size() const;
bool empty() const;

// Core modification
/// Add value with count (default 1), incrementing if already present
void insert(Value const& _value, Count _count = 1);
/// Remove value completely regardless of count
void erase(Value const& _value);
/// Decrement value count, removing if count reaches zero
void remove(Value const& _value, Count _count = 1);

// Set operations
/// Add all entries from other, summing counts
LivenessData& operator+=(LivenessData const& _other);
/// Remove all values present in other
LivenessData& operator-=(LivenessData const& _other);
/// Union with other, taking max count for each value
LivenessData& maxUnion(LivenessData const& _other);

// Bulk operations
/// Insert all values from range with count 1 each
template<typename Range>
void insertAll(Range const& _values)
{
for (auto const& value: _values)
insert(value);
}

/// Erase all values from range
template<typename Range>
void eraseAll(Range const& _values)
{
for (auto const& value: _values)
erase(value);
}

// Conditional removal
/// Remove all entries matching predicate
template<typename Predicate>
void eraseIf(Predicate&& _predicate)
{
std::erase_if(m_liveCounts, std::forward<Predicate>(_predicate));
}

private:
LiveCounts::iterator findEntry(Value const& _value);
LiveCounts::const_iterator findEntry(Value const& _value) const;

/// Usage counts represent the total number of times each variable will be used
/// downstream across all possible execution paths from this program point.
LiveCounts m_liveCounts;
};
explicit LivenessAnalysis(SSACFG const& _cfg);

LivenessData const& liveIn(SSACFG::BlockId const _blockId) const { return m_liveIns[_blockId.value]; }
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/ssa/PhiInverse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ bool PhiInverse::noOp() const

SSACFG::ValueId PhiInverse::operator()(SSACFG::ValueId _valueId) const
{
return util::valueOrDefault(m_phiToPreImage, _valueId, _valueId);
return solidity::util::valueOrDefault(m_phiToPreImage, _valueId, _valueId);
}

std::map<SSACFG::ValueId, SSACFG::ValueId> const& PhiInverse::data() const
Expand Down
6 changes: 3 additions & 3 deletions libyul/backends/evm/ssa/SSACFGBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -440,7 +440,7 @@ void SSACFGBuilder::assign(std::vector<std::reference_wrapper<Scope::Variable co
std::vector<SSACFG::ValueId> SSACFGBuilder::visitFunctionCall(FunctionCall const& _call)
{
bool canContinue = true;
SSACFG::Operation operation = std::visit(util::GenericVisitor{
SSACFG::Operation operation = std::visit(solidity::util::GenericVisitor{
[&](BuiltinName const& _builtinName)
{
auto const& builtin = m_dialect.builtin(_builtinName.handle);
Expand Down Expand Up @@ -553,7 +553,7 @@ void SSACFGBuilder::writeVariable(Scope::Variable const& _variable, SSACFG::Bloc
Scope::Function const& SSACFGBuilder::lookupFunction(YulName _name) const
{
Scope::Function const* function = nullptr;
yulAssert(m_scope->lookup(_name, util::GenericVisitor{
yulAssert(m_scope->lookup(_name, solidity::util::GenericVisitor{
[](Scope::Variable&) { yulAssert(false, "Expected function name."); },
[&](Scope::Function& _function) { function = &_function; }
}), "Function name not found.");
Expand All @@ -565,7 +565,7 @@ Scope::Variable const& SSACFGBuilder::lookupVariable(YulName _name) const
{
yulAssert(m_scope, "");
Scope::Variable const* var = nullptr;
if (m_scope->lookup(_name, util::GenericVisitor{
if (m_scope->lookup(_name, solidity::util::GenericVisitor{
[&](Scope::Variable const& _var) { var = &_var; },
[](Scope::Function const&)
{
Expand Down
2 changes: 1 addition & 1 deletion libyul/backends/evm/ssa/Stack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ std::string slotToString(StackSlot const& _slot)
case StackSlot::Kind::FunctionReturnLabel:
return fmt::format("ReturnLabel[{}]", _slot.functionReturnLabel());
}
util::unreachable();
solidity::util::unreachable();
}

std::string stackToString(StackData const& _stackData)
Expand Down
12 changes: 7 additions & 5 deletions libyul/backends/evm/ssa/StackLayoutGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -253,18 +253,19 @@ void StackLayoutGenerator::visitBlock(SSACFG::BlockId const& _blockId)
)
stack.declareJunk(depth);

StackSlotLiveness const opLiveOutSlots = toStackSlotLiveness(opLiveOutWithoutOutputs);
std::size_t const targetSize = findOptimalTargetSize(
stack.data(),
requiredStackTop,
opLiveOutWithoutOutputs,
opLiveOutSlots,
junkCanBeAdded,
m_hasFunctionReturnLabel
);
{
auto const shuffleResult = StackShuffler<StackType::Callbacks>::shuffle(
stack,
requiredStackTop,
opLiveOutWithoutOutputs,
opLiveOutSlots,
targetSize
);
yulAssert(shuffleResult.status == StackShufflerResult::Status::Admissible);
Expand All @@ -278,7 +279,7 @@ void StackLayoutGenerator::visitBlock(SSACFG::BlockId const& _blockId)
}

std::visit(
util::GenericVisitor{
solidity::util::GenericVisitor{
[&](SSACFG::BasicBlock::ConditionalJump const& _cJump) {
auto const& blockLiveOut = m_liveness.liveOut(_blockId);

Expand All @@ -290,15 +291,16 @@ void StackLayoutGenerator::visitBlock(SSACFG::BlockId const& _blockId)
if (!conditionSlotAlreadyFinal)
{
auto const condition = Slot::makeValueID(_cJump.condition);
StackSlotLiveness const blockLiveOutSlots = toStackSlotLiveness(blockLiveOut);
auto const targetSize = findOptimalTargetSize(
stack.data(),
{condition},
blockLiveOut,
blockLiveOutSlots,
false,
m_hasFunctionReturnLabel
);
auto const shuffleResult = StackShuffler<StackType::Callbacks>::shuffle(
stack, {condition}, blockLiveOut, targetSize
stack, {condition}, blockLiveOutSlots, targetSize
);
yulAssert(shuffleResult.status == StackShufflerResult::Status::Admissible);
}
Expand Down
Loading