2828#include < fmt/ranges.h>
2929#pragma GCC diagnostic pop
3030
31+ #include < libyul/backends/evm/ssa/JunkAdmittingBlocksFinder.h>
32+
3133#include < range/v3/view/zip.hpp>
3234
3335using namespace solidity ;
@@ -43,41 +45,23 @@ class SSACFGPrinter
4345 SSACFGPrinter (SSACFG const & _cfg, SSACFG::BlockId _blockId, LivenessAnalysis const * _liveness):
4446 m_cfg (_cfg), m_functionIndex(0 ), m_liveness(_liveness)
4547 {
48+ if (_liveness)
49+ m_junkAdmittingBlocks = std::make_unique<JunkAdmittingBlocksFinder>(_cfg, _liveness->topologicalSort ());
4650 printBlock (_blockId);
4751 }
4852 SSACFGPrinter (SSACFG const & _cfg, size_t _functionIndex, Scope::Function const & _function, LivenessAnalysis const * _liveness):
4953 m_cfg (_cfg), m_functionIndex(_functionIndex), m_liveness(_liveness)
5054 {
55+ if (_liveness)
56+ m_junkAdmittingBlocks = std::make_unique<JunkAdmittingBlocksFinder>(_cfg, _liveness->topologicalSort ());
5157 printFunction (_function);
5258 }
5359 friend std::ostream& operator <<(std::ostream& stream, SSACFGPrinter const & printer) {
5460 stream << printer.m_result .str ();
5561 return stream;
5662 }
57- private:
58- static std::string varToString (SSACFG const & _cfg, SSACFG::ValueId _var) {
59- if (_var.value == std::numeric_limits<size_t >::max ())
60- return " INVALID" ;
61- auto const & info = _cfg.valueInfo (_var);
62- return std::visit (
63- GenericVisitor{
64- [&](SSACFG::UnreachableValue const &) -> std::string {
65- return " [unreachable]" ;
66- },
67- [&](SSACFG::PhiValue const &) -> std::string {
68- return fmt::format (" v{}" , _var.value );
69- },
70- [&](SSACFG::VariableValue const &) -> std::string {
71- return fmt::format (" v{}" , _var.value );
72- },
73- [&](SSACFG::LiteralValue const & _literal) -> std::string {
74- return formatNumberReadable (_literal.value );
75- }
76- },
77- info
78- );
79- }
8063
64+ private:
8165 static std::string escape (std::string_view const str)
8266 {
8367 using namespace std ::literals;
@@ -113,7 +97,7 @@ class SSACFGPrinter
11397
11498 static std::string formatPhi (SSACFG const & _cfg, SSACFG::PhiValue const & _phiValue)
11599 {
116- auto const transform = [&](SSACFG::ValueId const & valueId) { return varToString (_cfg, valueId ); };
100+ auto const transform = [&](SSACFG::ValueId const & valueId) { return valueId. str (_cfg); };
117101 std::vector<std::string> formattedArgs;
118102 formattedArgs.reserve (_phiValue.arguments .size ());
119103 for (auto const & [arg, entry]: ranges::zip_view (_phiValue.arguments | ranges::views::transform (transform), _cfg.block (_phiValue.block ).entries ))
@@ -126,19 +110,23 @@ class SSACFGPrinter
126110
127111 void writeBlock (SSACFG::BlockId const & _id, SSACFG::BasicBlock const & _block)
128112 {
129- auto const valueToString = [&](SSACFG::ValueId const & valueId) { return varToString (m_cfg, valueId ); };
113+ auto const valueToString = [&](SSACFG::ValueId const & valueId) { return valueId. str (m_cfg); };
130114 bool entryBlock = _id.value == 0 && m_functionIndex == 0 ;
131115 if (entryBlock)
132116 {
133117 m_result << fmt::format (" Entry{} [label=\" Entry\" ];\n " , m_functionIndex);
134118 m_result << fmt::format (" Entry{} -> {};\n " , m_functionIndex, formatBlockHandle (_id));
135119 }
136120 {
121+ std::string revertPathInfo;
122+ if (m_junkAdmittingBlocks)
123+ revertPathInfo = m_junkAdmittingBlocks->allowsAdditionOfJunk (_id) ? " fillcolor=\" #FF746C\" , style=filled, " : " " ;
137124 if (m_liveness)
138125 {
139126 m_result << fmt::format (
140- " {} [label=\"\\\n Block {}; ({}, max {})\\ n" ,
127+ " {} [{} label=\"\\\n Block {}; ({}, max {})\\ n" ,
141128 formatBlockHandle (_id),
129+ revertPathInfo,
142130 _id.value ,
143131 m_liveness->topologicalSort ().preOrderIndexOf (_id.value ),
144132 m_liveness->topologicalSort ().maxSubtreePreOrderIndexOf (_id.value )
@@ -151,14 +139,19 @@ class SSACFGPrinter
151139 " LiveOut: {}\\ l\\ n" ,
152140 fmt::join (m_liveness->liveOut (_id) | ranges::views::transform ([&](auto const & liveOut) { return valueToString (SSACFG::ValueId{liveOut.first }) + fmt::format (" [{}]" , liveOut.second ); }), " , " )
153141 );
142+ auto const usedVariables = m_liveness->used (_id);
143+ m_result << fmt::format (
144+ " Used: {}\\ l\\ n" ,
145+ fmt::join (usedVariables | ranges::views::transform ([&](auto const & used) { return valueToString (SSACFG::ValueId{used.first }) + fmt::format (" [{}]" , used.second ); }), " , " )
146+ );
154147 }
155148 else
156- m_result << fmt::format (" {} [label=\"\\\n Block {}\\ n" , formatBlockHandle (_id), _id.value );
149+ m_result << fmt::format (" {} [{}label=\"\\\n Block {}\\ n" , formatBlockHandle (_id), revertPathInfo, _id.value );
150+
157151 for (auto const & phi: _block.phis )
158152 {
159- auto const * phiValue = std::get_if<SSACFG::PhiValue>(&m_cfg.valueInfo (phi));
160- solAssert (phiValue);
161- m_result << fmt::format (" v{} := {}\\ l\\\n " , phi.value , formatPhi (m_cfg, *phiValue));
153+ auto const & phiInfo = m_cfg.phiInfo (phi);
154+ m_result << fmt::format (" phi{} := {}\\ l\\\n " , phi.value (), formatPhi (m_cfg, phiInfo));
162155 }
163156 for (auto const & operation: _block.operations )
164157 {
@@ -172,7 +165,7 @@ class SSACFGPrinter
172165 [&](SSACFG::LiteralAssignment const &)
173166 {
174167 yulAssert (operation.inputs .size () == 1 );
175- return varToString (m_cfg, operation.inputs .back ());
168+ return operation.inputs .back (). str (m_cfg );
176169 }
177170 }, operation.kind );
178171 if (!operation.outputs .empty ())
@@ -210,7 +203,7 @@ class SSACFGPrinter
210203 m_result << fmt::format (" {} -> {}Exit;\n " , formatBlockHandle (_id), formatBlockHandle (_id));
211204 m_result << fmt::format (
212205 " {}Exit [label=\" {{ If {} | {{ <0> Zero | <1> NonZero }}}}\" shape=Mrecord];\n " ,
213- formatBlockHandle (_id), varToString (m_cfg, _conditionalJump.condition )
206+ formatBlockHandle (_id), _conditionalJump.condition . str (m_cfg )
214207 );
215208 m_result << formatEdge (_id, _conditionalJump.zero , " 0" );
216209 m_result << formatEdge (_id, _conditionalJump.nonZero , " 1" );
@@ -279,7 +272,7 @@ class SSACFGPrinter
279272 void printFunction (Scope::Function const & _fun)
280273 {
281274 static auto constexpr returnsTransform = [](auto const & functionReturnValue) { return escape (functionReturnValue.get ().name .str ()); };
282- static auto constexpr argsTransform = [](auto const & arg) { return fmt::format (" v{}" , std::get<1 >(arg).value ); };
275+ static auto constexpr argsTransform = [](auto const & arg) { return fmt::format (" v{}" , std::get<1 >(arg).value () ); };
283276 m_result << " FunctionEntry_" << escape (_fun.name .str ()) << " _" << m_cfg.entry .value << " [label=\" " ;
284277 if (!m_cfg.returns .empty ())
285278 m_result << fmt::format (" function {0}:\n {1} := {0}({2})" , escape (_fun.name .str ()), fmt::join (m_cfg.returns | ranges::views::transform (returnsTransform), " , " ), fmt::join (m_cfg.arguments | ranges::views::transform (argsTransform), " , " ));
@@ -291,12 +284,28 @@ class SSACFGPrinter
291284 }
292285
293286 SSACFG const & m_cfg;
287+ std::unique_ptr<JunkAdmittingBlocksFinder> m_junkAdmittingBlocks;
294288 size_t m_functionIndex;
295289 LivenessAnalysis const * m_liveness;
296290 std::stringstream m_result{};
297291};
298292}
299293
294+ std::string SSACFG::ValueId::str (SSACFG const & _cfg) const
295+ {
296+ if (!hasValue ())
297+ return " INVALID" ;
298+ switch (kind ())
299+ {
300+ case Kind::Literal: return toCompactHexWithPrefix (_cfg.literalInfo (*this ).value );
301+ case Kind::Variable: return fmt::format (" v{}" , value ());
302+ case Kind::Phi: return fmt::format (" phi{}" , value ());
303+ case Kind::Unreachable: return " [unreachable]" ;
304+ }
305+ unreachable ();
306+ }
307+
308+
300309std::string SSACFG::toDot (
301310 bool _includeDiGraphDefinition,
302311 std::optional<size_t > _functionIndex,
@@ -305,7 +314,7 @@ std::string SSACFG::toDot(
305314{
306315 std::ostringstream output;
307316 if (_includeDiGraphDefinition)
308- output << " digraph SSACFG {\n nodesep=0.7;\n graph[fontname=\" DejaVu Sans\" ]\n node[shape=box,fontname=\" DejaVu Sans\" ];\n\n " ;
317+ output << " digraph SSACFG {\n nodesep=0.7;\n graph[fontname=\" DejaVu Sans\" , rankdir=LR ]\n node[shape=box,fontname=\" DejaVu Sans\" ];\n\n " ;
309318 if (function)
310319 output << SSACFGPrinter (*this , _functionIndex ? *_functionIndex : static_cast <size_t >(1 ), *function, _liveness);
311320 else
0 commit comments