2020
2121#include < libsolutil/Visitor.h>
2222
23+ #include < range/v3/algorithm/find.hpp>
24+ #include < range/v3/algorithm/find_if.hpp>
2325#include < range/v3/range/conversion.hpp>
26+
2427#include < range/v3/view/filter.hpp>
2528#include < range/v3/view/reverse.hpp>
2629
2730using namespace solidity ::yul::ssa;
2831
2932namespace
3033{
31- constexpr auto literalsFilter (SSACFG const & _cfg)
34+ constexpr auto excludingLiteralsFilter (SSACFG const & _cfg)
35+ {
36+ return [&_cfg](LivenessAnalysis::LivenessData::Value const & _valueId) -> bool
37+ {
38+ return !std::holds_alternative<SSACFG::LiteralValue>(_cfg.valueInfo (_valueId));
39+ };
40+ }
41+ constexpr auto unreachableFilter (SSACFG const & _cfg)
3242{
33- return [&_cfg](SSACFG::ValueId const & _valueId) -> bool
43+ return [&_cfg](LivenessAnalysis::LivenessData::Value const & _valueId) -> bool
3444 {
35- return ! std::holds_alternative<SSACFG::LiteralValue >(_cfg.valueInfo (_valueId)); ;
45+ return std::holds_alternative<SSACFG::UnreachableValue >(_cfg.valueInfo (_valueId));
3646 };
3747}
3848}
3949
40- std::set<SSACFG::ValueId> LivenessAnalysis::blockExitValues (SSACFG::BlockId const & _blockId) const
50+ bool LivenessAnalysis::LivenessData::contains (Value const & _valueId) const
51+ {
52+ return findEntry (_valueId) != m_liveCounts.end ();
53+ }
54+
55+ LivenessAnalysis::LivenessData::Count LivenessAnalysis::LivenessData::count (Value const & _valueId) const
56+ {
57+ if (
58+ auto const it = findEntry (_valueId);
59+ it != m_liveCounts.end ()
60+ )
61+ return it->second ;
62+ return 0 ;
63+ }
64+
65+ LivenessAnalysis::LivenessData::LiveCounts::const_iterator LivenessAnalysis::LivenessData::begin () const
66+ {
67+ return m_liveCounts.begin ();
68+ }
69+
70+ LivenessAnalysis::LivenessData::LiveCounts::const_iterator LivenessAnalysis::LivenessData::end () const
71+ {
72+ return m_liveCounts.end ();
73+ }
74+
75+ LivenessAnalysis::LivenessData::LiveCounts::size_type LivenessAnalysis::LivenessData::size () const
76+ {
77+ return m_liveCounts.size ();
78+ }
79+
80+ bool LivenessAnalysis::LivenessData::empty () const { return m_liveCounts.empty (); }
81+
82+ void LivenessAnalysis::LivenessData::insert (Value const & _value, Count _count)
83+ {
84+ if (_count == 0 )
85+ return ;
86+
87+ auto it = findEntry (_value);
88+ if (it != m_liveCounts.end ())
89+ it->second += _count;
90+ else
91+ m_liveCounts.emplace_back (_value, _count);
92+ }
93+
94+ LivenessAnalysis::LivenessData& LivenessAnalysis::LivenessData::maxUnion (LivenessData const & _other)
95+ {
96+ for (auto const & [value, count]: _other.m_liveCounts )
97+ {
98+ auto it = findEntry (value);
99+ if (it != m_liveCounts.end ())
100+ it->second = std::max (it->second , count);
101+ else
102+ m_liveCounts.emplace_back (value, count);
103+ }
104+ return *this ;
105+ }
106+
107+ LivenessAnalysis::LivenessData& LivenessAnalysis::LivenessData::operator +=(LivenessData const & _other)
41108{
42- std::set<SSACFG::ValueId> result;
43- util::GenericVisitor exitVisitor {
109+ for (auto const & [valueId, count]: _other.m_liveCounts )
110+ insert (valueId, count);
111+ return *this ;
112+ }
113+
114+ LivenessAnalysis::LivenessData& LivenessAnalysis::LivenessData::operator -=(LivenessData const & _other)
115+ {
116+ std::erase_if (m_liveCounts, [&](auto const & entry) { return _other.contains (entry.first ); });
117+ return *this ;
118+ }
119+
120+ void LivenessAnalysis::LivenessData::erase (Value const & _value)
121+ {
122+ if (
123+ auto const it = findEntry (_value);
124+ it != m_liveCounts.end ()
125+ )
126+ m_liveCounts.erase (it);
127+ }
128+
129+ void LivenessAnalysis::LivenessData::remove (Value const & _value, Count _count)
130+ {
131+ if (_count == 0 )
132+ return ;
133+
134+ auto it = findEntry (_value);
135+ if (it != m_liveCounts.end ())
136+ {
137+ if (it->second <= _count)
138+ m_liveCounts.erase (it);
139+ else
140+ it->second -= _count;
141+ }
142+ }
143+
144+
145+ LivenessAnalysis::LivenessData LivenessAnalysis::blockExitValues (SSACFG::BlockId const & _blockId) const
146+ {
147+ LivenessData result;
148+ util::GenericVisitor exitVisitor{
44149 [](SSACFG::BasicBlock::MainExit const &) {},
45- [&](SSACFG::BasicBlock::FunctionReturn const & _functionReturn) {
46- result += _functionReturn.returnValues | ranges::views::filter (literalsFilter (m_cfg));
150+ [&](SSACFG::BasicBlock::FunctionReturn const & _functionReturn)
151+ {
152+ for (auto const & valueId: _functionReturn.returnValues | ranges::views::filter (excludingLiteralsFilter (m_cfg)))
153+ result.insert (valueId);
47154 },
48- [&](SSACFG::BasicBlock::JumpTable const & _jt) {
49- if (literalsFilter (m_cfg)(_jt.value ))
50- result.emplace (_jt.value );
155+ [&](SSACFG::BasicBlock::JumpTable const & _jt)
156+ {
157+ if (excludingLiteralsFilter (m_cfg)(_jt.value ))
158+ result.insert (_jt.value );
51159 },
52160 [](SSACFG::BasicBlock::Jump const &) {},
53- [&](SSACFG::BasicBlock::ConditionalJump const & _conditionalJump) {
54- if (literalsFilter (m_cfg)(_conditionalJump.condition ))
55- result.emplace (_conditionalJump.condition );
161+ [&](SSACFG::BasicBlock::ConditionalJump const & _conditionalJump)
162+ {
163+ if (excludingLiteralsFilter (m_cfg)(_conditionalJump.condition ))
164+ result.insert (_conditionalJump.condition );
56165 },
57- [](SSACFG::BasicBlock::Terminated const &) {}
58- };
166+ [](SSACFG::BasicBlock::Terminated const &) {}};
59167 std::visit (exitVisitor, m_cfg.block (_blockId).exit );
60168 return result;
61169}
62170
171+
172+ LivenessAnalysis::LivenessData::LiveCounts::iterator LivenessAnalysis::LivenessData::findEntry (Value const & _value)
173+ {
174+ return ranges::find_if (m_liveCounts, [&](auto const & _entry) { return _entry.first == _value; });
175+ }
176+
177+ LivenessAnalysis::LivenessData::LiveCounts::const_iterator LivenessAnalysis::LivenessData::findEntry (Value const & _value) const
178+ {
179+ return ranges::find_if (m_liveCounts, [&](auto const & _entry) { return _entry.first == _value; });
180+ }
181+
63182LivenessAnalysis::LivenessAnalysis (SSACFG const & _cfg):
64183 m_cfg(_cfg),
65184 m_topologicalSort(_cfg),
@@ -75,6 +194,14 @@ LivenessAnalysis::LivenessAnalysis(SSACFG const& _cfg):
75194 fillOperationsLiveOut ();
76195}
77196
197+ LivenessAnalysis::LivenessData LivenessAnalysis::used (SSACFG::BlockId const _blockId) const
198+ {
199+ auto used = liveIn (_blockId);
200+ for (auto const & [valueId, count]: liveOut (_blockId))
201+ used.remove (valueId, count);
202+ return used;
203+ }
204+
78205void LivenessAnalysis::runDagDfs ()
79206{
80207 // SSA Book, Algorithm 9.2
@@ -85,7 +212,7 @@ void LivenessAnalysis::runDagDfs()
85212 auto const & block = m_cfg.block (blockId);
86213
87214 // live <- PhiUses(B)
88- std::set<SSACFG::ValueId> live{};
215+ LivenessData live{};
89216 block.forEachExit (
90217 [&](SSACFG::BlockId const & _successor)
91218 {
@@ -105,15 +232,21 @@ void LivenessAnalysis::runDagDfs()
105232 block.forEachExit (
106233 [&](SSACFG::BlockId const & _successor) {
107234 if (!m_topologicalSort.backEdge (blockId, _successor))
108- live += m_liveIns[_successor.value ] - m_cfg.block (_successor).phis ;
235+ {
236+ // LiveIn(S) - PhiDefs(S)
237+ auto liveInWithoutPhiDefs = m_liveIns[_successor.value ];
238+ for (auto const & phiId: m_cfg.block (_successor).phis )
239+ liveInWithoutPhiDefs.erase (phiId);
240+ live.maxUnion (liveInWithoutPhiDefs);
241+ }
109242 });
110243
111244 if (std::holds_alternative<SSACFG::BasicBlock::FunctionReturn>(block.exit ))
112- live += std::get<SSACFG::BasicBlock::FunctionReturn>(block.exit ).returnValues
113- | ranges::views::filter ( literalsFilter (m_cfg) );
245+ for ( auto const & returnValue: std::get<SSACFG::BasicBlock::FunctionReturn>(block.exit ).returnValues | ranges::views::filter ( excludingLiteralsFilter (m_cfg)))
246+ live. insert (returnValue );
114247
115248 // clean out unreachables
116- live = live | ranges::views::filter ([&](auto const & valueId ) { return !std::holds_alternative<SSACFG::UnreachableValue> (m_cfg. valueInfo (valueId)) ; }) | ranges::to<std::set> ;
249+ live. eraseIf ([&](auto const & _entry ) { return unreachableFilter (m_cfg)(_entry. first ) ; });
117250
118251 // LiveOut(B) <- live
119252 m_liveOuts[blockId.value ] = live;
@@ -126,35 +259,39 @@ void LivenessAnalysis::runDagDfs()
126259 for (auto const & op: block.operations | ranges::views::reverse)
127260 {
128261 // remove variables defined at p from live
129- live -= op.outputs | ranges::views::filter (literalsFilter (m_cfg)) | ranges::to<std::vector>;
262+ live. eraseAll ( op.outputs | ranges::views::filter (excludingLiteralsFilter (m_cfg)) | ranges::to<std::vector>) ;
130263 // add uses at p to live
131- live += op.inputs | ranges::views::filter (literalsFilter (m_cfg)) | ranges::to<std::vector>;
264+ live. insertAll ( op.inputs | ranges::views::filter (excludingLiteralsFilter (m_cfg)) | ranges::to<std::vector>) ;
132265 }
133266 }
134267
135268 // livein(b) <- live \cup PhiDefs(B)
136- m_liveIns[blockId.value ] = live + block.phis ;
269+ for (auto const & phi: block.phis )
270+ live.insert (phi);
271+ m_liveIns[blockId.value ] = live;
137272 }
138273}
139274
140275void LivenessAnalysis::runLoopTreeDfs (size_t const _loopHeader)
141276{
142277 // SSA Book, Algorithm 9.3
143- if (m_loopNestingForest.loopNodes ().count (_loopHeader) > 0 )
278+ if (m_loopNestingForest.loopNodes ().contains (_loopHeader))
144279 {
145280 // the loop header block id
146281 auto const & block = m_cfg.block (SSACFG::BlockId{_loopHeader});
147282 // LiveLoop <- LiveIn(B_N) - PhiDefs(B_N)
148- auto liveLoop = m_liveIns[_loopHeader] - block.phis ;
283+ auto liveLoop = m_liveIns[_loopHeader];
284+ for (auto const & phi: block.phis )
285+ liveLoop.erase (phi);
149286 // must be live out of header if live in of children
150- m_liveOuts[_loopHeader] += liveLoop;
287+ m_liveOuts[_loopHeader]. maxUnion ( liveLoop) ;
151288 // for each blockId \in children(loopHeader)
152289 for (size_t blockIdValue = 0 ; blockIdValue < m_cfg.numBlocks (); ++blockIdValue)
153290 if (m_loopNestingForest.loopParents ()[blockIdValue] == _loopHeader)
154291 {
155292 // propagate loop liveness information down to the loop header's children
156- m_liveIns[blockIdValue] += liveLoop;
157- m_liveOuts[blockIdValue] += liveLoop;
293+ m_liveIns[blockIdValue]. maxUnion ( liveLoop) ;
294+ m_liveOuts[blockIdValue]. maxUnion ( liveLoop) ;
158295
159296 runLoopTreeDfs (blockIdValue);
160297 }
@@ -163,21 +300,23 @@ void LivenessAnalysis::runLoopTreeDfs(size_t const _loopHeader)
163300
164301void LivenessAnalysis::fillOperationsLiveOut ()
165302{
166- for (size_t blockIdValue = 0 ; blockIdValue < m_cfg.numBlocks (); ++blockIdValue )
303+ for (SSACFG::BlockId blockId{ 0 }; blockId. value < m_cfg.numBlocks (); ++blockId. value )
167304 {
168- SSACFG::BlockId const blockId{blockIdValue};
169305 auto const & operations = m_cfg.block (blockId).operations ;
170- auto & liveOuts = m_operationLiveOuts[blockIdValue ];
306+ auto & liveOuts = m_operationLiveOuts[blockId. value ];
171307 liveOuts.resize (operations.size ());
172308 if (!operations.empty ())
173309 {
174- auto live = m_liveOuts[blockIdValue] + blockExitValues (blockId);
310+ auto live = m_liveOuts[blockId.value ];
311+ live += blockExitValues (blockId);
175312 auto rit = liveOuts.rbegin ();
176313 for (auto const & op: operations | ranges::views::reverse)
177314 {
178315 *rit = live;
179- live -= op.outputs | ranges::views::filter (literalsFilter (m_cfg)) | ranges::to<std::vector>;
180- live += op.inputs | ranges::views::filter (literalsFilter (m_cfg)) | ranges::to<std::vector>;
316+ for (auto const & output: op.outputs | ranges::views::filter (excludingLiteralsFilter (m_cfg)))
317+ live.erase (output);
318+ for (auto const & input: op.inputs | ranges::views::filter (excludingLiteralsFilter (m_cfg)))
319+ live.insert (input);
181320 ++rit;
182321 }
183322 }
0 commit comments