Skip to content

Commit

Permalink
Export liveness information of Yul SSA CFG (#15608)
Browse files Browse the repository at this point in the history
Export SSA CFG liveness data
  • Loading branch information
r0qs authored Dec 4, 2024
1 parent df91531 commit 8da621c
Show file tree
Hide file tree
Showing 6 changed files with 721 additions and 22 deletions.
33 changes: 25 additions & 8 deletions libyul/YulControlFlowGraphExporter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ using namespace solidity::langutil;
using namespace solidity::util;
using namespace solidity::yul;

YulControlFlowGraphExporter::YulControlFlowGraphExporter(ControlFlow const& _controlFlow): m_controlFlow(_controlFlow)
YulControlFlowGraphExporter::YulControlFlowGraphExporter(ControlFlow const& _controlFlow, ControlFlowLiveness const* _liveness): m_controlFlow(_controlFlow), m_liveness(_liveness)
{
}

Expand All @@ -58,37 +58,41 @@ std::string YulControlFlowGraphExporter::varToString(SSACFG const& _cfg, SSACFG:

Json YulControlFlowGraphExporter::run()
{
if (m_liveness)
yulAssert(&m_liveness->controlFlow.get() == &m_controlFlow);

Json yulObjectJson = Json::object();
yulObjectJson["blocks"] = exportBlock(*m_controlFlow.mainGraph, SSACFG::BlockId{0});
yulObjectJson["blocks"] = exportBlock(*m_controlFlow.mainGraph, SSACFG::BlockId{0}, m_liveness ? m_liveness->mainLiveness.get() : nullptr);

Json functionsJson = Json::object();
size_t index = 0;
for (auto const& [function, functionGraph]: m_controlFlow.functionGraphMapping)
functionsJson[function->name.str()] = exportFunction(*functionGraph);
functionsJson[function->name.str()] = exportFunction(*functionGraph, m_liveness ? m_liveness->functionLiveness[index++].get() : nullptr);
yulObjectJson["functions"] = functionsJson;

return yulObjectJson;
}

Json YulControlFlowGraphExporter::exportFunction(SSACFG const& _cfg)
Json YulControlFlowGraphExporter::exportFunction(SSACFG const& _cfg, SSACFGLiveness const* _liveness)
{
Json functionJson = Json::object();
functionJson["type"] = "Function";
functionJson["entry"] = "Block" + std::to_string(_cfg.entry.value);
static auto constexpr argsTransform = [](auto const& _arg) { return fmt::format("v{}", std::get<1>(_arg).value); };
functionJson["arguments"] = _cfg.arguments | ranges::views::transform(argsTransform) | ranges::to<std::vector>;
functionJson["numReturns"] = _cfg.returns.size();
functionJson["blocks"] = exportBlock(_cfg, _cfg.entry);
functionJson["blocks"] = exportBlock(_cfg, _cfg.entry, _liveness);
return functionJson;
}

Json YulControlFlowGraphExporter::exportBlock(SSACFG const& _cfg, SSACFG::BlockId _entryId)
Json YulControlFlowGraphExporter::exportBlock(SSACFG const& _cfg, SSACFG::BlockId _entryId, SSACFGLiveness const* _liveness)
{
Json blocksJson = Json::array();
util::BreadthFirstSearch<SSACFG::BlockId> bfs{{{_entryId}}};
bfs.run([&](SSACFG::BlockId _blockId, auto _addChild) {
auto const& block = _cfg.block(_blockId);
// Convert current block to JSON
Json blockJson = toJson(_cfg, _blockId);
Json blockJson = toJson(_cfg, _blockId, _liveness);

Json exitBlockJson = Json::object();
std::visit(util::GenericVisitor{
Expand Down Expand Up @@ -128,12 +132,25 @@ Json YulControlFlowGraphExporter::exportBlock(SSACFG const& _cfg, SSACFG::BlockI
return blocksJson;
}

Json YulControlFlowGraphExporter::toJson(SSACFG const& _cfg, SSACFG::BlockId _blockId)
Json YulControlFlowGraphExporter::toJson(SSACFG const& _cfg, SSACFG::BlockId _blockId, SSACFGLiveness const* _liveness)
{
auto const valueToString = [&](SSACFG::ValueId const& valueId) { return varToString(_cfg, valueId); };

Json blockJson = Json::object();
auto const& block = _cfg.block(_blockId);

blockJson["id"] = "Block" + std::to_string(_blockId.value);
if (_liveness)
{
Json livenessJson = Json::object();
livenessJson["in"] = _liveness->liveIn(_blockId)
| ranges::views::transform(valueToString)
| ranges::to<Json::array_t>();
livenessJson["out"] = _liveness->liveOut(_blockId)
| ranges::views::transform(valueToString)
| ranges::to<Json::array_t>();
blockJson["liveness"] = livenessJson;
}
blockJson["instructions"] = Json::array();
if (!block.phis.empty())
{
Expand Down
9 changes: 5 additions & 4 deletions libyul/YulControlFlowGraphExporter.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,15 +28,16 @@ using namespace yul;
class YulControlFlowGraphExporter
{
public:
YulControlFlowGraphExporter(ControlFlow const& _controlFlow);
YulControlFlowGraphExporter(ControlFlow const& _controlFlow, ControlFlowLiveness const* _liveness=nullptr);
Json run();
Json exportBlock(SSACFG const& _cfg, SSACFG::BlockId _blockId);
Json exportFunction(SSACFG const& _cfg);
Json exportBlock(SSACFG const& _cfg, SSACFG::BlockId _blockId, SSACFGLiveness const* _liveness);
Json exportFunction(SSACFG const& _cfg, SSACFGLiveness const* _liveness);
std::string varToString(SSACFG const& _cfg, SSACFG::ValueId _var);

private:
ControlFlow const& m_controlFlow;
Json toJson(SSACFG const& _cfg, SSACFG::BlockId _blockId);
ControlFlowLiveness const* m_liveness;
Json toJson(SSACFG const& _cfg, SSACFG::BlockId _blockId, SSACFGLiveness const* _liveness);
Json toJson(Json& _ret, SSACFG const& _cfg, SSACFG::Operation const& _operation);
Json toJson(SSACFG const& _cfg, std::vector<SSACFG::ValueId> const& _values);
};
3 changes: 2 additions & 1 deletion libyul/YulStack.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -389,7 +389,8 @@ Json YulStack::cfgJson() const
languageToDialect(m_language, m_evmVersion, m_eofVersion),
_object.code()->root()
);
YulControlFlowGraphExporter exporter(*controlFlow);
std::unique_ptr<ControlFlowLiveness> liveness = std::make_unique<ControlFlowLiveness>(*controlFlow);
YulControlFlowGraphExporter exporter(*controlFlow, liveness.get());
return exporter.run();
};

Expand Down
Loading

0 comments on commit 8da621c

Please sign in to comment.