Skip to content

Commit

Permalink
Prune unreferenced functions from CFG
Browse files Browse the repository at this point in the history
  • Loading branch information
rodiazet committed Dec 17, 2024
1 parent 03e2739 commit 682d2c6
Show file tree
Hide file tree
Showing 7 changed files with 203 additions and 3 deletions.
27 changes: 24 additions & 3 deletions libyul/backends/evm/ControlFlowGraphBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,23 @@ namespace
/// Removes edges to blocks that are not reachable.
void cleanUnreachable(CFG& _cfg)
{
// If operation is a function call it adds the callee entry as child
auto const addFunctionsEntries = [&_cfg](CFG::BasicBlock* _node, auto&& _addChild)
{
for (auto const& operation: _node->operations)
{
if (auto const* functionCall = std::get_if<CFG::FunctionCall>(&operation.operation))
{
auto const functionInfo = _cfg.functionInfo.at(&(functionCall->function.get()));
_addChild(functionInfo.entry);
}
}
};

// Determine which blocks are reachable from the entry.
util::BreadthFirstSearch<CFG::BasicBlock*> reachabilityCheck{{_cfg.entry}};
for (auto const& functionInfo: _cfg.functionInfo | ranges::views::values)
reachabilityCheck.verticesToTraverse.emplace_back(functionInfo.entry);

reachabilityCheck.run([&](CFG::BasicBlock* _node, auto&& _addChild) {
addFunctionsEntries(_node, _addChild);
visit(util::GenericVisitor{
[&](CFG::BasicBlock::Jump const& _jump) {
_addChild(_jump.target);
Expand All @@ -77,6 +88,16 @@ void cleanUnreachable(CFG& _cfg)
cxx20::erase_if(node->entries, [&](CFG::BasicBlock* entry) -> bool {
return !reachabilityCheck.visited.count(entry);
});

// Remove functions which are never referenced.
_cfg.functions.erase(std::remove_if(_cfg.functions.begin(), _cfg.functions.end(), [&](auto const& item) {
return !reachabilityCheck.visited.count(_cfg.functionInfo.at(item).entry);
}), _cfg.functions.end());

// Remove functionInfos which are never referenced.
cxx20::erase_if(_cfg.functionInfo, [&](auto const& entry) -> bool {
return !reachabilityCheck.visited.count(entry.second.entry);
});
}

/// Sets the ``recursive`` member to ``true`` for all recursive function calls.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
object "Contract" {
code {
f()
g()

function f() { revert(0, 0) }
function g() { mstore(0, 2) }
}
}

// ====
// EVMVersion: >=shanghai
// bytecodeFormat: >=EOFv1
// optimizationPreset: none
// ----
// Assembly:
// /* "source":53:56 */
// jumpf{code_section_1}
//
// code_section_1: assembly {
// /* "source":124:125 */
// 0x00
// /* "source":114:126 */
// dup1
// revert
// }
// Bytecode: ef000101000802000200030003040000000080ffff0080ffffe500015f80fd
// Opcodes: 0xEF STOP ADD ADD STOP ADDMOD MUL STOP MUL STOP SUB STOP SUB DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT STOP DUP1 SELFDESTRUCT SELFDESTRUCT JUMPF 0x1 PUSH0 DUP1 REVERT
// SourceMappings: 53:3:0:i:0124:1:0:-:0;114:12;
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
object "Contract" {
code {
f()
g()

function f() { f() }
function g() { mstore(0, 2) }
}
}

// ====
// EVMVersion: >=shanghai
// bytecodeFormat: >=EOFv1
// optimizationPreset: none
// ----
// Assembly:
// /* "source":53:56 */
// jumpf{code_section_1}
//
// code_section_1: assembly {
// /* "source":114:117 */
// jumpf{code_section_1}
// }
// Bytecode: ef000101000802000200030003040000000080ffff0080ffffe50001e50001
// Opcodes: 0xEF STOP ADD ADD STOP ADDMOD MUL STOP MUL STOP SUB STOP SUB DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT STOP DUP1 SELFDESTRUCT SELFDESTRUCT JUMPF 0x1 JUMPF 0x1
// SourceMappings: 53:3:0:i:0114:3:0:i:0
33 changes: 33 additions & 0 deletions test/libyul/objectCompiler/eof/prune_unreferenced_function.yul
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
object "Contract" {
code {
g()

function f() { mstore(0, 3) }
function g() { mstore(0, 2) }
}
}

// ====
// EVMVersion: >=shanghai
// bytecodeFormat: >=EOFv1
// optimizationPreset: none
// ----
// Assembly:
// /* "source":41:44 */
// callf{code_section_1}
// /* "source":29:98 */
// stop
//
// code_section_1: assembly {
// /* "source":88:89 */
// 0x02
// /* "source":85:86 */
// 0x00
// /* "source":78:90 */
// mstore
// /* "source":55:92 */
// retf
// }
// Bytecode: ef000101000802000200040005040000000080ffff0000ffffe300010060025f52e4
// Opcodes: 0xEF STOP ADD ADD STOP ADDMOD MUL STOP MUL STOP DIV STOP SDIV DIV STOP STOP STOP STOP DUP1 SELFDESTRUCT SELFDESTRUCT STOP STOP SELFDESTRUCT SELFDESTRUCT CALLF 0x1 STOP PUSH1 0x2 PUSH0 MSTORE RETF
// SourceMappings: 41:3:0:i:0;29:69::-88:1:0:-:0;85;78:12;55:37::o
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
object "Contract" {
code {
f()
g()

function f() { revert(0, 0) }
function g() { mstore(0, 2) }
}
}

// ====
// EVMVersion: >=shanghai
// bytecodeFormat: legacy
// optimizationPreset: none
// ----
// Assembly:
// /* "source":53:56 */
// tag_1
// jump // in
// /* "source":91:128 */
// tag_1:
// /* "source":124:125 */
// 0x00
// /* "source":114:126 */
// dup1
// revert
// Bytecode: 6003565b5f80fd
// Opcodes: PUSH1 0x3 JUMP JUMPDEST PUSH0 DUP1 REVERT
// SourceMappings: 53:3:0:-:0;:::i;91:37::-;124:1;114:12;
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
object "Contract" {
code {
f()
g()

function f() { f() }
function g() { mstore(0, 2) }
}
}

// ====
// EVMVersion: >=shanghai
// bytecodeFormat: legacy
// optimizationPreset: none
// ----
// Assembly:
// /* "source":53:56 */
// tag_1
// jump // in
// /* "source":91:119 */
// tag_1:
// /* "source":114:117 */
// tag_1
// jump // in
// Bytecode: 6003565b600356
// Opcodes: PUSH1 0x3 JUMP JUMPDEST PUSH1 0x3 JUMP
// SourceMappings: 53:3:0:-:0;:::i;91:28::-;114:3;:::i
35 changes: 35 additions & 0 deletions test/libyul/objectCompiler/prune_unreferenced_function.yul
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
object "Contract" {
code {
g()

function f() { mstore(0, 3) }
function g() { mstore(0, 2) }
}
}

// ====
// EVMVersion: >=shanghai
// bytecodeFormat: legacy
// optimizationPreset: none
// ----
// Assembly:
// /* "source":41:44 */
// tag_2
// tag_1
// jump // in
// tag_2:
// /* "source":29:98 */
// stop
// /* "source":55:92 */
// tag_1:
// /* "source":88:89 */
// 0x02
// /* "source":85:86 */
// 0x00
// /* "source":78:90 */
// mstore
// /* "source":55:92 */
// jump // out
// Bytecode: 60056007565b005b60025f5256
// Opcodes: PUSH1 0x5 PUSH1 0x7 JUMP JUMPDEST STOP JUMPDEST PUSH1 0x2 PUSH0 MSTORE JUMP
// SourceMappings: 41:3:0:-:0;;:::i;:::-;29:69;55:37;88:1;85;78:12;55:37::o

0 comments on commit 682d2c6

Please sign in to comment.